From 35c340779af55f6b8d501de79988b0345b311c70 Mon Sep 17 00:00:00 2001 From: Gregory Herrero Date: Tue, 3 Dec 2019 15:38:29 +0100 Subject: [PATCH 001/816] worktree: mimic 'git worktree add' behavior. When adding a worktree using 'git worktree add ', if a reference named 'refs/heads/$(basename )' already exist, it is checkouted in the worktree. Mimic this behavior in libgit2. Signed-off-by: Gregory Herrero --- src/worktree.c | 26 +++++++++++++++++----- tests/worktree/worktree.c | 47 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/worktree.c b/src/worktree.c index ef4ebfda83c..c5edcb86bf2 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -278,7 +278,8 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree, const git_worktree_add_options *opts) { - git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT; + git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT; + git_buf buf = GIT_BUF_INIT, ref_buf = GIT_BUF_INIT; git_reference *ref = NULL, *head = NULL; git_commit *commit = NULL; git_repository *wt = NULL; @@ -365,12 +366,24 @@ int git_worktree_add(git_worktree **out, git_repository *repo, if ((err = git_reference_dup(&ref, wtopts.ref)) < 0) goto out; } else { - if ((err = git_repository_head(&head, repo)) < 0) - goto out; - if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0) - goto out; - if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0) + if ((err = git_buf_printf(&ref_buf, "refs/heads/%s", name)) < 0) goto out; + if (!git_reference_lookup(&ref, repo, ref_buf.ptr)) { + if (git_branch_is_checked_out(ref)) { + git_error_set(GIT_ERROR_WORKTREE, + "reference %s is already checked out", + ref_buf.ptr); + err = -1; + goto out; + } + } else { + if ((err = git_repository_head(&head, repo)) < 0) + goto out; + if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0) + goto out; + if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0) + goto out; + } } /* Set worktree's HEAD */ @@ -392,6 +405,7 @@ int git_worktree_add(git_worktree **out, git_repository *repo, git_buf_dispose(&gitdir); git_buf_dispose(&wddir); git_buf_dispose(&buf); + git_buf_dispose(&ref_buf); git_reference_free(ref); git_reference_free(head); git_commit_free(commit); diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c index 5e99dbf616b..9ef08320163 100644 --- a/tests/worktree/worktree.c +++ b/tests/worktree/worktree.c @@ -216,6 +216,46 @@ void test_worktree_worktree__init(void) git_repository_free(repo); } +void test_worktree_worktree__add_remove_add(void) +{ + git_worktree *wt; + git_repository *repo; + git_reference *branch; + git_buf path = GIT_BUF_INIT; + + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + + /* Add the worktree */ + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-add-remove-add")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, NULL)); + + /* Open and verify created repo */ + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL)); + git_repository_free(repo); + + /* Prune the worktree */ + opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_WORKING_TREE; + cl_git_pass(git_worktree_prune(wt, &opts)); + cl_assert(!git_path_exists(wt->gitdir_path)); + cl_assert(!git_path_exists(wt->gitlink_path)); + git_worktree_free(wt); + + /* Add the worktree back */ + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, NULL)); + + /* Open and verify created repo */ + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL)); + + git_buf_dispose(&path); + git_worktree_free(wt); + git_reference_free(branch); + git_repository_free(repo); +} + void test_worktree_worktree__add_locked(void) { git_worktree *wt; @@ -250,12 +290,13 @@ void test_worktree_worktree__init_existing_branch(void) cl_git_pass(git_repository_head(&head, fixture.repo)); cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid)); - cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new", commit, false)); + cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new-exist", commit, false)); - cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new")); - cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new-exist")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new-exist", path.ptr, NULL)); git_buf_dispose(&path); + git_worktree_free(wt); git_commit_free(commit); git_reference_free(head); git_reference_free(branch); From ea5028ab68584268ba9055e76eb99e5e2e6cac8e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 24 Jan 2020 12:46:59 +0100 Subject: [PATCH 002/816] worktree: add flag to allow re-using existing branches for new worktrees In this commit's parent, we have introduced logic that will automatically re-use of existing branches if the new worktree name matches the branch name. While this is a handy feature, it changes behaviour in a backwards-incompatible way and might thus surprise users. Furthermore, it's impossible to tell whether we have created the worktree with a new or an existing reference. To fix this, introduce a new option `checkout_existing` that toggles this behaviour. Only if the flag is set will we now allow re-use of existing branches, while it's set to "off" by default. --- include/git2/worktree.h | 9 ++++---- src/worktree.c | 47 +++++++++++++-------------------------- tests/worktree/worktree.c | 32 +++++++++++++++++--------- 3 files changed, 41 insertions(+), 47 deletions(-) diff --git a/include/git2/worktree.h b/include/git2/worktree.h index 049511da121..3f1acbdb0ff 100644 --- a/include/git2/worktree.h +++ b/include/git2/worktree.h @@ -84,12 +84,13 @@ GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt); typedef struct git_worktree_add_options { unsigned int version; - int lock; /**< lock newly created worktree */ - git_reference *ref; /**< reference to use for the new worktree HEAD */ + int lock; /**< lock newly created worktree */ + int checkout_existing; /**< allow checkout of existing branch matching worktree name */ + git_reference *ref; /**< reference to use for the new worktree HEAD */ } git_worktree_add_options; -#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1 -#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0,NULL} +#define GIT_WORKTREE_ADD_OPTIONS_VERSION 2 +#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0,0,NULL} /** * Initialize git_worktree_add_options structure diff --git a/src/worktree.c b/src/worktree.c index c5edcb86bf2..5e4255b91e9 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -278,8 +278,7 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree, const git_worktree_add_options *opts) { - git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT; - git_buf buf = GIT_BUF_INIT, ref_buf = GIT_BUF_INIT; + git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT; git_reference *ref = NULL, *head = NULL; git_commit *commit = NULL; git_repository *wt = NULL; @@ -304,11 +303,21 @@ int git_worktree_add(git_worktree **out, git_repository *repo, goto out; } - if (git_branch_is_checked_out(wtopts.ref)) { - git_error_set(GIT_ERROR_WORKTREE, "reference is already checked out"); - err = -1; + if ((err = git_reference_dup(&ref, wtopts.ref)) < 0) goto out; - } + } else if (wtopts.checkout_existing && git_branch_lookup(&ref, repo, name, GIT_BRANCH_LOCAL) == 0) { + /* Do nothing */ + } else if ((err = git_repository_head(&head, repo)) < 0 || + (err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0 || + (err = git_branch_create(&ref, repo, name, commit, false)) < 0) { + goto out; + } + + if (git_branch_is_checked_out(ref)) { + git_error_set(GIT_ERROR_WORKTREE, "reference %s is already checked out", + git_reference_name(ref)); + err = -1; + goto out; } /* Create gitdir directory ".git/worktrees/" */ @@ -361,31 +370,6 @@ int git_worktree_add(git_worktree **out, git_repository *repo, || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0) goto out; - /* Set up worktree reference */ - if (wtopts.ref) { - if ((err = git_reference_dup(&ref, wtopts.ref)) < 0) - goto out; - } else { - if ((err = git_buf_printf(&ref_buf, "refs/heads/%s", name)) < 0) - goto out; - if (!git_reference_lookup(&ref, repo, ref_buf.ptr)) { - if (git_branch_is_checked_out(ref)) { - git_error_set(GIT_ERROR_WORKTREE, - "reference %s is already checked out", - ref_buf.ptr); - err = -1; - goto out; - } - } else { - if ((err = git_repository_head(&head, repo)) < 0) - goto out; - if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0) - goto out; - if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0) - goto out; - } - } - /* Set worktree's HEAD */ if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0) goto out; @@ -405,7 +389,6 @@ int git_worktree_add(git_worktree **out, git_repository *repo, git_buf_dispose(&gitdir); git_buf_dispose(&wddir); git_buf_dispose(&buf); - git_buf_dispose(&ref_buf); git_reference_free(ref); git_reference_free(head); git_commit_free(commit); diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c index 9ef08320163..6a709476a1b 100644 --- a/tests/worktree/worktree.c +++ b/tests/worktree/worktree.c @@ -218,12 +218,12 @@ void test_worktree_worktree__init(void) void test_worktree_worktree__add_remove_add(void) { - git_worktree *wt; - git_repository *repo; - git_reference *branch; - git_buf path = GIT_BUF_INIT; - + git_worktree_add_options add_opts = GIT_WORKTREE_ADD_OPTIONS_INIT; git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_buf path = GIT_BUF_INIT; + git_reference *branch; + git_repository *repo; + git_worktree *wt; /* Add the worktree */ cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-add-remove-add")); @@ -233,6 +233,7 @@ void test_worktree_worktree__add_remove_add(void) cl_git_pass(git_repository_open(&repo, path.ptr)); cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0); cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL)); + git_reference_free(branch); git_repository_free(repo); /* Prune the worktree */ @@ -242,18 +243,21 @@ void test_worktree_worktree__add_remove_add(void) cl_assert(!git_path_exists(wt->gitlink_path)); git_worktree_free(wt); - /* Add the worktree back */ - cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, NULL)); + /* Add the worktree back with default options should fail. */ + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, &add_opts)); + /* If allowing checkout of existing branches, it should succeed. */ + add_opts.checkout_existing = 1; + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, &add_opts)); /* Open and verify created repo */ cl_git_pass(git_repository_open(&repo, path.ptr)); cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0); cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL)); + git_reference_free(branch); + git_repository_free(repo); git_buf_dispose(&path); git_worktree_free(wt); - git_reference_free(branch); - git_repository_free(repo); } void test_worktree_worktree__add_locked(void) @@ -283,6 +287,7 @@ void test_worktree_worktree__add_locked(void) void test_worktree_worktree__init_existing_branch(void) { + git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT; git_reference *head, *branch; git_commit *commit; git_worktree *wt; @@ -293,7 +298,12 @@ void test_worktree_worktree__init_existing_branch(void) cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new-exist", commit, false)); cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new-exist")); - cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new-exist", path.ptr, NULL)); + + /* Add the worktree back with default options should fail. */ + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new-exist", path.ptr, NULL)); + /* If allowing checkout of existing branches, it should succeed. */ + opts.checkout_existing = 1; + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new-exist", path.ptr, &opts)); git_buf_dispose(&path); git_worktree_free(wt); @@ -421,7 +431,7 @@ void test_worktree_worktree__name(void) cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); cl_assert_equal_s(git_worktree_name(wt), "testrepo-worktree"); - + git_worktree_free(wt); } From 0668384efe29a4d92ce1e9d1108187599ac9a067 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 2 Aug 2018 21:38:40 +0200 Subject: [PATCH 003/816] repo: basic graft API This represents (old-style) grafted commits, a.k.a an array of overridden parents for a commit's OID. --- src/graft.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/graft.h | 29 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/graft.c create mode 100644 src/graft.h diff --git a/src/graft.c b/src/graft.c new file mode 100644 index 00000000000..21d32fb3846 --- /dev/null +++ b/src/graft.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "graft.h" + +int git__graft_register(git_graftmap *grafts, const git_oid *oid, git_array_oid_t parents) +{ + git_commit_graft *graft; + git_oid *parent_oid; + int error; + size_t i; + + assert(grafts && oid); + + graft = git__calloc(1, sizeof(*graft)); + GIT_ERROR_CHECK_ALLOC(graft); + + git_array_init_to_size(graft->parents, git_array_size(parents)); + git_array_foreach(parents, i, parent_oid) { + git_oid *id = git_array_alloc(graft->parents); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, parent_oid); + } + git_oid_cpy(&graft->oid, oid); + + if ((error = git_oidmap_set(grafts, &graft->oid, graft)) < 0) + goto cleanup; + + return 0; + +cleanup: + git_array_clear(graft->parents); + git__free(graft); + return error; +} + +int git__graft_unregister(git_graftmap *grafts, const git_oid *oid) +{ + git_commit_graft *graft; + int error; + + assert(grafts && oid); + + if ((graft = git_oidmap_get(grafts, oid)) == NULL) + return GIT_ENOTFOUND; + + if ((error = git_oidmap_delete(grafts, oid)) < 0) + return error; + + git__free(graft); + + return 0; +} + +void git__graft_clear(git_graftmap *grafts) +{ + git_commit_graft *graft; + + assert(grafts); + + git_oidmap_foreach_value(grafts, graft, { + git__free(graft->parents.ptr); + git__free(graft); + }); + + git_oidmap_clear(grafts); +} + +int git__graft_for_oid(git_commit_graft **out, git_graftmap *grafts, const git_oid *oid) +{ + assert(out && grafts && oid); + if ((*out = git_oidmap_get(grafts, oid)) == NULL) + return GIT_ENOTFOUND; + return 0; +} diff --git a/src/graft.h b/src/graft.h new file mode 100644 index 00000000000..e2afb971131 --- /dev/null +++ b/src/graft.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_graft_h__ +#define INCLUDE_graft_h__ + +#include "common.h" +#include "oidarray.h" +#include "oidmap.h" + +/** graft commit */ +typedef struct { + git_oid oid; + git_array_oid_t parents; +} git_commit_graft; + +/* A special type of git_oidmap with git_commit_grafts as values */ +typedef git_oidmap git_graftmap; + +int git__graft_register(git_graftmap *grafts, const git_oid *oid, git_array_oid_t parents); +int git__graft_unregister(git_graftmap *grafts, const git_oid *oid); +void git__graft_clear(git_graftmap *grafts); + +int git__graft_for_oid(git_commit_graft **out, git_graftmap *grafts, const git_oid *oid); + +#endif From 919501a92dbafac6e6e876aa7160c3f46f8afe55 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 2 Aug 2018 21:38:42 +0200 Subject: [PATCH 004/816] repo: load grafts on open This wires git_repository to open the .git/info/grafts file and load its contents as git_commit_grafts objects. --- src/buffer.h | 5 +++ src/commit.c | 1 + src/repository.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ src/repository.h | 4 +++ 4 files changed, 91 insertions(+) diff --git a/src/buffer.h b/src/buffer.h index 6b717d2e90c..fc8fe140055 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -219,4 +219,9 @@ int git_buf_splice( const char *data, size_t nb_to_insert); +/* warning: this will wreck your buf contents */ +#define git_buf_foreach_line(line_start, line_end, line_num, buf) \ + while (((line_start) = git__strsep(&(buf)->ptr, "\n")) != NULL && \ + ((line_end) = (line_start) + strlen((line_start))) != NULL && ++(line_num)) + #endif diff --git a/src/commit.c b/src/commit.c index cf9902d022b..e2003d2181a 100644 --- a/src/commit.c +++ b/src/commit.c @@ -22,6 +22,7 @@ #include "object.h" #include "array.h" #include "oidarray.h" +#include "graft.h" void git_commit__free(void *_commit) { diff --git a/src/repository.c b/src/repository.c index 5e818fb8289..bcd91509d3d 100644 --- a/src/repository.c +++ b/src/repository.c @@ -148,6 +148,9 @@ int git_repository__cleanup(git_repository *repo) git_cache_clear(&repo->objects); git_attr_cache_flush(repo); + git__graft_clear(repo->grafts); + git_oidmap_free(repo->grafts); + set_config(repo, NULL); set_index(repo, NULL); set_odb(repo, NULL); @@ -254,6 +257,9 @@ static git_repository *repository_alloc(void) /* set all the entries in the configmap cache to `unset` */ git_repository__configmap_lookup_cache_clear(repo); + if (git_oidmap_new(&repo->grafts) < 0) + goto on_error; + return repo; on_error: @@ -574,6 +580,78 @@ static int find_repo( return error; } +static int load_grafts(git_repository *repo) +{ + git_buf graft_path = GIT_BUF_INIT; + git_buf contents = GIT_BUF_INIT; + git_buf dup_contents; + const char *line_start; + const char *line_end; + int line_num = 0; + int error, updated; + git_array_oid_t parents = GIT_ARRAY_INIT; + + if ((error = git_repository_item_path(&graft_path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0) + return error; + + if (git_buf_joinpath(&graft_path, graft_path.ptr, "grafts")) { + git_buf_dispose(&graft_path); + return error; + } + + error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&graft_path), &repo->graft_checksum, &updated); + git_buf_dispose(&graft_path); + + if (error == GIT_ENOTFOUND || !updated) + return 0; + + if (error < 0) + goto cleanup; + + if (updated) { + git__graft_clear(repo->grafts); + } + + dup_contents.ptr = contents.ptr; + git_buf_foreach_line(line_start, line_end, line_num, &dup_contents) { + git_oid graft_oid, parent_oid; + + error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ); + if (error < 0) { + git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); + error = -1; + } + line_start += GIT_OID_HEXSZ; + + if (*(line_start++) == ' ') { + while (git_oid_fromstrn(&parent_oid, line_start, GIT_OID_HEXSZ) == 0) { + git_oid *id = git_array_alloc(parents); + + git_oid_cpy(id, &parent_oid); + line_start += GIT_OID_HEXSZ; + if (line_start >= line_end) { + break; + } + line_start += 1; + } + } + + if (git__graft_register(repo->grafts, &graft_oid, parents) < 0) { + git_error_set(GIT_ERROR_REPOSITORY, "Invalid graft at line %d", line_num); + error = -1; + goto cleanup; + } + git_array_clear(parents); + line_num++; + } + +cleanup: + git_array_clear(parents); + git_buf_dispose(&contents); + + return error; +} + int git_repository_open_bare( git_repository **repo_ptr, const char *bare_path) @@ -863,6 +941,9 @@ int git_repository_open_ext( if ((error = check_extensions(config, version) < 0)) goto cleanup; + if ((error = load_grafts(repo)) < 0) + goto cleanup; + if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) repo->is_bare = 1; else { diff --git a/src/repository.h b/src/repository.h index bafdb589697..98d266d839b 100644 --- a/src/repository.h +++ b/src/repository.h @@ -24,6 +24,7 @@ #include "attrcache.h" #include "submodule.h" #include "diff_driver.h" +#include "graft.h" #define DOT_GIT ".git" #define GIT_DIR DOT_GIT "/" @@ -152,6 +153,9 @@ struct git_repository { unsigned int lru_counter; + git_graftmap *grafts; + git_oid graft_checksum; + git_atomic attr_session_key; git_configmap_value configmap_cache[GIT_CONFIGMAP_CACHE_MAX]; From 3c17f22976d62e5fc2743186b4b1b567aadf104a Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 10 Oct 2019 11:32:16 +0200 Subject: [PATCH 005/816] repo: load shallow roots --- include/git2/repository.h | 12 +++++++ src/repository.c | 75 +++++++++++++++++++++++++++++++++++++++ src/repository.h | 6 ++++ 3 files changed, 93 insertions(+) diff --git a/include/git2/repository.h b/include/git2/repository.h index 9ddcd340420..5a27cf08e8d 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -11,6 +11,7 @@ #include "types.h" #include "oid.h" #include "buffer.h" +#include "oidarray.h" /** * @file git2/repository.h @@ -874,6 +875,17 @@ GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); */ GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); +/** + * Determine the shallow roots of the repository + * + * This oidarray is owned by the library. Do not free it. + * + * @param out An array of shallow oids. + * @param repo The repository + * @return 0 on success, an error otherwise. + */ +GIT_EXTERN(int) git_repository_shallow_roots(git_oidarray *out, git_repository *repo); + /** * Retrieve the configured identity to use for reflogs * diff --git a/src/repository.c b/src/repository.c index bcd91509d3d..da27f545b15 100644 --- a/src/repository.c +++ b/src/repository.c @@ -151,6 +151,8 @@ int git_repository__cleanup(git_repository *repo) git__graft_clear(repo->grafts); git_oidmap_free(repo->grafts); + git_array_clear(repo->shallow_oids); + set_config(repo, NULL); set_index(repo, NULL); set_odb(repo, NULL); @@ -2978,6 +2980,79 @@ int git_repository_state_cleanup(git_repository *repo) return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); } +int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) +{ + git_buf path = GIT_BUF_INIT; + git_buf contents = GIT_BUF_INIT; + int error, updated, line_num = 1; + char *line; + char *buffer; + + assert(out && repo); + + if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) + return error; + + error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_checksum, &updated); + git_buf_dispose(&path); + + if (error < 0 && error != GIT_ENOTFOUND) + return error; + + /* cancel out GIT_ENOTFOUND */ + git_error_clear(); + error = 0; + + if (!updated) { + *out = repo->shallow_oids; + goto cleanup; + } + + git_array_clear(repo->shallow_oids); + + buffer = contents.ptr; + while ((line = git__strsep(&buffer, "\n")) != NULL) { + git_oid *oid = git_array_alloc(repo->shallow_oids); + + error = git_oid_fromstr(oid, line); + if (error < 0) { + git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); + git_array_clear(repo->shallow_oids); + error = -1; + goto cleanup; + } + ++line_num; + } + + if (*buffer) { + git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); + git_array_clear(repo->shallow_oids); + error = -1; + goto cleanup; + } + + *out = repo->shallow_oids; + +cleanup: + git_buf_dispose(&contents); + + return error; +} + +int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) +{ + int ret; + git_array_oid_t array = GIT_ARRAY_INIT; + + assert(out); + + ret = git_repository__shallow_roots(&array, repo); + + git_oidarray__from_array(out, &array); + + return ret; +} + int git_repository_is_shallow(git_repository *repo) { git_buf path = GIT_BUF_INIT; diff --git a/src/repository.h b/src/repository.h index 98d266d839b..f7c25f589e7 100644 --- a/src/repository.h +++ b/src/repository.h @@ -25,6 +25,7 @@ #include "submodule.h" #include "diff_driver.h" #include "graft.h" +#include "oidarray.h" #define DOT_GIT ".git" #define GIT_DIR DOT_GIT "/" @@ -156,6 +157,9 @@ struct git_repository { git_graftmap *grafts; git_oid graft_checksum; + git_oid shallow_checksum; + git_array_oid_t shallow_oids; + git_atomic attr_session_key; git_configmap_value configmap_cache[GIT_CONFIGMAP_CACHE_MAX]; @@ -259,4 +263,6 @@ extern size_t git_repository__reserved_names_posix_len; bool git_repository__reserved_names( git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs); +int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo); + #endif From a8b1d5156cf25c6b24feb084c55e8133b43d6390 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 2 Aug 2018 21:40:51 +0200 Subject: [PATCH 006/816] repo: graft shallow roots on open --- src/repository.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/repository.c b/src/repository.c index da27f545b15..977c7100285 100644 --- a/src/repository.c +++ b/src/repository.c @@ -654,6 +654,27 @@ static int load_grafts(git_repository *repo) return error; } +static int load_shallow(git_repository *repo) +{ + int error = 0; + git_array_oid_t roots = GIT_ARRAY_INIT; + git_array_oid_t parents = GIT_ARRAY_INIT; + size_t i; + git_oid *graft_oid; + + /* Graft shallow roots */ + if ((error = git_repository__shallow_roots(&roots, repo)) < 0) { + return error; + } + + git_array_foreach(roots, i, graft_oid) { + if ((error = git__graft_register(repo->grafts, graft_oid, parents)) < 0) { + return error; + } + } + return 0; +} + int git_repository_open_bare( git_repository **repo_ptr, const char *bare_path) @@ -946,6 +967,9 @@ int git_repository_open_ext( if ((error = load_grafts(repo)) < 0) goto cleanup; + if ((error = load_shallow(repo)) < 0) + goto cleanup; + if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) repo->is_bare = 1; else { From a35cc402fa615b316ab1a02d700de3c36482ad39 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 2 Aug 2018 21:38:43 +0200 Subject: [PATCH 007/816] commit: apply grafts when parsing --- src/commit.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/commit.c b/src/commit.c index e2003d2181a..ac8fb32501b 100644 --- a/src/commit.c +++ b/src/commit.c @@ -412,10 +412,6 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig buffer += tree_len; } - /* - * TODO: commit grafts! - */ - while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { git_oid *new_id = git_array_alloc(commit->parent_ids); GIT_ERROR_CHECK_ALLOC(new_id); @@ -499,7 +495,29 @@ int git_commit__parse_raw(void *commit, const char *data, size_t size) int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) { - return commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags); + git_repository *repo = git_object_owner((git_object *)commit); + git_commit_graft *graft; + int error; + + if ((error = commit_parse(commit, git_odb_object_data(odb_obj), + git_odb_object_size(odb_obj), flags)) < 0) + return error; + + /* Perform necessary grafts */ + if (git__graft_for_oid(&graft, repo->grafts, git_odb_object_id(odb_obj)) != GIT_ENOTFOUND) { + size_t idx; + git_oid *oid; + git_array_clear(commit->parent_ids); + git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); + git_array_foreach(graft->parents, idx, oid) { + git_oid *id = git_array_alloc(commit->parent_ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, oid); + } + } + + return 0; } int git_commit__parse(void *_commit, git_odb_object *odb_obj) From d54c00814bbba7eb39c43a8556e1720674cab3f3 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 2 Aug 2018 21:38:45 +0200 Subject: [PATCH 008/816] tests: graft commits --- tests/grafts/basic.c | 122 ++++++++++++++++ tests/grafts/shallow.c | 130 ++++++++++++++++++ tests/repo/shallow.c | 39 ------ tests/resources/grafted.git/HEAD | 1 + tests/resources/grafted.git/config | 6 + tests/resources/grafted.git/info/grafts | 3 + .../05/12adebd3782157f0d5c9b22b043f87b4aaff9e | Bin 0 -> 133 bytes .../1c/18e80a276611bb9b146590616bbc5aebdf2945 | Bin 0 -> 170 bytes .../1c/3f11eca55d76bc1bf7353ca7e4226246d353ed | Bin 0 -> 46 bytes .../2a/f02ebff1fc0142d2380c98758d81c67b365869 | Bin 0 -> 73 bytes .../2b/ecadd3f1ecad07a054392421edf9c0e1c375b2 | Bin 0 -> 74 bytes .../2f/3053cbff8a4ca2f0666de364ddb734a28a31a9 | Bin 0 -> 133 bytes .../45/342912745ba6f8893b1e126df4653a4355df1a | Bin 0 -> 50 bytes .../48/b2b333732644eafb385771a992b923fa88f135 | Bin 0 -> 49 bytes .../5d/31bf4b437e1191b6c709c665f1bd329d0ed0bf | Bin 0 -> 74 bytes .../66/cc22a015f6ca75b34c82d28f78ba663876bade | 2 + .../6c/f192eb71cd3243c9fbbe2551012c4449de3fcf | Bin 0 -> 36 bytes .../7c/9da502b2744b70522bb694cd607fb00104a233 | Bin 0 -> 76 bytes .../8a/00e91619098618be97c0d2ceabb05a2c58edd9 | 2 + .../a0/4de168dd5c43aa2af594d794d62e922f8b3b34 | Bin 0 -> 42 bytes .../b2/b4f9e5fe5dacbb2f98bd71d1dc86c7b571ddd1 | Bin 0 -> 54 bytes .../ba/54010f8d41532eb130eba420f50248881f7fc2 | Bin 0 -> 37 bytes .../d7/224d49d6d5aff6ade596ed74f4bcd4f77b29e2 | 2 + .../db/8e43f297a313c439530c977b733aaa8c10d54e | Bin 0 -> 35 bytes .../e4/14f42f4e6bc6934563a2349a8600f0ab68618e | Bin 0 -> 139 bytes .../e6/7b587a57850c69f6f9351ee10c7c8a41dacc78 | Bin 0 -> 74 bytes .../f0/7330bc2e4ed4bd0bf2301505f6c6bbad01aa2a | Bin 0 -> 77 bytes .../f5/03807ffa920e407a600cfaee96b7152259acc7 | 2 + tests/resources/grafted.git/refs/heads/bottom | 1 + tests/resources/grafted.git/refs/heads/branch | 1 + tests/resources/grafted.git/refs/heads/master | 1 + tests/resources/grafted.git/refs/heads/top | 1 + 32 files changed, 274 insertions(+), 39 deletions(-) create mode 100644 tests/grafts/basic.c create mode 100644 tests/grafts/shallow.c delete mode 100644 tests/repo/shallow.c create mode 100644 tests/resources/grafted.git/HEAD create mode 100644 tests/resources/grafted.git/config create mode 100644 tests/resources/grafted.git/info/grafts create mode 100644 tests/resources/grafted.git/objects/05/12adebd3782157f0d5c9b22b043f87b4aaff9e create mode 100644 tests/resources/grafted.git/objects/1c/18e80a276611bb9b146590616bbc5aebdf2945 create mode 100644 tests/resources/grafted.git/objects/1c/3f11eca55d76bc1bf7353ca7e4226246d353ed create mode 100644 tests/resources/grafted.git/objects/2a/f02ebff1fc0142d2380c98758d81c67b365869 create mode 100644 tests/resources/grafted.git/objects/2b/ecadd3f1ecad07a054392421edf9c0e1c375b2 create mode 100644 tests/resources/grafted.git/objects/2f/3053cbff8a4ca2f0666de364ddb734a28a31a9 create mode 100644 tests/resources/grafted.git/objects/45/342912745ba6f8893b1e126df4653a4355df1a create mode 100644 tests/resources/grafted.git/objects/48/b2b333732644eafb385771a992b923fa88f135 create mode 100644 tests/resources/grafted.git/objects/5d/31bf4b437e1191b6c709c665f1bd329d0ed0bf create mode 100644 tests/resources/grafted.git/objects/66/cc22a015f6ca75b34c82d28f78ba663876bade create mode 100644 tests/resources/grafted.git/objects/6c/f192eb71cd3243c9fbbe2551012c4449de3fcf create mode 100644 tests/resources/grafted.git/objects/7c/9da502b2744b70522bb694cd607fb00104a233 create mode 100644 tests/resources/grafted.git/objects/8a/00e91619098618be97c0d2ceabb05a2c58edd9 create mode 100644 tests/resources/grafted.git/objects/a0/4de168dd5c43aa2af594d794d62e922f8b3b34 create mode 100644 tests/resources/grafted.git/objects/b2/b4f9e5fe5dacbb2f98bd71d1dc86c7b571ddd1 create mode 100644 tests/resources/grafted.git/objects/ba/54010f8d41532eb130eba420f50248881f7fc2 create mode 100644 tests/resources/grafted.git/objects/d7/224d49d6d5aff6ade596ed74f4bcd4f77b29e2 create mode 100644 tests/resources/grafted.git/objects/db/8e43f297a313c439530c977b733aaa8c10d54e create mode 100644 tests/resources/grafted.git/objects/e4/14f42f4e6bc6934563a2349a8600f0ab68618e create mode 100644 tests/resources/grafted.git/objects/e6/7b587a57850c69f6f9351ee10c7c8a41dacc78 create mode 100644 tests/resources/grafted.git/objects/f0/7330bc2e4ed4bd0bf2301505f6c6bbad01aa2a create mode 100644 tests/resources/grafted.git/objects/f5/03807ffa920e407a600cfaee96b7152259acc7 create mode 100644 tests/resources/grafted.git/refs/heads/bottom create mode 100644 tests/resources/grafted.git/refs/heads/branch create mode 100644 tests/resources/grafted.git/refs/heads/master create mode 100644 tests/resources/grafted.git/refs/heads/top diff --git a/tests/grafts/basic.c b/tests/grafts/basic.c new file mode 100644 index 00000000000..39755ee8224 --- /dev/null +++ b/tests/grafts/basic.c @@ -0,0 +1,122 @@ +#include "clar_libgit2.h" + +#include "futils.h" +#include "graft.h" + +static git_repository *g_repo; + +void test_grafts_basic__initialize(void) +{ + g_repo = cl_git_sandbox_init("grafted.git"); +} + +void test_grafts_basic__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_grafts_basic__graft_add(void) +{ + git_oid oid_src, *oid1; + git_commit_graft *graft; + git_graftmap *grafts; + git_array_oid_t parents = GIT_ARRAY_INIT; + + cl_git_pass(git_oidmap_new(&grafts)); + + cl_assert(oid1 = git_array_alloc(parents)); + cl_git_pass(git_oid_fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9")); + git_oid_cpy(oid1, &oid_src); + + git_oid_fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7"); + cl_git_pass(git__graft_register(grafts, &oid_src, parents)); + git_array_clear(parents); + + cl_assert_equal_i(1, git_oidmap_size(grafts)); + cl_git_pass(git__graft_for_oid(&graft, grafts, &oid_src)); + cl_assert_equal_s("f503807ffa920e407a600cfaee96b7152259acc7", git_oid_tostr_s(&graft->oid)); + cl_assert_equal_i(1, git_array_size(graft->parents)); + cl_assert_equal_s("2f3053cbff8a4ca2f0666de364ddb734a28a31a9", git_oid_tostr_s(git_array_get(graft->parents, 0))); + + git__graft_clear(grafts); + git_oidmap_free(grafts); +} + +void test_grafts_basic__grafted_revwalk(void) +{ + git_revwalk *w; + git_oid oids[10]; + size_t i = 0; + git_commit *commit; + + cl_git_pass(git_revwalk_new(&w, g_repo)); + cl_git_pass(git_revwalk_push_ref(w, "refs/heads/branch")); + + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[0]), "8a00e91619098618be97c0d2ceabb05a2c58edd9"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[1]), "f503807ffa920e407a600cfaee96b7152259acc7"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[2]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9"); + + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w)); + + cl_git_pass(git_commit_lookup(&commit, g_repo, &oids[0])); + + cl_assert_equal_i(1, git_commit_parentcount(commit)); + + git_commit_free(commit); + git_revwalk_free(w); +} + +void test_grafts_basic__grafted_objects(void) +{ + git_oid oid; + git_commit *commit; + + cl_git_pass(git_oid_fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7")); + cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); + cl_assert_equal_i(1, git_commit_parentcount(commit)); + git_commit_free(commit); + + cl_git_pass(git_oid_fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e")); + cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); + cl_assert_equal_i(1, git_commit_parentcount(commit)); + git_commit_free(commit); + + cl_git_pass(git_oid_fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade")); + cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); + cl_assert_equal_i(4, git_commit_parentcount(commit)); + git_commit_free(commit); +} + +void test_grafts_basic__grafted_merge_revwalk(void) +{ + git_revwalk *w; + git_oid oids[10]; + size_t i = 0; + + cl_git_pass(git_revwalk_new(&w, g_repo)); + cl_git_pass(git_revwalk_push_ref(w, "refs/heads/bottom")); + + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "66cc22a015f6ca75b34c82d28f78ba663876bade"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "e414f42f4e6bc6934563a2349a8600f0ab68618e"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "8a00e91619098618be97c0d2ceabb05a2c58edd9"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "1c18e80a276611bb9b146590616bbc5aebdf2945"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "d7224d49d6d5aff6ade596ed74f4bcd4f77b29e2"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "0512adebd3782157f0d5c9b22b043f87b4aaff9e"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "f503807ffa920e407a600cfaee96b7152259acc7"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9"); + + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w)); + + git_revwalk_free(w); +} diff --git a/tests/grafts/shallow.c b/tests/grafts/shallow.c new file mode 100644 index 00000000000..e4a0f741f0b --- /dev/null +++ b/tests/grafts/shallow.c @@ -0,0 +1,130 @@ +#include "clar_libgit2.h" +#include "futils.h" + +static git_repository *g_repo; +static git_oid g_shallow_oid; + +void test_grafts_shallow__initialize(void) +{ + cl_git_pass(git_oid_fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); +} + +void test_grafts_shallow__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_grafts_shallow__no_shallow_file(void) +{ + g_repo = cl_git_sandbox_init("testrepo.git"); + cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); +} + +void test_grafts_shallow__empty_shallow_file(void) +{ + g_repo = cl_git_sandbox_init("testrepo.git"); + cl_git_mkfile("testrepo.git/shallow", ""); + cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); +} + +void test_grafts_shallow__shallow_repo(void) +{ + g_repo = cl_git_sandbox_init("shallow.git"); + cl_assert_equal_i(1, git_repository_is_shallow(g_repo)); +} + +void test_grafts_shallow__clears_errors(void) +{ + g_repo = cl_git_sandbox_init("testrepo.git"); + cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); + cl_assert_equal_p(NULL, git_error_last()); +} + +void test_grafts_shallow__shallow_oids(void) +{ + git_oidarray oids, oids2; + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); + cl_assert_equal_i(1, oids.count); + cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); + + cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); + cl_assert_equal_p(oids.ids, oids2.ids); +} + +void test_grafts_shallow__cache_clearing(void) +{ + git_oidarray oids, oids2; + git_oid tmp_oid; + + git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000"); + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); + cl_assert_equal_i(1, oids.count); + cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); + + cl_git_mkfile("shallow.git/shallow", + "be3563ae3f795b2b4353bcce3a527ad0a4f7f644\n" + "0000000000000000000000000000000000000000\n" + ); + + cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); + cl_assert_equal_i(2, oids2.count); + cl_assert_equal_oid(&g_shallow_oid, &oids2.ids[0]); + cl_assert_equal_oid(&tmp_oid, &oids2.ids[1]); + + cl_git_pass(p_unlink("shallow.git/shallow")); + cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); + cl_assert_equal_i(0, oids.count); + git_oidarray_free(&oids); +} + +void test_grafts_shallow__errors_on_borked(void) +{ + git_oidarray oids; + + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_mkfile("shallow.git/shallow", "lolno"); + + cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); + + cl_git_mkfile("shallow.git/shallow", "lolno\n"); + + cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); +} + +void test_grafts_shallow__revwalk_behavior(void) +{ + git_revwalk *w; + git_oid oid_1, oid_2, oid_3; + + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_revwalk_new(&w, g_repo)); + cl_git_pass(git_revwalk_push_head(w)); + + cl_git_pass(git_revwalk_next(&oid_1, w)); // a65fedf39aefe402d3bb6e24df4d4f5fe4547750 + cl_git_pass(git_revwalk_next(&oid_2, w)); // be3563ae3f795b2b4353bcce3a527ad0a4f7f644 + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid_3, w)); + + cl_assert_equal_s(git_oid_tostr_s(&oid_1), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + cl_assert_equal_s(git_oid_tostr_s(&oid_2), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + + git_revwalk_free(w); +} + +void test_grafts_shallow__grafted_object(void) +{ + git_commit *commit; + + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_commit_lookup(&commit, g_repo, &g_shallow_oid)); + + cl_assert_equal_i(0, git_commit_parentcount(commit)); + + git_commit_free(commit); +} diff --git a/tests/repo/shallow.c b/tests/repo/shallow.c deleted file mode 100644 index adb7a9e44b5..00000000000 --- a/tests/repo/shallow.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "clar_libgit2.h" -#include "futils.h" - -static git_repository *g_repo; - -void test_repo_shallow__initialize(void) -{ -} - -void test_repo_shallow__cleanup(void) -{ - cl_git_sandbox_cleanup(); -} - -void test_repo_shallow__no_shallow_file(void) -{ - g_repo = cl_git_sandbox_init("testrepo.git"); - cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); -} - -void test_repo_shallow__empty_shallow_file(void) -{ - g_repo = cl_git_sandbox_init("testrepo.git"); - cl_git_mkfile("testrepo.git/shallow", ""); - cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); -} - -void test_repo_shallow__shallow_repo(void) -{ - g_repo = cl_git_sandbox_init("shallow.git"); - cl_assert_equal_i(1, git_repository_is_shallow(g_repo)); -} - -void test_repo_shallow__clears_errors(void) -{ - g_repo = cl_git_sandbox_init("testrepo.git"); - cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); - cl_assert_equal_p(NULL, git_error_last()); -} diff --git a/tests/resources/grafted.git/HEAD b/tests/resources/grafted.git/HEAD new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/tests/resources/grafted.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/grafted.git/config b/tests/resources/grafted.git/config new file mode 100644 index 00000000000..e6da231579b --- /dev/null +++ b/tests/resources/grafted.git/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true diff --git a/tests/resources/grafted.git/info/grafts b/tests/resources/grafted.git/info/grafts new file mode 100644 index 00000000000..bb9df8c0a80 --- /dev/null +++ b/tests/resources/grafted.git/info/grafts @@ -0,0 +1,3 @@ +f503807ffa920e407a600cfaee96b7152259acc7 2f3053cbff8a4ca2f0666de364ddb734a28a31a9 +0512adebd3782157f0d5c9b22b043f87b4aaff9e 2f3053cbff8a4ca2f0666de364ddb734a28a31a9 +66cc22a015f6ca75b34c82d28f78ba663876bade e414f42f4e6bc6934563a2349a8600f0ab68618e 8a00e91619098618be97c0d2ceabb05a2c58edd9 1c18e80a276611bb9b146590616bbc5aebdf2945 2f3053cbff8a4ca2f0666de364ddb734a28a31a9 diff --git a/tests/resources/grafted.git/objects/05/12adebd3782157f0d5c9b22b043f87b4aaff9e b/tests/resources/grafted.git/objects/05/12adebd3782157f0d5c9b22b043f87b4aaff9e new file mode 100644 index 0000000000000000000000000000000000000000..16880d596e5be78d02e1ea264f4b2ee69d02c680 GIT binary patch literal 133 zcmV;00DAv;oTZIH3d0}}0DJZodoP6D7!5)R?V&H|3)EdxAu1&H|Aq7kJq^rZCbm*? z2Xf}pcM&kGDWoY(dKMx_!NwU~wALgFtVhQvj3Fui>F>6~vuCMQ;N{EFD%_5fgZ%V; nEk18UY-Is5sL{-X4z4&Ns(7xu{1s6T=3G}uc@wR^E=)i_XyrVi literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/1c/18e80a276611bb9b146590616bbc5aebdf2945 b/tests/resources/grafted.git/objects/1c/18e80a276611bb9b146590616bbc5aebdf2945 new file mode 100644 index 0000000000000000000000000000000000000000..2c057b85d87270c2fb5dd4f9ee40b4c34158b122 GIT binary patch literal 170 zcmV;b09F5ZoTZOF3IZ_@My+#-=>^Ho<`+b4Y;8P2HZ!9OCXwBU*H`oiRu8`7@x9zi znLD6~o4zmuCeg@~$RJq{1_{TYa}3@F3PW~&8l4R;sz+M5b|8;v$V75vlZZ>iHaaG6 z#7votct2reRO#7oZGlstxmJctDr>8-U%%Y(Z$4g2n(w>Z$^izeM{Pg)09%b(tNgv% Y`7en&^9y9Y^9Z@s{z+KX8>doGwo)cfs{jB1 literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/1c/3f11eca55d76bc1bf7353ca7e4226246d353ed b/tests/resources/grafted.git/objects/1c/3f11eca55d76bc1bf7353ca7e4226246d353ed new file mode 100644 index 0000000000000000000000000000000000000000..b92a3047f1804ae188cc86555e7179093185915b GIT binary patch literal 46 zcmV+}0MY+=oJ-2dPf{>8V2I2wRVYf$%`Zz;D9K1wNXyJgRY=ayD@n~ODc0ix0Qf`< E_1_m1iU0rr literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/2a/f02ebff1fc0142d2380c98758d81c67b365869 b/tests/resources/grafted.git/objects/2a/f02ebff1fc0142d2380c98758d81c67b365869 new file mode 100644 index 0000000000000000000000000000000000000000..ed3f874a7bddb6d5d2f46ac5823f8181b09105dd GIT binary patch literal 73 zcmV-P0Ji^loGU3xO;s>6WiT`_Ff%bxNXyJgWw_nv{Av1P;Ukv8JkzU-tyc92T=hee fH)hxs!pPt27_7I^;Pn!PuS^~t^7V%Rkc%1M+}9*@ literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/2b/ecadd3f1ecad07a054392421edf9c0e1c375b2 b/tests/resources/grafted.git/objects/2b/ecadd3f1ecad07a054392421edf9c0e1c375b2 new file mode 100644 index 0000000000000000000000000000000000000000..724eedbb2ecf35e1e3f3ba08ec2445092841ba5f GIT binary patch literal 74 zcmV-Q0JZ;koGU3xO;s>6WiT`_Ff%bxNXyJgWw_nv{Av1P;Ukv8JkzU-tyc92T=hee gH)fEr7kslcwrr2|cT=0?Pn43}E(gB_0GnVNGu+-H00000 literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/2f/3053cbff8a4ca2f0666de364ddb734a28a31a9 b/tests/resources/grafted.git/objects/2f/3053cbff8a4ca2f0666de364ddb734a28a31a9 new file mode 100644 index 0000000000000000000000000000000000000000..3d124a6735246418d158e34e43266d782f20f0b9 GIT binary patch literal 133 zcmV;00DAv;oTZIH3d0}}0DJZodoKjt)u<3kFFo|!7p!5^3Q-}k|1Ts@=xJaMGjl5? zcQDak`X&N4Buqr)2}f&%mqfvNZ#YIw5ozHN7DG<)w}09OkDjGgfftv(RhagJgPi*Q nE}Yk4Zsi8XX^dmk7U8N8VQ|dLFUd$P(orbR$xP2E$*ELG$xKU2ElSNRQAo?oNj2dD I05rx9iB#hjJ^%m! literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/48/b2b333732644eafb385771a992b923fa88f135 b/tests/resources/grafted.git/objects/48/b2b333732644eafb385771a992b923fa88f135 new file mode 100644 index 0000000000000000000000000000000000000000..ac640636beb3e853d58759fdcbe76da2e6396e3e GIT binary patch literal 49 zcmV-10M7q-oGU3xO;s>9VlXr?Ff%bxNXyJgWw_nv{Av1P;Ukv8JkzU-tyc92T=fG0 H3L_4b`6Lx1 literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/5d/31bf4b437e1191b6c709c665f1bd329d0ed0bf b/tests/resources/grafted.git/objects/5d/31bf4b437e1191b6c709c665f1bd329d0ed0bf new file mode 100644 index 0000000000000000000000000000000000000000..47a05377ef383fe0018c4ae10588e3aa6e87115a GIT binary patch literal 74 zcmV-Q0JZ;koGU3xO;s>6WiT`_Ff%bxNXyJgWw_nv{Av1P;Ukv8JkzU-tyc92T=hee gH)dGi`!M5fjPok3uT!p1xu!QszuVdb0JJ+B_4OnqA^-pY literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/66/cc22a015f6ca75b34c82d28f78ba663876bade b/tests/resources/grafted.git/objects/66/cc22a015f6ca75b34c82d28f78ba663876bade new file mode 100644 index 00000000000..c68b2cd4fb1 --- /dev/null +++ b/tests/resources/grafted.git/objects/66/cc22a015f6ca75b34c82d28f78ba663876bade @@ -0,0 +1,2 @@ +xM +0F]$Dx=4N4Fϯ#x|260dvmap1 a}NhL!E&}BTO^dn )$~ꖜl,=bF|:W{myrY uN~t/ѫM, \ No newline at end of file diff --git a/tests/resources/grafted.git/objects/6c/f192eb71cd3243c9fbbe2551012c4449de3fcf b/tests/resources/grafted.git/objects/6c/f192eb71cd3243c9fbbe2551012c4449de3fcf new file mode 100644 index 0000000000000000000000000000000000000000..a437f24320485d43a36754c301df4ec942291628 GIT binary patch literal 36 scmb=J<9+I+e~^Ju630o8&=Y6%y+SokdazFFbX{3hRTaZ9g^SY$02^Em9RL6T literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/7c/9da502b2744b70522bb694cd607fb00104a233 b/tests/resources/grafted.git/objects/7c/9da502b2744b70522bb694cd607fb00104a233 new file mode 100644 index 0000000000000000000000000000000000000000..b363584fd9ab216bee5892efa1ce7ae800d72ec3 GIT binary patch literal 76 zcmV-S0JHyioGU3xO;xb8U@$Z=Ff%bxNXyJgWw_nv{Av1P;Ukv8JkzU-tyc92T=hee iHzK6Kgu&HBQ>Y|**^f?ZIicJysaDRR_oV>MU?ur-;U+Nv literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/8a/00e91619098618be97c0d2ceabb05a2c58edd9 b/tests/resources/grafted.git/objects/8a/00e91619098618be97c0d2ceabb05a2c58edd9 new file mode 100644 index 00000000000..887778a60a0 --- /dev/null +++ b/tests/resources/grafted.git/objects/8a/00e91619098618be97c0d2ceabb05a2c58edd9 @@ -0,0 +1,2 @@ +xA +0E]t4Dt <$@J#ч@B5@b$'[ig&V/^6H ]J<AbH,2ȎSne{R˶T8ovשp |d~_u1 RŨߚNC \ No newline at end of file diff --git a/tests/resources/grafted.git/objects/a0/4de168dd5c43aa2af594d794d62e922f8b3b34 b/tests/resources/grafted.git/objects/a0/4de168dd5c43aa2af594d794d62e922f8b3b34 new file mode 100644 index 0000000000000000000000000000000000000000..1ed3ed906abd905893455c38a9597e7ef259df59 GIT binary patch literal 42 ycmb=J<9+I+e~^JuazTj4x%0XnXHK6vAMA1ZjAy8aj)sS?j#k(cCWb@G+%5p0ClPP} literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/b2/b4f9e5fe5dacbb2f98bd71d1dc86c7b571ddd1 b/tests/resources/grafted.git/objects/b2/b4f9e5fe5dacbb2f98bd71d1dc86c7b571ddd1 new file mode 100644 index 0000000000000000000000000000000000000000..2adc857219eb17dcbb6489b39e2e9d520e9ec1d0 GIT binary patch literal 54 zcmV-60LlM&oGU3xO;s>6WiT`_Ff%bxNXyJgWw_nv{Av1P;Ukv8JkzU-tyc92T=hee MH^Qm_0IJ^`DtJ*CmjD0& literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/ba/54010f8d41532eb130eba420f50248881f7fc2 b/tests/resources/grafted.git/objects/ba/54010f8d41532eb130eba420f50248881f7fc2 new file mode 100644 index 0000000000000000000000000000000000000000..52a8872747197a2a017978f343a13d5fafaa5b8c GIT binary patch literal 37 tcmb=J<9+I+e~^Ju$_Jf5{V)x0-BlqTzTT&O&iS0x4t&DI(D{Kg0ste34+H=J literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/d7/224d49d6d5aff6ade596ed74f4bcd4f77b29e2 b/tests/resources/grafted.git/objects/d7/224d49d6d5aff6ade596ed74f4bcd4f77b29e2 new file mode 100644 index 00000000000..5b41b6778f8 --- /dev/null +++ b/tests/resources/grafted.git/objects/d7/224d49d6d5aff6ade596ed74f4bcd4f77b29e2 @@ -0,0 +1,2 @@ +xA +0E]dҐDx=$hI_Gp/Ԁ,"%p&/1ތԓƀq֓z"ZMG%6co|Ϝ(^8IJr^kú|e.|mѠuH*lW%Q%Y ZڧbUoaRj \ No newline at end of file diff --git a/tests/resources/grafted.git/objects/db/8e43f297a313c439530c977b733aaa8c10d54e b/tests/resources/grafted.git/objects/db/8e43f297a313c439530c977b733aaa8c10d54e new file mode 100644 index 0000000000000000000000000000000000000000..b9cf5947b705184a4ba4a8e3d19140da9eb41356 GIT binary patch literal 35 rcmb=J<9+I+e~`hJl!A~G-n!u)r_XqXdgy3)`08jqV`3jUvmdN{IG$9V?CXd*oVbWUhyDfEtXG>Cwz>D)<3tabuo&5BD t&YadR)O>^9qDJfV#ljg0QH5jO literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/e6/7b587a57850c69f6f9351ee10c7c8a41dacc78 b/tests/resources/grafted.git/objects/e6/7b587a57850c69f6f9351ee10c7c8a41dacc78 new file mode 100644 index 0000000000000000000000000000000000000000..213f9ac22ef650e98e03036bd3ba542f0c498454 GIT binary patch literal 74 zcmV-Q0JZ;koGU3xO;s>6V=y!@Ff%bxNXyJgHDb8k=lp5+4m2we3; gQeeX1YN9Dr620t4r?s3=?w3?6=g|970GyW@mfHIx)c^nh literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/f0/7330bc2e4ed4bd0bf2301505f6c6bbad01aa2a b/tests/resources/grafted.git/objects/f0/7330bc2e4ed4bd0bf2301505f6c6bbad01aa2a new file mode 100644 index 0000000000000000000000000000000000000000..f2d64889207b6c5a5676af3ef9addc92077d3b14 GIT binary patch literal 77 zcmV-T0J8shoGU3xO;xb8U@$Z=Ff%bxNXyJgWw_nv{Av1P;Ukv8JkzU-tyc92T=hee jHzK6KgdykSq}PRKjhs*Z-lrPKsN>>!&;C3B_1!3bz$Ga8 literal 0 HcmV?d00001 diff --git a/tests/resources/grafted.git/objects/f5/03807ffa920e407a600cfaee96b7152259acc7 b/tests/resources/grafted.git/objects/f5/03807ffa920e407a600cfaee96b7152259acc7 new file mode 100644 index 00000000000..21436c177e9 --- /dev/null +++ b/tests/resources/grafted.git/objects/f5/03807ffa920e407a600cfaee96b7152259acc7 @@ -0,0 +1,2 @@ +xA +0E]J&6) @@#xZ)z{D/ɋMb9P&yyBF&7헙Qw =KPV;Oߖ:P+3Ə6Z+:Qw\Hy>zA \ No newline at end of file diff --git a/tests/resources/grafted.git/refs/heads/bottom b/tests/resources/grafted.git/refs/heads/bottom new file mode 100644 index 00000000000..10513e69877 --- /dev/null +++ b/tests/resources/grafted.git/refs/heads/bottom @@ -0,0 +1 @@ +66cc22a015f6ca75b34c82d28f78ba663876bade diff --git a/tests/resources/grafted.git/refs/heads/branch b/tests/resources/grafted.git/refs/heads/branch new file mode 100644 index 00000000000..d0fe5c28390 --- /dev/null +++ b/tests/resources/grafted.git/refs/heads/branch @@ -0,0 +1 @@ +8a00e91619098618be97c0d2ceabb05a2c58edd9 diff --git a/tests/resources/grafted.git/refs/heads/master b/tests/resources/grafted.git/refs/heads/master new file mode 100644 index 00000000000..de809b9421a --- /dev/null +++ b/tests/resources/grafted.git/refs/heads/master @@ -0,0 +1 @@ +2f3053cbff8a4ca2f0666de364ddb734a28a31a9 diff --git a/tests/resources/grafted.git/refs/heads/top b/tests/resources/grafted.git/refs/heads/top new file mode 100644 index 00000000000..ce226110b8e --- /dev/null +++ b/tests/resources/grafted.git/refs/heads/top @@ -0,0 +1 @@ +1c18e80a276611bb9b146590616bbc5aebdf2945 From 22f201b158f4a3b7bfcf3bac2324ab3fa77bac06 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 3 Oct 2019 10:40:41 +0200 Subject: [PATCH 009/816] grafts: make the structure self-contained and opaque In order to increase maintainability in the future, we should try to make structures as self-contained and opaque to its users as possible. Thus it is probably not a good idea to just typedef `git_graftmap` to `git_oidmap`, as that will make it a lot harder in the future to extend the API in the future, if this need ever arises. Refactor the code to instead declare a real structure `git_grafts`, which is completely opaque to its callers. --- src/commit.c | 4 +- src/graft.c | 80 -------------------------- src/grafts.c | 115 ++++++++++++++++++++++++++++++++++++++ src/{graft.h => grafts.h} | 14 +++-- src/repository.c | 17 ++---- src/repository.h | 4 +- tests/grafts/basic.c | 17 +++--- 7 files changed, 141 insertions(+), 110 deletions(-) delete mode 100644 src/graft.c create mode 100644 src/grafts.c rename src/{graft.h => grafts.h} (50%) diff --git a/src/commit.c b/src/commit.c index ac8fb32501b..e06faafe781 100644 --- a/src/commit.c +++ b/src/commit.c @@ -22,7 +22,7 @@ #include "object.h" #include "array.h" #include "oidarray.h" -#include "graft.h" +#include "grafts.h" void git_commit__free(void *_commit) { @@ -504,7 +504,7 @@ int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned return error; /* Perform necessary grafts */ - if (git__graft_for_oid(&graft, repo->grafts, git_odb_object_id(odb_obj)) != GIT_ENOTFOUND) { + if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != GIT_ENOTFOUND) { size_t idx; git_oid *oid; git_array_clear(commit->parent_ids); diff --git a/src/graft.c b/src/graft.c deleted file mode 100644 index 21d32fb3846..00000000000 --- a/src/graft.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "graft.h" - -int git__graft_register(git_graftmap *grafts, const git_oid *oid, git_array_oid_t parents) -{ - git_commit_graft *graft; - git_oid *parent_oid; - int error; - size_t i; - - assert(grafts && oid); - - graft = git__calloc(1, sizeof(*graft)); - GIT_ERROR_CHECK_ALLOC(graft); - - git_array_init_to_size(graft->parents, git_array_size(parents)); - git_array_foreach(parents, i, parent_oid) { - git_oid *id = git_array_alloc(graft->parents); - GIT_ERROR_CHECK_ALLOC(id); - - git_oid_cpy(id, parent_oid); - } - git_oid_cpy(&graft->oid, oid); - - if ((error = git_oidmap_set(grafts, &graft->oid, graft)) < 0) - goto cleanup; - - return 0; - -cleanup: - git_array_clear(graft->parents); - git__free(graft); - return error; -} - -int git__graft_unregister(git_graftmap *grafts, const git_oid *oid) -{ - git_commit_graft *graft; - int error; - - assert(grafts && oid); - - if ((graft = git_oidmap_get(grafts, oid)) == NULL) - return GIT_ENOTFOUND; - - if ((error = git_oidmap_delete(grafts, oid)) < 0) - return error; - - git__free(graft); - - return 0; -} - -void git__graft_clear(git_graftmap *grafts) -{ - git_commit_graft *graft; - - assert(grafts); - - git_oidmap_foreach_value(grafts, graft, { - git__free(graft->parents.ptr); - git__free(graft); - }); - - git_oidmap_clear(grafts); -} - -int git__graft_for_oid(git_commit_graft **out, git_graftmap *grafts, const git_oid *oid) -{ - assert(out && grafts && oid); - if ((*out = git_oidmap_get(grafts, oid)) == NULL) - return GIT_ENOTFOUND; - return 0; -} diff --git a/src/grafts.c b/src/grafts.c new file mode 100644 index 00000000000..90490d0ac29 --- /dev/null +++ b/src/grafts.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "grafts.h" + +struct git_grafts { + /* Map of `git_commit_graft`s */ + git_oidmap *commits; +}; + +int git_grafts_new(git_grafts **out) +{ + git_grafts *grafts; + + grafts = git__calloc(1, sizeof(*grafts)); + GIT_ERROR_CHECK_ALLOC(grafts); + + if ((git_oidmap_new(&grafts->commits)) < 0) { + git__free(grafts); + return -1; + } + + *out = grafts; + return 0; +} + +void git_grafts_free(git_grafts *grafts) +{ + if (!grafts) + return; + git_grafts_clear(grafts); + git_oidmap_free(grafts->commits); + git__free(grafts); +} + +void git_grafts_clear(git_grafts *grafts) +{ + git_commit_graft *graft; + + assert(grafts); + + git_oidmap_foreach_value(grafts->commits, graft, { + git__free(graft->parents.ptr); + git__free(graft); + }); + + git_oidmap_clear(grafts->commits); +} + +int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents) +{ + git_commit_graft *graft; + git_oid *parent_oid; + int error; + size_t i; + + assert(grafts && oid); + + graft = git__calloc(1, sizeof(*graft)); + GIT_ERROR_CHECK_ALLOC(graft); + + git_array_init_to_size(graft->parents, git_array_size(parents)); + git_array_foreach(parents, i, parent_oid) { + git_oid *id = git_array_alloc(graft->parents); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, parent_oid); + } + git_oid_cpy(&graft->oid, oid); + + if ((error = git_oidmap_set(grafts->commits, &graft->oid, graft)) < 0) + goto cleanup; + + return 0; + +cleanup: + git_array_clear(graft->parents); + git__free(graft); + return error; +} + +int git_grafts_remove(git_grafts *grafts, const git_oid *oid) +{ + git_commit_graft *graft; + int error; + + assert(grafts && oid); + + if ((graft = git_oidmap_get(grafts->commits, oid)) == NULL) + return GIT_ENOTFOUND; + + if ((error = git_oidmap_delete(grafts->commits, oid)) < 0) + return error; + + git__free(graft); + + return 0; +} + +int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid) +{ + assert(out && grafts && oid); + if ((*out = git_oidmap_get(grafts->commits, oid)) == NULL) + return GIT_ENOTFOUND; + return 0; +} + +size_t git_grafts_size(git_grafts *grafts) +{ + return git_oidmap_size(grafts->commits); +} diff --git a/src/graft.h b/src/grafts.h similarity index 50% rename from src/graft.h rename to src/grafts.h index e2afb971131..76e8d3f2966 100644 --- a/src/graft.h +++ b/src/grafts.h @@ -17,13 +17,15 @@ typedef struct { git_array_oid_t parents; } git_commit_graft; -/* A special type of git_oidmap with git_commit_grafts as values */ -typedef git_oidmap git_graftmap; +typedef struct git_grafts git_grafts; -int git__graft_register(git_graftmap *grafts, const git_oid *oid, git_array_oid_t parents); -int git__graft_unregister(git_graftmap *grafts, const git_oid *oid); -void git__graft_clear(git_graftmap *grafts); +int git_grafts_new(git_grafts **out); +void git_grafts_free(git_grafts *grafts); +void git_grafts_clear(git_grafts *grafts); -int git__graft_for_oid(git_commit_graft **out, git_graftmap *grafts, const git_oid *oid); +int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); +int git_grafts_remove(git_grafts *grafts, const git_oid *oid); +int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); +size_t git_grafts_size(git_grafts *grafts); #endif diff --git a/src/repository.c b/src/repository.c index 977c7100285..57b91410711 100644 --- a/src/repository.c +++ b/src/repository.c @@ -147,10 +147,7 @@ int git_repository__cleanup(git_repository *repo) git_repository_submodule_cache_clear(repo); git_cache_clear(&repo->objects); git_attr_cache_flush(repo); - - git__graft_clear(repo->grafts); - git_oidmap_free(repo->grafts); - + git_grafts_free(repo->grafts); git_array_clear(repo->shallow_oids); set_config(repo, NULL); @@ -259,7 +256,7 @@ static git_repository *repository_alloc(void) /* set all the entries in the configmap cache to `unset` */ git_repository__configmap_lookup_cache_clear(repo); - if (git_oidmap_new(&repo->grafts) < 0) + if (git_grafts_new(&repo->grafts) < 0) goto on_error; return repo; @@ -610,9 +607,8 @@ static int load_grafts(git_repository *repo) if (error < 0) goto cleanup; - if (updated) { - git__graft_clear(repo->grafts); - } + if (updated) + git_grafts_clear(repo->grafts); dup_contents.ptr = contents.ptr; git_buf_foreach_line(line_start, line_end, line_num, &dup_contents) { @@ -638,7 +634,7 @@ static int load_grafts(git_repository *repo) } } - if (git__graft_register(repo->grafts, &graft_oid, parents) < 0) { + if (git_grafts_add(repo->grafts, &graft_oid, parents) < 0) { git_error_set(GIT_ERROR_REPOSITORY, "Invalid graft at line %d", line_num); error = -1; goto cleanup; @@ -668,9 +664,8 @@ static int load_shallow(git_repository *repo) } git_array_foreach(roots, i, graft_oid) { - if ((error = git__graft_register(repo->grafts, graft_oid, parents)) < 0) { + if ((error = git_grafts_add(repo->grafts, graft_oid, parents)) < 0) return error; - } } return 0; } diff --git a/src/repository.h b/src/repository.h index f7c25f589e7..fd7c274a8dc 100644 --- a/src/repository.h +++ b/src/repository.h @@ -24,7 +24,7 @@ #include "attrcache.h" #include "submodule.h" #include "diff_driver.h" -#include "graft.h" +#include "grafts.h" #include "oidarray.h" #define DOT_GIT ".git" @@ -154,7 +154,7 @@ struct git_repository { unsigned int lru_counter; - git_graftmap *grafts; + git_grafts *grafts; git_oid graft_checksum; git_oid shallow_checksum; diff --git a/tests/grafts/basic.c b/tests/grafts/basic.c index 39755ee8224..f91397002d0 100644 --- a/tests/grafts/basic.c +++ b/tests/grafts/basic.c @@ -1,7 +1,7 @@ #include "clar_libgit2.h" #include "futils.h" -#include "graft.h" +#include "grafts.h" static git_repository *g_repo; @@ -17,29 +17,28 @@ void test_grafts_basic__cleanup(void) void test_grafts_basic__graft_add(void) { + git_array_oid_t parents = GIT_ARRAY_INIT; git_oid oid_src, *oid1; git_commit_graft *graft; - git_graftmap *grafts; - git_array_oid_t parents = GIT_ARRAY_INIT; + git_grafts *grafts; - cl_git_pass(git_oidmap_new(&grafts)); + cl_git_pass(git_grafts_new(&grafts)); cl_assert(oid1 = git_array_alloc(parents)); cl_git_pass(git_oid_fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9")); git_oid_cpy(oid1, &oid_src); git_oid_fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7"); - cl_git_pass(git__graft_register(grafts, &oid_src, parents)); + cl_git_pass(git_grafts_add(grafts, &oid_src, parents)); git_array_clear(parents); - cl_assert_equal_i(1, git_oidmap_size(grafts)); - cl_git_pass(git__graft_for_oid(&graft, grafts, &oid_src)); + cl_assert_equal_i(1, git_grafts_size(grafts)); + cl_git_pass(git_grafts_get(&graft, grafts, &oid_src)); cl_assert_equal_s("f503807ffa920e407a600cfaee96b7152259acc7", git_oid_tostr_s(&graft->oid)); cl_assert_equal_i(1, git_array_size(graft->parents)); cl_assert_equal_s("2f3053cbff8a4ca2f0666de364ddb734a28a31a9", git_oid_tostr_s(git_array_get(graft->parents, 0))); - git__graft_clear(grafts); - git_oidmap_free(grafts); + git_grafts_free(grafts); } void test_grafts_basic__grafted_revwalk(void) From 14a309ab384a8732f692e468ac56c0d1831fce2f Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 3 Oct 2019 11:17:10 +0200 Subject: [PATCH 010/816] repository: convert grafts parsing to use parse context Instead of using the newly introduced `git_buf_foreach_line`, which modifies the buffer itself, we should try to use our existing parsing infrastructure in "parse.h". Convert the grafts parsing code to make use of `git_parse_ctx`. Remove the `git_buf_foreach_line` macro, as grafts have been its sole user. --- src/buffer.h | 5 ---- src/repository.c | 68 +++++++++++++++++++++++------------------------- 2 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/buffer.h b/src/buffer.h index fc8fe140055..6b717d2e90c 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -219,9 +219,4 @@ int git_buf_splice( const char *data, size_t nb_to_insert); -/* warning: this will wreck your buf contents */ -#define git_buf_foreach_line(line_start, line_end, line_num, buf) \ - while (((line_start) = git__strsep(&(buf)->ptr, "\n")) != NULL && \ - ((line_end) = (line_start) + strlen((line_start))) != NULL && ++(line_num)) - #endif diff --git a/src/repository.c b/src/repository.c index 57b91410711..4465d8e7968 100644 --- a/src/repository.c +++ b/src/repository.c @@ -31,6 +31,7 @@ #include "annotated_commit.h" #include "submodule.h" #include "worktree.h" +#include "parse.h" #include "strmap.h" @@ -581,14 +582,11 @@ static int find_repo( static int load_grafts(git_repository *repo) { + git_array_oid_t parents = GIT_ARRAY_INIT; git_buf graft_path = GIT_BUF_INIT; git_buf contents = GIT_BUF_INIT; - git_buf dup_contents; - const char *line_start; - const char *line_end; - int line_num = 0; + git_parse_ctx parser; int error, updated; - git_array_oid_t parents = GIT_ARRAY_INIT; if ((error = git_repository_item_path(&graft_path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0) return error; @@ -598,54 +596,52 @@ static int load_grafts(git_repository *repo) return error; } - error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&graft_path), &repo->graft_checksum, &updated); - git_buf_dispose(&graft_path); + error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&graft_path), + &repo->graft_checksum, &updated); + if (error < 0 || error == GIT_ENOTFOUND || !updated) { + if (error == GIT_ENOTFOUND) + error = 0; + goto cleanup; + } - if (error == GIT_ENOTFOUND || !updated) - return 0; + git_grafts_clear(repo->grafts); - if (error < 0) + if ((error = git_parse_ctx_init(&parser, contents.ptr, contents.size)) < 0) goto cleanup; - if (updated) - git_grafts_clear(repo->grafts); - - dup_contents.ptr = contents.ptr; - git_buf_foreach_line(line_start, line_end, line_num, &dup_contents) { - git_oid graft_oid, parent_oid; + for (; parser.remain_len; git_parse_advance_line(&parser)) { + const char *line_start = parser.line, *line_end = parser.line + parser.line_len; + git_oid graft_oid; - error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ); - if (error < 0) { - git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); - error = -1; - } + if (git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ) < 0) + goto invalid_oid; line_start += GIT_OID_HEXSZ; - if (*(line_start++) == ' ') { - while (git_oid_fromstrn(&parent_oid, line_start, GIT_OID_HEXSZ) == 0) { - git_oid *id = git_array_alloc(parents); + while (line_start < line_end && *line_start == ' ') { + git_oid *id = git_array_alloc(parents); + GIT_ERROR_CHECK_ALLOC(id); - git_oid_cpy(id, &parent_oid); - line_start += GIT_OID_HEXSZ; - if (line_start >= line_end) { - break; - } - line_start += 1; - } + if (git_oid_fromstrn(id, ++line_start, GIT_OID_HEXSZ) < 0) + goto invalid_oid; + line_start += GIT_OID_HEXSZ; } - if (git_grafts_add(repo->grafts, &graft_oid, parents) < 0) { - git_error_set(GIT_ERROR_REPOSITORY, "Invalid graft at line %d", line_num); - error = -1; + if ((error = git_grafts_add(repo->grafts, &graft_oid, parents)) < 0) goto cleanup; - } + git_array_clear(parents); - line_num++; + continue; + +invalid_oid: + git_error_set(GIT_ERROR_REPOSITORY, "invalid OID at line %" PRIuZ, parser.line_num); + error = -1; + goto cleanup; } cleanup: git_array_clear(parents); git_buf_dispose(&contents); + git_buf_dispose(&graft_path); return error; } From 05e286fba318d21147347a572b05b0d1dac79610 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 12 May 2020 11:30:27 +0200 Subject: [PATCH 011/816] grafts: move parsing into grafts module Parsing of grafts files is currently contained in the repository code. To make grafts-related logic more self-contained, move it into "grafts.c" instead. --- include/git2/errors.h | 3 +- src/grafts.c | 46 +++++++++++++ src/grafts.h | 1 + src/repository.c | 37 +---------- tests/grafts/parse.c | 149 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 37 deletions(-) create mode 100644 tests/grafts/parse.c diff --git a/include/git2/errors.h b/include/git2/errors.h index 8887b329901..47a79b76ccb 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -108,7 +108,8 @@ typedef enum { GIT_ERROR_WORKTREE, GIT_ERROR_SHA1, GIT_ERROR_HTTP, - GIT_ERROR_INTERNAL + GIT_ERROR_INTERNAL, + GIT_ERROR_GRAFTS } git_error_t; /** diff --git a/src/grafts.c b/src/grafts.c index 90490d0ac29..8ae39f4ac0b 100644 --- a/src/grafts.c +++ b/src/grafts.c @@ -7,6 +7,8 @@ #include "grafts.h" +#include "parse.h" + struct git_grafts { /* Map of `git_commit_graft`s */ git_oidmap *commits; @@ -51,6 +53,50 @@ void git_grafts_clear(git_grafts *grafts) git_oidmap_clear(grafts->commits); } +int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) +{ + git_array_oid_t parents = GIT_ARRAY_INIT; + git_parse_ctx parser; + int error; + + git_grafts_clear(grafts); + + if ((error = git_parse_ctx_init(&parser, content, contentlen)) < 0) + goto error; + + for (; parser.remain_len; git_parse_advance_line(&parser)) { + const char *line_start = parser.line, *line_end = parser.line + parser.line_len; + git_oid graft_oid; + + if ((error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ)) < 0) { + git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num); + goto error; + } + line_start += GIT_OID_HEXSZ; + + while (line_start < line_end && *line_start == ' ') { + git_oid *id = git_array_alloc(parents); + GIT_ERROR_CHECK_ALLOC(id); + + if ((error = git_oid_fromstrn(id, ++line_start, GIT_OID_HEXSZ)) < 0) { + git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num); + goto error; + } + + line_start += GIT_OID_HEXSZ; + } + + if ((error = git_grafts_add(grafts, &graft_oid, parents)) < 0) + goto error; + + git_array_clear(parents); + } + +error: + git_array_clear(parents); + return error; +} + int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents) { git_commit_graft *graft; diff --git a/src/grafts.h b/src/grafts.h index 76e8d3f2966..723792ded83 100644 --- a/src/grafts.h +++ b/src/grafts.h @@ -23,6 +23,7 @@ int git_grafts_new(git_grafts **out); void git_grafts_free(git_grafts *grafts); void git_grafts_clear(git_grafts *grafts); +int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen); int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); int git_grafts_remove(git_grafts *grafts, const git_oid *oid); int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); diff --git a/src/repository.c b/src/repository.c index 4465d8e7968..7721c3cd00a 100644 --- a/src/repository.c +++ b/src/repository.c @@ -31,7 +31,6 @@ #include "annotated_commit.h" #include "submodule.h" #include "worktree.h" -#include "parse.h" #include "strmap.h" @@ -582,10 +581,8 @@ static int find_repo( static int load_grafts(git_repository *repo) { - git_array_oid_t parents = GIT_ARRAY_INIT; git_buf graft_path = GIT_BUF_INIT; git_buf contents = GIT_BUF_INIT; - git_parse_ctx parser; int error, updated; if ((error = git_repository_item_path(&graft_path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0) @@ -604,42 +601,10 @@ static int load_grafts(git_repository *repo) goto cleanup; } - git_grafts_clear(repo->grafts); - - if ((error = git_parse_ctx_init(&parser, contents.ptr, contents.size)) < 0) - goto cleanup; - - for (; parser.remain_len; git_parse_advance_line(&parser)) { - const char *line_start = parser.line, *line_end = parser.line + parser.line_len; - git_oid graft_oid; - - if (git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ) < 0) - goto invalid_oid; - line_start += GIT_OID_HEXSZ; - - while (line_start < line_end && *line_start == ' ') { - git_oid *id = git_array_alloc(parents); - GIT_ERROR_CHECK_ALLOC(id); - - if (git_oid_fromstrn(id, ++line_start, GIT_OID_HEXSZ) < 0) - goto invalid_oid; - line_start += GIT_OID_HEXSZ; - } - - if ((error = git_grafts_add(repo->grafts, &graft_oid, parents)) < 0) - goto cleanup; - - git_array_clear(parents); - continue; - -invalid_oid: - git_error_set(GIT_ERROR_REPOSITORY, "invalid OID at line %" PRIuZ, parser.line_num); - error = -1; + if ((error = git_grafts_parse(repo->grafts, contents.ptr, contents.size)) < 0) goto cleanup; - } cleanup: - git_array_clear(parents); git_buf_dispose(&contents); git_buf_dispose(&graft_path); diff --git a/tests/grafts/parse.c b/tests/grafts/parse.c new file mode 100644 index 00000000000..de110c90110 --- /dev/null +++ b/tests/grafts/parse.c @@ -0,0 +1,149 @@ +#include "clar_libgit2.h" + +#include "grafts.h" + +#define OID0 "c0368f9f9743e950e6cfe1f45a649f8a9dfcd97e" +#define OID1 "cfc50a0db87ce908fb8a8c5b8f7b4ab96eee8643" +#define OID2 "6914d97cd08b9edf5e855fca211c750fa82fd80a" +#define OID3 "516521937d0e9ce9d0d836149a0702671f326b4a" +#define OID4 "e2c29d67ef2f217650196f94c796f0532b8caad6" +#define OID5 "79bcb936596cb50353fe7be28b7444e66e4a2842" +#define OID6 "b9c54107d57c17dbcaf646c4d52f66eb9e69d23d" +#define OID7 "9f8a746e9ad7b58cc840016bc3944d5ad262acb5" +#define OID8 "392f4beef7d0d15b2bc5b1abe1a754eba0ec36da" + +#define OID_TRUNCATED "392f4beef7d0d15b2bc5b1abe1a754eba0ec36d" +#define OID_NONHEX "9f8a746e9ax7b58cc840016bc3944d5ad262acb5" + +static git_grafts *grafts; + +void test_grafts_parse__initialize(void) +{ + cl_git_pass(git_grafts_new(&grafts)); +} + +void test_grafts_parse__cleanup(void) +{ + git_grafts_free(grafts); + grafts = NULL; +} + +static void assert_parse_succeeds(git_grafts *grafts, const char *string, size_t n) +{ + cl_git_pass(git_grafts_parse(grafts, string, strlen(string))); + cl_assert_equal_i(git_grafts_size(grafts), n); +} + +static void assert_parse_fails(git_grafts *grafts, const char *string) +{ + cl_git_fail(git_grafts_parse(grafts, string, strlen(string))); +} + +static void assert_graft_contains(git_grafts *grafts, const char *graft, size_t n, ...) +{ + git_commit_graft *commit; + git_oid oid; + va_list ap; + size_t i = 0; + + cl_git_pass(git_oid_fromstr(&oid, graft)); + cl_git_pass(git_grafts_get(&commit, grafts, &oid)); + cl_assert_equal_oid(&commit->oid, &oid); + cl_assert_equal_i(commit->parents.size, n); + + va_start(ap, n); + while (i < n) { + cl_git_pass(git_oid_fromstr(&oid, va_arg(ap, const char *))); + cl_assert_equal_oid(&commit->parents.ptr[i], &oid); + i++; + } + va_end(ap); +} + +void test_grafts_parse__single_oid(void) +{ + assert_parse_succeeds(grafts, OID1, 1); + assert_graft_contains(grafts, OID1, 0); +} + +void test_grafts_parse__single_oid_with_newline(void) +{ + assert_parse_succeeds(grafts, OID1 "\n", 1); + assert_graft_contains(grafts, OID1, 0); +} + +void test_grafts_parse__multiple_oids(void) +{ + assert_parse_succeeds(grafts, OID1 "\n" OID2 "\n" OID3, 3); + assert_graft_contains(grafts, OID1, 0); + assert_graft_contains(grafts, OID2, 0); + assert_graft_contains(grafts, OID3, 0); +} + +void test_grafts_parse__same_oid(void) +{ + assert_parse_succeeds(grafts, OID1 "\n" OID1, 1); + assert_graft_contains(grafts, OID1, 0); +} + +void test_grafts_parse__oid_with_parent(void) +{ + assert_parse_succeeds(grafts, OID1 " " OID2, 1); + assert_graft_contains(grafts, OID1, 1, OID2); +} + +void test_grafts_parse__oid_with_parent_and_newline(void) +{ + assert_parse_succeeds(grafts, OID1 " " OID2 "\n", 1); + assert_graft_contains(grafts, OID1, 1, OID2); +} + +void test_grafts_parse__oid_with_multiple_parents(void) +{ + assert_parse_succeeds(grafts, OID1 " " OID2 " " OID3 " " OID4 " " OID5, 1); + assert_graft_contains(grafts, OID1, 4, OID2, OID3, OID4, OID5); +} + +void test_grafts_parse__multiple_oids_with_multiple_parents(void) +{ + assert_parse_succeeds(grafts, + OID1 " " OID2 " " OID3 " " OID4 " " OID5 "\n" + OID6 " " OID7 " " OID8 "\n" , 2); + assert_graft_contains(grafts, OID1, 4, OID2, OID3, OID4, OID5); + assert_graft_contains(grafts, OID6, 2, OID7, OID8); +} + +void test_grafts_parse__multiple_spaces_fails(void) +{ + assert_parse_fails(grafts, OID1 " " OID2); +} + +void test_grafts_parse__trailing_space_fails(void) +{ + assert_parse_fails(grafts, OID1 " " OID2 " "); +} + +void test_grafts_parse__invalid_character_inbetween_fails(void) +{ + assert_parse_fails(grafts, OID1 " x " OID2); +} + +void test_grafts_parse__truncated_oid_fails(void) +{ + assert_parse_fails(grafts, OID_TRUNCATED); +} + +void test_grafts_parse__truncated_parent_fails(void) +{ + assert_parse_fails(grafts, OID1 " " OID_TRUNCATED); +} + +void test_grafts_parse__invalid_oid_fails(void) +{ + assert_parse_fails(grafts, OID_NONHEX); +} + +void test_grafts_parse__invalid_parent_fails(void) +{ + assert_parse_fails(grafts, OID1 " " OID_NONHEX); +} From a11026ecbb3575b02638ae060b20e77227e2291c Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 24 Oct 2019 13:30:24 +0200 Subject: [PATCH 012/816] repository: reuse grafts for shallow roots The shallow roots are in fact another user of the grafting mechanism, and in essence they do use the same file format for grafted commits. Thus, instead of hand-coding the parsing logic a second time, we can just reuse the `git_grafts` structure for shallow commits, as well. --- include/git2/repository.h | 3 +- src/grafts.c | 21 ++++++++ src/grafts.h | 1 + src/repository.c | 103 ++++++++++++-------------------------- src/repository.h | 4 +- tests/grafts/shallow.c | 21 ++++---- 6 files changed, 68 insertions(+), 85 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 5a27cf08e8d..59e938710c7 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -878,7 +878,8 @@ GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); /** * Determine the shallow roots of the repository * - * This oidarray is owned by the library. Do not free it. + * The resulting OID array needs to be free'd by calling + * `git_oidarray_free`. * * @param out An array of shallow oids. * @param repo The repository diff --git a/src/grafts.c b/src/grafts.c index 8ae39f4ac0b..23b012ce8eb 100644 --- a/src/grafts.c +++ b/src/grafts.c @@ -7,6 +7,7 @@ #include "grafts.h" +#include "oidarray.h" #include "parse.h" struct git_grafts { @@ -155,6 +156,26 @@ int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oi return 0; } +int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts) +{ + git_array_oid_t oids = GIT_ARRAY_INIT; + const git_oid *oid; + size_t i = 0; + int error; + + assert(out && grafts); + + while ((error = git_oidmap_iterate(NULL, grafts->commits, &i, &oid)) == 0) { + git_oid *cpy = git_array_alloc(oids); + GIT_ERROR_CHECK_ALLOC(cpy); + git_oid_cpy(cpy, oid); + } + + git_oidarray__from_array(out, &oids); + + return 0; +} + size_t git_grafts_size(git_grafts *grafts) { return git_oidmap_size(grafts->commits); diff --git a/src/grafts.h b/src/grafts.h index 723792ded83..305b0d61adf 100644 --- a/src/grafts.h +++ b/src/grafts.h @@ -27,6 +27,7 @@ int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); int git_grafts_remove(git_grafts *grafts, const git_oid *oid); int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); +int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts); size_t git_grafts_size(git_grafts *grafts); #endif diff --git a/src/repository.c b/src/repository.c index 7721c3cd00a..fc14ef4d6e2 100644 --- a/src/repository.c +++ b/src/repository.c @@ -148,7 +148,7 @@ int git_repository__cleanup(git_repository *repo) git_cache_clear(&repo->objects); git_attr_cache_flush(repo); git_grafts_free(repo->grafts); - git_array_clear(repo->shallow_oids); + git_grafts_free(repo->shallow_grafts); set_config(repo, NULL); set_index(repo, NULL); @@ -613,22 +613,22 @@ static int load_grafts(git_repository *repo) static int load_shallow(git_repository *repo) { - int error = 0; - git_array_oid_t roots = GIT_ARRAY_INIT; git_array_oid_t parents = GIT_ARRAY_INIT; + git_oidarray roots; + int error; size_t i; - git_oid *graft_oid; /* Graft shallow roots */ - if ((error = git_repository__shallow_roots(&roots, repo)) < 0) { - return error; - } + if ((error = git_repository_shallow_roots(&roots, repo)) < 0) + goto out; - git_array_foreach(roots, i, graft_oid) { - if ((error = git_grafts_add(repo->grafts, graft_oid, parents)) < 0) - return error; - } - return 0; + for (i = 0; i < roots.count; i++) + if ((error = git_grafts_add(repo->grafts, &roots.ids[i], parents)) < 0) + goto out; + +out: + git_oidarray_free(&roots); + return error; } int git_repository_open_bare( @@ -2960,79 +2960,38 @@ int git_repository_state_cleanup(git_repository *repo) return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); } -int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) +int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) { - git_buf path = GIT_BUF_INIT; - git_buf contents = GIT_BUF_INIT; - int error, updated, line_num = 1; - char *line; - char *buffer; - - assert(out && repo); - - if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) - return error; - - error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_checksum, &updated); - git_buf_dispose(&path); + git_buf path = GIT_BUF_INIT, contents = GIT_BUF_INIT; + int error, updated = 0; - if (error < 0 && error != GIT_ENOTFOUND) - return error; - - /* cancel out GIT_ENOTFOUND */ - git_error_clear(); - error = 0; - - if (!updated) { - *out = repo->shallow_oids; - goto cleanup; - } + assert(out && repo); - git_array_clear(repo->shallow_oids); + memset(out, 0, sizeof(*out)); - buffer = contents.ptr; - while ((line = git__strsep(&buffer, "\n")) != NULL) { - git_oid *oid = git_array_alloc(repo->shallow_oids); + if (!repo->shallow_grafts && (error = git_grafts_new(&repo->shallow_grafts)) < 0) + goto error; - error = git_oid_fromstr(oid, line); - if (error < 0) { - git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); - git_array_clear(repo->shallow_oids); - error = -1; - goto cleanup; - } - ++line_num; + if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0 || + (error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), + &repo->shallow_checksum, &updated)) < 0) { + if (error == GIT_ENOTFOUND) + error = 0; + goto error; } - if (*buffer) { - git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); - git_array_clear(repo->shallow_oids); - error = -1; - goto cleanup; - } + if (updated && (error = git_grafts_parse(repo->shallow_grafts, contents.ptr, contents.size)) < 0) + goto error; - *out = repo->shallow_oids; + if ((error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) + goto error; -cleanup: +error: + git_buf_dispose(&path); git_buf_dispose(&contents); - return error; } -int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) -{ - int ret; - git_array_oid_t array = GIT_ARRAY_INIT; - - assert(out); - - ret = git_repository__shallow_roots(&array, repo); - - git_oidarray__from_array(out, &array); - - return ret; -} - int git_repository_is_shallow(git_repository *repo) { git_buf path = GIT_BUF_INIT; diff --git a/src/repository.h b/src/repository.h index fd7c274a8dc..14b2665675e 100644 --- a/src/repository.h +++ b/src/repository.h @@ -157,8 +157,8 @@ struct git_repository { git_grafts *grafts; git_oid graft_checksum; + git_grafts *shallow_grafts; git_oid shallow_checksum; - git_array_oid_t shallow_oids; git_atomic attr_session_key; @@ -263,6 +263,4 @@ extern size_t git_repository__reserved_names_posix_len; bool git_repository__reserved_names( git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs); -int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo); - #endif diff --git a/tests/grafts/shallow.c b/tests/grafts/shallow.c index e4a0f741f0b..fc74de4385b 100644 --- a/tests/grafts/shallow.c +++ b/tests/grafts/shallow.c @@ -42,38 +42,41 @@ void test_grafts_shallow__clears_errors(void) void test_grafts_shallow__shallow_oids(void) { - git_oidarray oids, oids2; + git_oidarray oids; g_repo = cl_git_sandbox_init("shallow.git"); cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); cl_assert_equal_i(1, oids.count); cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); - cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); - cl_assert_equal_p(oids.ids, oids2.ids); + git_oidarray_free(&oids); } void test_grafts_shallow__cache_clearing(void) { - git_oidarray oids, oids2; + git_oidarray oids; git_oid tmp_oid; - git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000"); + cl_git_pass(git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000")); g_repo = cl_git_sandbox_init("shallow.git"); cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); cl_assert_equal_i(1, oids.count); cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); + git_oidarray_free(&oids); cl_git_mkfile("shallow.git/shallow", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644\n" "0000000000000000000000000000000000000000\n" ); - cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); - cl_assert_equal_i(2, oids2.count); - cl_assert_equal_oid(&g_shallow_oid, &oids2.ids[0]); - cl_assert_equal_oid(&tmp_oid, &oids2.ids[1]); + cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); + cl_assert_equal_i(2, oids.count); + cl_assert((git_oid_equal(&g_shallow_oid, &oids.ids[0]) && + git_oid_equal(&tmp_oid, &oids.ids[1])) || + (git_oid_equal(&g_shallow_oid, &oids.ids[1]) && + git_oid_equal(&tmp_oid, &oids.ids[0]))); + git_oidarray_free(&oids); cl_git_pass(p_unlink("shallow.git/shallow")); cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); From 70867f7c594ea6960c07d10fef32c932f7fa3bbb Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 3 Oct 2019 13:08:24 +0200 Subject: [PATCH 013/816] repository: disentangle shallow and normal grafts When loading shallow grafts, we add each of the grafting commits to the grafts backed by ".git/info/grafts". Keeping track of both grafts separately, but partially storing them in a common grafts structure is likely to lead to inconsistencies. In fact, there already are inconsistencies if refreshing shallow grafts at a later point, as we only refresh the shallows, but not the normal grafts in that case. Disentangle both grafting stores and instead check both separately when parsing commits. --- src/commit.c | 3 ++- src/repository.c | 11 ++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/commit.c b/src/commit.c index e06faafe781..b498fd77eb7 100644 --- a/src/commit.c +++ b/src/commit.c @@ -504,7 +504,8 @@ int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned return error; /* Perform necessary grafts */ - if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != GIT_ENOTFOUND) { + if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) == 0 || + git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) == 0) { size_t idx; git_oid *oid; git_array_clear(commit->parent_ids); diff --git a/src/repository.c b/src/repository.c index fc14ef4d6e2..cad80845d32 100644 --- a/src/repository.c +++ b/src/repository.c @@ -613,22 +613,15 @@ static int load_grafts(git_repository *repo) static int load_shallow(git_repository *repo) { - git_array_oid_t parents = GIT_ARRAY_INIT; git_oidarray roots; int error; - size_t i; /* Graft shallow roots */ if ((error = git_repository_shallow_roots(&roots, repo)) < 0) - goto out; - - for (i = 0; i < roots.count; i++) - if ((error = git_grafts_add(repo->grafts, &roots.ids[i], parents)) < 0) - goto out; + return error; -out: git_oidarray_free(&roots); - return error; + return 0; } int git_repository_open_bare( From fd2398b2fc09e3ae292fb33f2ec2a45b6bf8e3e9 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 3 Oct 2019 13:24:25 +0200 Subject: [PATCH 014/816] grafts: move refresh logic into grafts code The refresh logic for both "normal" and shallow grafts are currently part of the repository code and implemented twice. Unify them into the grafts code by introducing two new functions to create grafts from a file and to refresh a grafts structure. --- src/grafts.c | 55 ++++++++++++++++++++++++++++++++++++ src/grafts.h | 2 ++ src/repository.c | 73 ++++++++++-------------------------------------- src/repository.h | 3 -- 4 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/grafts.c b/src/grafts.c index 23b012ce8eb..da5bd10504b 100644 --- a/src/grafts.c +++ b/src/grafts.c @@ -7,12 +7,17 @@ #include "grafts.h" +#include "futils.h" #include "oidarray.h" #include "parse.h" struct git_grafts { /* Map of `git_commit_graft`s */ git_oidmap *commits; + + /* File backing the graft. NULL if it's an in-memory graft */ + char *path; + git_oid path_checksum; }; int git_grafts_new(git_grafts **out) @@ -31,10 +36,32 @@ int git_grafts_new(git_grafts **out) return 0; } +int git_grafts_from_file(git_grafts **out, const char *path) +{ + git_grafts *grafts = NULL; + int error; + + if ((error = git_grafts_new(&grafts)) < 0) + goto error; + + grafts->path = git__strdup(path); + GIT_ERROR_CHECK_ALLOC(grafts->path); + + if ((error = git_grafts_refresh(grafts)) < 0) + goto error; + + *out = grafts; +error: + if (error < 0) + git_grafts_free(grafts); + return error; +} + void git_grafts_free(git_grafts *grafts) { if (!grafts) return; + git__free(grafts->path); git_grafts_clear(grafts); git_oidmap_free(grafts->commits); git__free(grafts); @@ -54,6 +81,34 @@ void git_grafts_clear(git_grafts *grafts) git_oidmap_clear(grafts->commits); } +int git_grafts_refresh(git_grafts *grafts) +{ + git_buf contents = GIT_BUF_INIT; + int error, updated = 0; + + assert(grafts); + + if (!grafts->path) + return 0; + + error = git_futils_readbuffer_updated(&contents, grafts->path, + &grafts->path_checksum, &updated); + if (error < 0 || error == GIT_ENOTFOUND || !updated) { + if (error == GIT_ENOTFOUND) { + git_grafts_clear(grafts); + error = 0; + } + goto cleanup; + } + + if ((error = git_grafts_parse(grafts, contents.ptr, contents.size)) < 0) + goto cleanup; + +cleanup: + git_buf_dispose(&contents); + return error; +} + int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) { git_array_oid_t parents = GIT_ARRAY_INIT; diff --git a/src/grafts.h b/src/grafts.h index 305b0d61adf..30062725e27 100644 --- a/src/grafts.h +++ b/src/grafts.h @@ -20,9 +20,11 @@ typedef struct { typedef struct git_grafts git_grafts; int git_grafts_new(git_grafts **out); +int git_grafts_from_file(git_grafts **out, const char *path); void git_grafts_free(git_grafts *grafts); void git_grafts_clear(git_grafts *grafts); +int git_grafts_refresh(git_grafts *grafts); int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen); int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); int git_grafts_remove(git_grafts *grafts, const git_oid *oid); diff --git a/src/repository.c b/src/repository.c index cad80845d32..730f19c20c7 100644 --- a/src/repository.c +++ b/src/repository.c @@ -256,9 +256,6 @@ static git_repository *repository_alloc(void) /* set all the entries in the configmap cache to `unset` */ git_repository__configmap_lookup_cache_clear(repo); - if (git_grafts_new(&repo->grafts) < 0) - goto on_error; - return repo; on_error: @@ -581,49 +578,25 @@ static int find_repo( static int load_grafts(git_repository *repo) { - git_buf graft_path = GIT_BUF_INIT; - git_buf contents = GIT_BUF_INIT; - int error, updated; - - if ((error = git_repository_item_path(&graft_path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0) - return error; - - if (git_buf_joinpath(&graft_path, graft_path.ptr, "grafts")) { - git_buf_dispose(&graft_path); - return error; - } + git_buf path = GIT_BUF_INIT; + int error; - error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&graft_path), - &repo->graft_checksum, &updated); - if (error < 0 || error == GIT_ENOTFOUND || !updated) { - if (error == GIT_ENOTFOUND) - error = 0; - goto cleanup; - } + if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || + (error = git_buf_joinpath(&path, path.ptr, "grafts")) < 0 || + (error = git_grafts_from_file(&repo->grafts, path.ptr)) < 0) + goto error; - if ((error = git_grafts_parse(repo->grafts, contents.ptr, contents.size)) < 0) - goto cleanup; + git_buf_clear(&path); -cleanup: - git_buf_dispose(&contents); - git_buf_dispose(&graft_path); + if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0 || + (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr)) < 0) + goto error; +error: + git_buf_dispose(&path); return error; } -static int load_shallow(git_repository *repo) -{ - git_oidarray roots; - int error; - - /* Graft shallow roots */ - if ((error = git_repository_shallow_roots(&roots, repo)) < 0) - return error; - - git_oidarray_free(&roots); - return 0; -} - int git_repository_open_bare( git_repository **repo_ptr, const char *bare_path) @@ -916,9 +889,6 @@ int git_repository_open_ext( if ((error = load_grafts(repo)) < 0) goto cleanup; - if ((error = load_shallow(repo)) < 0) - goto cleanup; - if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) repo->is_bare = 1; else { @@ -2956,27 +2926,14 @@ int git_repository_state_cleanup(git_repository *repo) int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) { git_buf path = GIT_BUF_INIT, contents = GIT_BUF_INIT; - int error, updated = 0; + int error; assert(out && repo); memset(out, 0, sizeof(*out)); - if (!repo->shallow_grafts && (error = git_grafts_new(&repo->shallow_grafts)) < 0) - goto error; - - if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0 || - (error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), - &repo->shallow_checksum, &updated)) < 0) { - if (error == GIT_ENOTFOUND) - error = 0; - goto error; - } - - if (updated && (error = git_grafts_parse(repo->shallow_grafts, contents.ptr, contents.size)) < 0) - goto error; - - if ((error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) + if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0 || + (error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) goto error; error: diff --git a/src/repository.h b/src/repository.h index 14b2665675e..81f2bc10114 100644 --- a/src/repository.h +++ b/src/repository.h @@ -155,10 +155,7 @@ struct git_repository { unsigned int lru_counter; git_grafts *grafts; - git_oid graft_checksum; - git_grafts *shallow_grafts; - git_oid shallow_checksum; git_atomic attr_session_key; From a4803c3c5ae2d3e038d56fcfe52215bc2364521a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 10 Oct 2019 13:40:22 +0200 Subject: [PATCH 015/816] grafts: fix memory leak if replacing pre-existing graft If replacing an already existing graft in the grafts map, then we need to free the previous `git_commit_graft` structure. --- src/grafts.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/grafts.c b/src/grafts.c index da5bd10504b..55eb33615ab 100644 --- a/src/grafts.c +++ b/src/grafts.c @@ -174,6 +174,8 @@ int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t paren } git_oid_cpy(&graft->oid, oid); + if ((error = git_grafts_remove(grafts, &graft->oid)) < 0 && error != GIT_ENOTFOUND) + goto cleanup; if ((error = git_oidmap_set(grafts->commits, &graft->oid, graft)) < 0) goto cleanup; @@ -198,6 +200,7 @@ int git_grafts_remove(git_grafts *grafts, const git_oid *oid) if ((error = git_oidmap_delete(grafts->commits, oid)) < 0) return error; + git__free(graft->parents.ptr); git__free(graft); return 0; From 79af067665c37b6dc0b31edb35596c362b0cd9a0 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 24 Oct 2019 13:54:42 +0200 Subject: [PATCH 016/816] repository: do not expose grafting mechanism Currently, we expose the function `git_repository_shallow_roots` to get all grafted roots of the repository. This already paints us into a corner, though, as we certainly need to experiment with some functionality of the grafting mechanism before we can happily expose some of its functionality. Most importantly, we need to get right when to refresh grafts and when not. Thus, this commit removes the public function with no public replacement. We should first try and see what usecases people come up with to e.g. expose the `git_grafts` mechanism directly in the future or do something different altogether. Instead, we provide an internal interface to get weak pointers to the grafting structs part of the repository itself. --- include/git2/repository.h | 12 --------- src/repository.c | 33 +++++++++++------------- src/repository.h | 2 ++ tests/grafts/shallow.c | 53 ++++++++++++++++++++------------------- 4 files changed, 43 insertions(+), 57 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 59e938710c7..aa81e384352 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -875,18 +875,6 @@ GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); */ GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); -/** - * Determine the shallow roots of the repository - * - * The resulting OID array needs to be free'd by calling - * `git_oidarray_free`. - * - * @param out An array of shallow oids. - * @param repo The repository - * @return 0 on success, an error otherwise. - */ -GIT_EXTERN(int) git_repository_shallow_roots(git_oidarray *out, git_repository *repo); - /** * Retrieve the configured identity to use for reflogs * diff --git a/src/repository.c b/src/repository.c index 730f19c20c7..bc5ee6ac059 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1263,6 +1263,20 @@ int git_repository_set_index(git_repository *repo, git_index *index) return 0; } +int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo) +{ + assert(out && repo && repo->shallow_grafts); + *out = repo->grafts; + return 0; +} + +int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo) +{ + assert(out && repo && repo->shallow_grafts); + *out = repo->shallow_grafts; + return 0; +} + int git_repository_set_namespace(git_repository *repo, const char *namespace) { git__free(repo->namespace); @@ -2923,25 +2937,6 @@ int git_repository_state_cleanup(git_repository *repo) return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); } -int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) -{ - git_buf path = GIT_BUF_INIT, contents = GIT_BUF_INIT; - int error; - - assert(out && repo); - - memset(out, 0, sizeof(*out)); - - if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0 || - (error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) - goto error; - -error: - git_buf_dispose(&path); - git_buf_dispose(&contents); - return error; -} - int git_repository_is_shallow(git_repository *repo) { git_buf path = GIT_BUF_INIT; diff --git a/src/repository.h b/src/repository.h index 81f2bc10114..5922bf02a07 100644 --- a/src/repository.h +++ b/src/repository.h @@ -211,6 +211,8 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo); int git_repository_odb__weakptr(git_odb **out, git_repository *repo); int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo); int git_repository_index__weakptr(git_index **out, git_repository *repo); +int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo); +int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo); /* * Configuration map cache diff --git a/tests/grafts/shallow.c b/tests/grafts/shallow.c index fc74de4385b..8fe3421f280 100644 --- a/tests/grafts/shallow.c +++ b/tests/grafts/shallow.c @@ -1,5 +1,8 @@ #include "clar_libgit2.h" + #include "futils.h" +#include "grafts.h" +#include "repository.h" static git_repository *g_repo; static git_oid g_shallow_oid; @@ -42,61 +45,59 @@ void test_grafts_shallow__clears_errors(void) void test_grafts_shallow__shallow_oids(void) { - git_oidarray oids; - g_repo = cl_git_sandbox_init("shallow.git"); + git_commit_graft *graft; + git_grafts *grafts; - cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); - cl_assert_equal_i(1, oids.count); - cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); + g_repo = cl_git_sandbox_init("shallow.git"); - git_oidarray_free(&oids); + cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo)); + cl_assert_equal_i(1, git_grafts_size(grafts)); + cl_git_pass(git_grafts_get(&graft, grafts, &g_shallow_oid)); } void test_grafts_shallow__cache_clearing(void) { - git_oidarray oids; + git_commit_graft *graft; + git_grafts *grafts; git_oid tmp_oid; cl_git_pass(git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000")); g_repo = cl_git_sandbox_init("shallow.git"); + cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo)); - cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); - cl_assert_equal_i(1, oids.count); - cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); - git_oidarray_free(&oids); + cl_assert_equal_i(1, git_grafts_size(grafts)); + cl_git_pass(git_grafts_get(&graft, grafts, &g_shallow_oid)); cl_git_mkfile("shallow.git/shallow", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644\n" "0000000000000000000000000000000000000000\n" ); - cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); - cl_assert_equal_i(2, oids.count); - cl_assert((git_oid_equal(&g_shallow_oid, &oids.ids[0]) && - git_oid_equal(&tmp_oid, &oids.ids[1])) || - (git_oid_equal(&g_shallow_oid, &oids.ids[1]) && - git_oid_equal(&tmp_oid, &oids.ids[0]))); - git_oidarray_free(&oids); + cl_git_pass(git_grafts_refresh(grafts)); + cl_assert_equal_i(2, git_grafts_size(grafts)); + cl_git_pass(git_grafts_get(&graft, grafts, &g_shallow_oid)); + cl_git_pass(git_grafts_get(&graft, grafts, &tmp_oid)); cl_git_pass(p_unlink("shallow.git/shallow")); - cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); - cl_assert_equal_i(0, oids.count); - git_oidarray_free(&oids); + cl_git_pass(git_grafts_refresh(grafts)); + cl_assert_equal_i(0, git_grafts_size(grafts)); } void test_grafts_shallow__errors_on_borked(void) { - git_oidarray oids; + git_grafts *grafts; g_repo = cl_git_sandbox_init("shallow.git"); cl_git_mkfile("shallow.git/shallow", "lolno"); - - cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); + cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo)); + cl_git_fail(git_grafts_refresh(grafts)); + cl_assert_equal_i(0, git_grafts_size(grafts)); cl_git_mkfile("shallow.git/shallow", "lolno\n"); - - cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); + cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo)); + cl_git_fail(git_grafts_refresh(grafts)); + cl_assert_equal_i(0, git_grafts_size(grafts)); } void test_grafts_shallow__revwalk_behavior(void) From 7ed00c5c92682edea3a67581c534ea5e970db038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Wed, 2 Jun 2021 16:31:54 +0200 Subject: [PATCH 017/816] Support authentication in push example This adds basic support for user/password and SSH authentication to the push example. Authentication is implemented by using the cred_acquire_cb credential callback defined in examples/common.c. Co-authored-by: Marius Knaust --- examples/push.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/push.c b/examples/push.c index bcf307607b0..5113eed394b 100644 --- a/examples/push.c +++ b/examples/push.c @@ -32,6 +32,7 @@ /** Entry point for this command */ int lg2_push(git_repository *repo, int argc, char **argv) { git_push_options options; + git_remote_callbacks callbacks; git_remote* remote = NULL; char *refspec = "refs/heads/master"; const git_strarray refspecs = { @@ -47,7 +48,11 @@ int lg2_push(git_repository *repo, int argc, char **argv) { check_lg2(git_remote_lookup(&remote, repo, "origin" ), "Unable to lookup remote", NULL); + check_lg2(git_remote_init_callbacks(&callbacks, GIT_REMOTE_CALLBACKS_VERSION), "Error initializing remote callbacks", NULL); + callbacks.credentials = cred_acquire_cb; + check_lg2(git_push_options_init(&options, GIT_PUSH_OPTIONS_VERSION ), "Error initializing push", NULL); + options.callbacks = callbacks; check_lg2(git_remote_push(remote, &refspecs, &options), "Error pushing", NULL); From ed241cea1a2b1d195722d5de7e3295be9ea3a5e3 Mon Sep 17 00:00:00 2001 From: xphoniex Date: Mon, 28 Feb 2022 18:07:53 +0000 Subject: [PATCH 018/816] Swap `GIT_DIFF_LINE_(ADD|DEL)_EOFNL` to match other Diffs Signed-off-by: xphoniex --- src/libgit2/patch_parse.c | 4 ++-- tests/libgit2/diff/parse.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/libgit2/patch_parse.c b/src/libgit2/patch_parse.c index 78cd96252f8..be765febd0a 100644 --- a/src/libgit2/patch_parse.c +++ b/src/libgit2/patch_parse.c @@ -558,9 +558,9 @@ static int parse_hunk_header( static int eof_for_origin(int origin) { if (origin == GIT_DIFF_LINE_ADDITION) - return GIT_DIFF_LINE_ADD_EOFNL; - if (origin == GIT_DIFF_LINE_DELETION) return GIT_DIFF_LINE_DEL_EOFNL; + if (origin == GIT_DIFF_LINE_DELETION) + return GIT_DIFF_LINE_ADD_EOFNL; return GIT_DIFF_LINE_CONTEXT_EOFNL; } diff --git a/tests/libgit2/diff/parse.c b/tests/libgit2/diff/parse.c index d3a0c8de6d4..48f924fe087 100644 --- a/tests/libgit2/diff/parse.c +++ b/tests/libgit2/diff/parse.c @@ -279,6 +279,31 @@ static int file_cb(const git_diff_delta *delta, float progress, void *payload) return 0; } +void test_diff_parse__eof_nl_missing(void) +{ + const char patch[] = + "diff --git a/.env b/.env\n" + "index f89e4c0..7c56eb7 100644\n" + "--- a/.env\n" + "+++ b/.env\n" + "@@ -1 +1 @@\n" + "-hello=12345\n" + "+hello=123456\n" + "\\ No newline at end of file\n"; + git_diff *diff; + git_patch *ret_patch; + git_diff_line *line; + + cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(git_patch_from_diff(&ret_patch, diff, 0)); + + cl_assert((line = git_array_get(ret_patch->lines, 2)) != NULL); + cl_assert(line->origin == GIT_DIFF_LINE_DEL_EOFNL); + + git_diff_free(diff); + git_patch_free(ret_patch); +} + void test_diff_parse__foreach_works_with_parsed_patch(void) { const char patch[] = From 13bd14d930006bc01b89f9fd4d0b074c387ef92f Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 27 Jun 2022 10:56:02 +0100 Subject: [PATCH 019/816] add feature flag for shallow clone support --- include/git2/common.h | 6 +++++- src/libgit2.c | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/git2/common.h b/include/git2/common.h index 2ee82902529..dff64103d87 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -211,7 +211,8 @@ typedef enum { GIT_OPT_SET_ODB_PACKED_PRIORITY, GIT_OPT_SET_ODB_LOOSE_PRIORITY, GIT_OPT_GET_EXTENSIONS, - GIT_OPT_SET_EXTENSIONS + GIT_OPT_SET_EXTENSIONS, + GIT_OPT_ENABLE_SHALLOW } git_libgit2_opt_t; /** @@ -448,6 +449,9 @@ typedef enum { * > { "!noop", "newext" } indicates that the caller does not want * > to support repositories with the `noop` extension but does want * > to support repositories with the `newext` extension. + * + * opts(GIT_OPT_ENABLE_SHALLOW, int enabled) + * > Enable or disable shallow clone support completely. * * @param option Option key * @param ... value to set the option diff --git a/src/libgit2.c b/src/libgit2.c index cc793b4587f..4eef2c618c4 100644 --- a/src/libgit2.c +++ b/src/libgit2.c @@ -390,6 +390,10 @@ int git_libgit2_opts(int key, ...) } break; + case GIT_OPT_ENABLE_SHALLOW: + git_cache__enabled = (va_arg(ap, int) != 0); + break; + default: git_error_set(GIT_ERROR_INVALID, "invalid option key"); error = -1; From 7a936258ddc93e012be8182a08f3c3e220bc6cbc Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 27 Jun 2022 13:35:46 +0100 Subject: [PATCH 020/816] add test for shallow feature flag --- tests/shallow/feature_flag.c | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/shallow/feature_flag.c diff --git a/tests/shallow/feature_flag.c b/tests/shallow/feature_flag.c new file mode 100644 index 00000000000..25d283a4489 --- /dev/null +++ b/tests/shallow/feature_flag.c @@ -0,0 +1,11 @@ +#include "clar_libgit2.h" + +void test_shallow_feature_flag__set_feature_flag(void) +{ + cl_must_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1)); +} + +void test_shallow_feature_flag__unset_feature_flag(void) +{ + cl_must_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0)); +} From 89494f6787407269c1eaa868058e30e35145b02f Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 27 Jun 2022 14:10:32 +0100 Subject: [PATCH 021/816] add shallow.h --- src/libgit2.c | 2 +- src/shallow.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 src/shallow.h diff --git a/src/libgit2.c b/src/libgit2.c index 4eef2c618c4..b6d2f0a80f7 100644 --- a/src/libgit2.c +++ b/src/libgit2.c @@ -391,7 +391,7 @@ int git_libgit2_opts(int key, ...) break; case GIT_OPT_ENABLE_SHALLOW: - git_cache__enabled = (va_arg(ap, int) != 0); + git_shallow__enabled = (va_arg(ap, int) != 0); break; default: diff --git a/src/shallow.h b/src/shallow.h new file mode 100644 index 00000000000..6e2bbbb5f6c --- /dev/null +++ b/src/shallow.h @@ -0,0 +1,3 @@ +#include "common.h" + +extern bool git_shallow__enabled; From 562246b415edf6abe9988d44e9044a8504989868 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 27 Jun 2022 15:34:35 +0100 Subject: [PATCH 022/816] move declaration of feature flag to graft.h/graft.c --- src/grafts.c | 2 ++ src/grafts.h | 2 ++ src/shallow.h | 3 --- 3 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 src/shallow.h diff --git a/src/grafts.c b/src/grafts.c index 55eb33615ab..94bbf7de2d5 100644 --- a/src/grafts.c +++ b/src/grafts.c @@ -11,6 +11,8 @@ #include "oidarray.h" #include "parse.h" +bool git_cache__enabled = true; + struct git_grafts { /* Map of `git_commit_graft`s */ git_oidmap *commits; diff --git a/src/grafts.h b/src/grafts.h index 30062725e27..fd9ef673698 100644 --- a/src/grafts.h +++ b/src/grafts.h @@ -19,6 +19,8 @@ typedef struct { typedef struct git_grafts git_grafts; +extern bool git_shallow__enabled; + int git_grafts_new(git_grafts **out); int git_grafts_from_file(git_grafts **out, const char *path); void git_grafts_free(git_grafts *grafts); diff --git a/src/shallow.h b/src/shallow.h deleted file mode 100644 index 6e2bbbb5f6c..00000000000 --- a/src/shallow.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "common.h" - -extern bool git_shallow__enabled; From 6bab22f4d3c659a7d4282080ac4d662066411f55 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 27 Jun 2022 15:49:54 +0100 Subject: [PATCH 023/816] move feature flag tests to tests/grafts/shallow.c --- src/libgit2.c | 1 + tests/grafts/shallow.c | 10 ++++++++++ tests/shallow/feature_flag.c | 11 ----------- 3 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 tests/shallow/feature_flag.c diff --git a/src/libgit2.c b/src/libgit2.c index b6d2f0a80f7..a4f0b4007b8 100644 --- a/src/libgit2.c +++ b/src/libgit2.c @@ -12,6 +12,7 @@ #include "cache.h" #include "common.h" #include "filter.h" +#include "grafts.h" #include "hash.h" #include "index.h" #include "merge_driver.h" diff --git a/tests/grafts/shallow.c b/tests/grafts/shallow.c index 8fe3421f280..ac1d686af8f 100644 --- a/tests/grafts/shallow.c +++ b/tests/grafts/shallow.c @@ -7,6 +7,16 @@ static git_repository *g_repo; static git_oid g_shallow_oid; +void test_grafts_shallow__set_feature_flag(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1)); +} + +void test_grafts_shallow__unset_feature_flag(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0)); +} + void test_grafts_shallow__initialize(void) { cl_git_pass(git_oid_fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); diff --git a/tests/shallow/feature_flag.c b/tests/shallow/feature_flag.c deleted file mode 100644 index 25d283a4489..00000000000 --- a/tests/shallow/feature_flag.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "clar_libgit2.h" - -void test_shallow_feature_flag__set_feature_flag(void) -{ - cl_must_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1)); -} - -void test_shallow_feature_flag__unset_feature_flag(void) -{ - cl_must_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0)); -} From ad5635525131b3435a6dffab29eae439e932f2cd Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 27 Jun 2022 16:27:00 +0100 Subject: [PATCH 024/816] use shallow feature flag in shallow clone support source code --- src/commit.c | 38 ++++++++++++++++++++++---------------- src/repository.c | 2 +- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/commit.c b/src/commit.c index 2a1bafae23a..ab68634815f 100644 --- a/src/commit.c +++ b/src/commit.c @@ -500,29 +500,35 @@ int git_commit__parse_raw(void *commit, const char *data, size_t size) int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) { - git_repository *repo = git_object_owner((git_object *)commit); - git_commit_graft *graft; - int error; + int error; + if ((error = commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags)) < 0) return error; - /* Perform necessary grafts */ - if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) == 0 || - git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) == 0) { - size_t idx; - git_oid *oid; - git_array_clear(commit->parent_ids); - git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); - git_array_foreach(graft->parents, idx, oid) { - git_oid *id = git_array_alloc(commit->parent_ids); - GIT_ERROR_CHECK_ALLOC(id); - - git_oid_cpy(id, oid); + if (GIT_OPT_ENABLE_SHALLOW) { + + git_repository *repo = git_object_owner((git_object *)commit); + git_commit_graft *graft; + + /* Perform necessary grafts */ + if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) == 0 || + git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) == 0) { + size_t idx; + git_oid *oid; + git_array_clear(commit->parent_ids); + git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); + git_array_foreach(graft->parents, idx, oid) { + git_oid *id = git_array_alloc(commit->parent_ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, oid); + } } - } + } + return 0; } diff --git a/src/repository.c b/src/repository.c index 5297a884046..f9b34445c1f 100644 --- a/src/repository.c +++ b/src/repository.c @@ -926,7 +926,7 @@ int git_repository_open_ext( if ((error = check_extensions(config, version)) < 0) goto cleanup; - if ((error = load_grafts(repo)) < 0) + if (GIT_OPT_ENABLE_SHALLOW && (error = load_grafts(repo)) < 0) goto cleanup; if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) From c4cd9a54b83700bd9166a78af3986df0e42e1e92 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 27 Jun 2022 16:31:22 +0100 Subject: [PATCH 025/816] correct naming of feature flag --- src/grafts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grafts.c b/src/grafts.c index 94bbf7de2d5..0ffe4677a59 100644 --- a/src/grafts.c +++ b/src/grafts.c @@ -11,7 +11,7 @@ #include "oidarray.h" #include "parse.h" -bool git_cache__enabled = true; +bool git_shallow__enabled = true; struct git_grafts { /* Map of `git_commit_graft`s */ From 59189757116e2f793f0901afdfa0dea916d34444 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 28 Jun 2022 09:29:10 +0100 Subject: [PATCH 026/816] disable shallow clone support by default --- src/grafts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grafts.c b/src/grafts.c index 0ffe4677a59..00352261670 100644 --- a/src/grafts.c +++ b/src/grafts.c @@ -11,7 +11,7 @@ #include "oidarray.h" #include "parse.h" -bool git_shallow__enabled = true; +bool git_shallow__enabled = false; struct git_grafts { /* Map of `git_commit_graft`s */ From 397753f01701ed7e5148f147e3a126a0abbd33e4 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 28 Jun 2022 09:29:55 +0100 Subject: [PATCH 027/816] enable shallow clone support in tests when necessary --- tests/grafts/basic.c | 1 + tests/grafts/shallow.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/grafts/basic.c b/tests/grafts/basic.c index f91397002d0..3d3c65aeb8b 100644 --- a/tests/grafts/basic.c +++ b/tests/grafts/basic.c @@ -7,6 +7,7 @@ static git_repository *g_repo; void test_grafts_basic__initialize(void) { + git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1); g_repo = cl_git_sandbox_init("grafted.git"); } diff --git a/tests/grafts/shallow.c b/tests/grafts/shallow.c index ac1d686af8f..339235860f2 100644 --- a/tests/grafts/shallow.c +++ b/tests/grafts/shallow.c @@ -19,6 +19,7 @@ void test_grafts_shallow__unset_feature_flag(void) void test_grafts_shallow__initialize(void) { + git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1); cl_git_pass(git_oid_fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); } From 9d1507d1d36d640669d82f80d2b0151e11dbab2f Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 28 Jun 2022 09:35:51 +0100 Subject: [PATCH 028/816] correct use of feature flag --- src/commit.c | 36 +++++++++++++++++------------------- src/repository.c | 3 ++- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/commit.c b/src/commit.c index ab68634815f..a4899ed57cb 100644 --- a/src/commit.c +++ b/src/commit.c @@ -502,31 +502,29 @@ int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned { int error; - if ((error = commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags)) < 0) return error; - if (GIT_OPT_ENABLE_SHALLOW) { - - git_repository *repo = git_object_owner((git_object *)commit); - git_commit_graft *graft; - - /* Perform necessary grafts */ - if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) == 0 || - git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) == 0) { - size_t idx; - git_oid *oid; - git_array_clear(commit->parent_ids); - git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); - git_array_foreach(graft->parents, idx, oid) { - git_oid *id = git_array_alloc(commit->parent_ids); - GIT_ERROR_CHECK_ALLOC(id); + if (!git_shallow__enabled) + return 0; - git_oid_cpy(id, oid); - } + git_repository *repo = git_object_owner((git_object *)commit); + git_commit_graft *graft; + + /* Perform necessary grafts */ + if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) == 0 || + git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) == 0) { + size_t idx; + git_oid *oid; + git_array_clear(commit->parent_ids); + git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); + git_array_foreach(graft->parents, idx, oid) { + git_oid *id = git_array_alloc(commit->parent_ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, oid); } - } return 0; diff --git a/src/repository.c b/src/repository.c index f9b34445c1f..87874feceb2 100644 --- a/src/repository.c +++ b/src/repository.c @@ -14,6 +14,7 @@ #include "common.h" #include "commit.h" +#include "grafts.h" #include "tag.h" #include "blob.h" #include "futils.h" @@ -926,7 +927,7 @@ int git_repository_open_ext( if ((error = check_extensions(config, version)) < 0) goto cleanup; - if (GIT_OPT_ENABLE_SHALLOW && (error = load_grafts(repo)) < 0) + if (git_shallow__enabled && (error = load_grafts(repo)) < 0) goto cleanup; if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) From 06eacb91679f4d7c828c64c71081500219926f22 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 28 Jun 2022 11:23:59 +0100 Subject: [PATCH 029/816] fix graft assertion --- src/repository.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repository.c b/src/repository.c index 87874feceb2..ab575379580 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1315,7 +1315,7 @@ int git_repository_set_index(git_repository *repo, git_index *index) int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo) { - assert(out && repo && repo->shallow_grafts); + assert(out && repo && repo->grafts); *out = repo->grafts; return 0; } From 70a332a51b6364507d19bd1821b22fabbd1f2e08 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 28 Jun 2022 11:57:50 +0100 Subject: [PATCH 030/816] disable shallow clone feature flag in test cleanup --- tests/grafts/basic.c | 1 + tests/grafts/shallow.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/grafts/basic.c b/tests/grafts/basic.c index 3d3c65aeb8b..4be4a12bfc2 100644 --- a/tests/grafts/basic.c +++ b/tests/grafts/basic.c @@ -13,6 +13,7 @@ void test_grafts_basic__initialize(void) void test_grafts_basic__cleanup(void) { + git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); cl_git_sandbox_cleanup(); } diff --git a/tests/grafts/shallow.c b/tests/grafts/shallow.c index 339235860f2..a75b5a0519b 100644 --- a/tests/grafts/shallow.c +++ b/tests/grafts/shallow.c @@ -25,6 +25,7 @@ void test_grafts_shallow__initialize(void) void test_grafts_shallow__cleanup(void) { + git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); cl_git_sandbox_cleanup(); } From b29b9e8e29b4d96e8c1e3de1e902d56fab3e5320 Mon Sep 17 00:00:00 2001 From: nathannaveen <42319948+nathannaveen@users.noreply.github.com> Date: Sun, 3 Jul 2022 00:58:19 +0000 Subject: [PATCH 031/816] chore: Set permissions for GitHub actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much. - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> --- .github/workflows/benchmark.yml | 3 +++ .github/workflows/codeql.yml | 7 +++++++ .github/workflows/nightly.yml | 3 +++ 3 files changed, 13 insertions(+) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 7ae14ca7e76..f7fcea1fbc9 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -6,6 +6,9 @@ on: schedule: - cron: '15 4 * * *' +permissions: + contents: read + jobs: # Run our nightly builds. We build a matrix with the various build # targets and their details. Then we build either in a docker container diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index de1ec5e33e3..de6fbc22ecc 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -8,8 +8,15 @@ on: env: docker-registry: ghcr.io +permissions: + contents: read + jobs: analyze: + permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/analyze to upload SARIF results name: Analyze runs-on: ubuntu-latest diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5f80ed010b8..74001a4ea31 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -10,6 +10,9 @@ env: docker-registry: ghcr.io docker-config-path: source/ci/docker +permissions: + contents: read + jobs: # Run our nightly builds. We build a matrix with the various build # targets and their details. Then we build either in a docker container From afa79ca05862c24baa0360324ab7b63c0df90689 Mon Sep 17 00:00:00 2001 From: yuangli Date: Mon, 4 Jul 2022 17:08:04 +0100 Subject: [PATCH 032/816] Merge branch 'pr/tiennou/4747' into transportPR --- include/git2/remote.h | 7 +- include/git2/repository.h | 11 +++ include/git2/sys/transport.h | 17 ++++- src/array.h | 4 +- src/fetch.c | 22 +++++- src/object.c | 21 +++++- src/object.h | 6 ++ src/remote.h | 1 + src/repository.c | 89 +++++++++++++++++++++++ src/repository.h | 3 + src/transports/local.c | 6 +- src/transports/smart.c | 28 +++++++ src/transports/smart.h | 21 +++++- src/transports/smart_pkt.c | 90 +++++++++++++++++++++-- src/transports/smart_protocol.c | 63 +++++++++++++++- tests/clone/shallow.c | 55 ++++++++++++++ tests/repo/grafts.c | 119 ++++++++++++++++++++++++++++++ tests/repo/shallow.c | 125 ++++++++++++++++++++++++++++++++ 18 files changed, 659 insertions(+), 29 deletions(-) create mode 100644 tests/clone/shallow.c create mode 100644 tests/repo/grafts.c create mode 100644 tests/repo/shallow.c diff --git a/include/git2/remote.h b/include/git2/remote.h index 4d57eaaf74f..e577f8a7bde 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -738,11 +738,16 @@ typedef struct { * Extra headers for this fetch operation */ git_strarray custom_headers; + + /** + * Depth of the fetch to perform + */ + int depth; } git_fetch_options; #define GIT_FETCH_OPTIONS_VERSION 1 #define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ - GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT } + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, { NULL }, -1 } /** * Initialize git_fetch_options structure diff --git a/include/git2/repository.h b/include/git2/repository.h index ec8adfb293b..bbf3ae4cd85 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -920,6 +920,17 @@ GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); */ GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); +/** + * Determine the shallow roots of the repository + * + * This oidarray is owned by the library. Do not free it. + * + * @param out An array of shallow oids. + * @param repo The repository + * @return 0 on success, an error otherwise. + */ +GIT_EXTERN(int) git_repository_shallow_roots(git_oidarray *out, git_repository *repo); + /** * Retrieve the configured identity to use for reflogs * diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index fee34544fa9..ea8bcb64b07 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -33,6 +33,15 @@ typedef enum { GIT_TRANSPORTFLAGS_NONE = 0, } git_transport_flags_t; +typedef struct git_shallowarray git_shallowarray; + +typedef struct { + const git_remote_head * const *refs; + size_t count; + git_shallowarray *shallow_roots; + int depth; +} git_fetch_negotiation; + struct git_transport { unsigned int version; /**< The struct version */ @@ -87,8 +96,7 @@ struct git_transport { int GIT_CALLBACK(negotiate_fetch)( git_transport *transport, git_repository *repo, - const git_remote_head * const *refs, - size_t count); + const git_fetch_negotiation *fetch_data); /** * Start downloading the packfile from the remote repository. @@ -435,6 +443,11 @@ GIT_EXTERN(int) git_smart_subtransport_ssh( git_transport *owner, void *param); +GIT_EXTERN(size_t) git_shallowarray_count(git_shallowarray *array); +GIT_EXTERN(const git_oid *) git_shallowarray_get(git_shallowarray *array, size_t idx); +GIT_EXTERN(int) git_shallowarray_add(git_shallowarray *array, git_oid *oid); +GIT_EXTERN(int) git_shallowarray_remove(git_shallowarray *array, git_oid *oid); + /** @} */ GIT_END_DECL #endif diff --git a/src/array.h b/src/array.h index e97688b365f..3d6c9113ce4 100644 --- a/src/array.h +++ b/src/array.h @@ -85,12 +85,14 @@ GIT_INLINE(int) git_array_grow(void *_a, size_t item_size) #define git_array_foreach(a, i, element) \ for ((i) = 0; (i) < (a).size && ((element) = &(a).ptr[(i)]); (i)++) +typedef int (*git_array_compare_cb)(const void *, const void *); + GIT_INLINE(int) git_array__search( size_t *out, void *array_ptr, size_t item_size, size_t array_len, - int (*compare)(const void *, const void *), + git_array_compare_cb compare, const void *key) { size_t lim; diff --git a/src/fetch.c b/src/fetch.c index dedbb54fa54..e08671db357 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -18,6 +18,7 @@ #include "netops.h" #include "repository.h" #include "refs.h" +#include "transports/smart.h" static int maybe_want(git_remote *remote, git_remote_head *head, git_odb *odb, git_refspec *tagspec, git_remote_autotag_option_t tagopt) { @@ -128,10 +129,18 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) * Now we have everything set up so we can start tell the * server what we want and what we have. */ + remote->nego.refs = (const git_remote_head * const *)remote->refs.contents; + remote->nego.count = remote->refs.length; + remote->nego.depth = opts->depth; + remote->nego.shallow_roots = git__malloc(sizeof(git_shallowarray)); + + git_array_init(remote->nego.shallow_roots->array); + + git_repository__shallow_roots(&remote->nego.shallow_roots->array, remote->repo); + return t->negotiate_fetch(t, remote->repo, - (const git_remote_head * const *)remote->refs.contents, - remote->refs.length); + &remote->nego); } int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *callbacks) @@ -139,6 +148,7 @@ int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *call git_transport *t = remote->transport; git_indexer_progress_cb progress = NULL; void *payload = NULL; + int error; if (!remote->need_pack) return 0; @@ -148,7 +158,13 @@ int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *call payload = callbacks->payload; } - return t->download_pack(t, remote->repo, &remote->stats, progress, payload); + if ((error = t->download_pack(t, remote->repo, &remote->stats, progress, payload)) < 0) + return error; + + if ((error = git_repository__shallow_roots_write(remote->repo, remote->nego.shallow_roots->array)) < 0) + return error; + + return 0; } int git_fetch_options_init(git_fetch_options *opts, unsigned int version) diff --git a/src/object.c b/src/object.c index 42e1e46bcc5..b58f01a34e9 100644 --- a/src/object.c +++ b/src/object.c @@ -104,15 +104,13 @@ int git_object__from_raw( return 0; } -int git_object__from_odb_object( +int git_object__init_from_odb_object( git_object **object_out, git_repository *repo, git_odb_object *odb_obj, git_object_t type) { - int error; size_t object_size; - git_object_def *def; git_object *object = NULL; GIT_ASSERT_ARG(object_out); @@ -139,6 +137,23 @@ int git_object__from_odb_object( object->cached.size = odb_obj->cached.size; object->repo = repo; + *object_out = object; + return 0; +} + +int git_object__from_odb_object( + git_object **object_out, + git_repository *repo, + git_odb_object *odb_obj, + git_object_t type) +{ + int error; + git_object_def *def; + git_object *object = NULL; + + if ((error = git_object__init_from_odb_object(&object, repo, odb_obj, type)) < 0) + return error; + /* Parse raw object data */ def = &git_objects_table[odb_obj->cached.type]; GIT_ASSERT(def->free && def->parse); diff --git a/src/object.h b/src/object.h index 4b67936127e..71a966a92c2 100644 --- a/src/object.h +++ b/src/object.h @@ -35,6 +35,12 @@ int git_object__from_raw( size_t size, git_object_t type); +int git_object__init_from_odb_object( + git_object **object_out, + git_repository *repo, + git_odb_object *odb_obj, + git_object_t type); + int git_object__from_odb_object( git_object **object_out, git_repository *repo, diff --git a/src/remote.h b/src/remote.h index ce92db76aa5..8297af197f6 100644 --- a/src/remote.h +++ b/src/remote.h @@ -35,6 +35,7 @@ struct git_remote { git_remote_autotag_option_t download_tags; int prune_refs; int passed_refspecs; + git_fetch_negotiation nego; }; typedef struct git_remote_connection_opts { diff --git a/src/repository.c b/src/repository.c index ab575379580..537622273fd 100644 --- a/src/repository.c +++ b/src/repository.c @@ -3192,6 +3192,95 @@ int git_repository_state_cleanup(git_repository *repo) return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); } +int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) +{ + git_buf path = GIT_BUF_INIT; + git_buf contents = GIT_BUF_INIT; + int error, updated, line_num = 1; + char *line; + char *buffer; + + assert(out && repo); + + if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) + return error; + + error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_checksum, &updated); + git_buf_dispose(&path); + + if (error < 0 && error != GIT_ENOTFOUND) + return error; + + /* cancel out GIT_ENOTFOUND */ + git_error_clear(); + error = 0; + + if (!updated) { + *out = repo->shallow_oids; + goto cleanup; + } + + git_array_clear(repo->shallow_oids); + + buffer = contents.ptr; + while ((line = git__strsep(&buffer, "\n")) != NULL) { + git_oid *oid = git_array_alloc(repo->shallow_oids); + + error = git_oid_fromstr(oid, line); + if (error < 0) { + git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); + git_array_clear(repo->shallow_oids); + error = -1; + goto cleanup; + } + ++line_num; + } + + if (*buffer) { + git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); + git_array_clear(repo->shallow_oids); + error = -1; + goto cleanup; + } + + *out = repo->shallow_oids; + +cleanup: + git_buf_dispose(&contents); + + return error; +} + +int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_buf path = GIT_BUF_INIT; + int error = 0; + size_t idx; + git_oid *oid; + + assert(repo); + + if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) + return error; + + if ((error = git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) + return error; + + git_array_foreach(roots, idx, oid) { + git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); + git_filebuf_write(&file, "\n", 1); + } + + git_filebuf_commit(&file); + + /* WIP: reload shallow */ + if (load_shallow(repo) < 0) + return -1; + + return 0; +} + int git_repository_is_shallow(git_repository *repo) { git_buf path = GIT_BUF_INIT; diff --git a/src/repository.h b/src/repository.h index 8da65652d16..4b6004bea44 100644 --- a/src/repository.h +++ b/src/repository.h @@ -242,6 +242,9 @@ extern size_t git_repository__reserved_names_posix_len; bool git_repository__reserved_names( git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs); +int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo); +int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots); + /* * The default branch for the repository; the `init.defaultBranch` * configuration option, if set, or `master` if it is not. diff --git a/src/transports/local.c b/src/transports/local.c index bb31b134580..17905d2223c 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -268,15 +268,13 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t static int local_negotiate_fetch( git_transport *transport, git_repository *repo, - const git_remote_head * const *refs, - size_t count) + const git_fetch_negotiation *wants) { transport_local *t = (transport_local*)transport; git_remote_head *rhead; unsigned int i; - GIT_UNUSED(refs); - GIT_UNUSED(count); + GIT_UNUSED(wants); /* Fill in the loids */ git_vector_foreach(&t->refs, i, rhead) { diff --git a/src/transports/smart.c b/src/transports/smart.c index 587f1435889..a26bf79ecf3 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -558,3 +558,31 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) *out = (git_transport *) t; return 0; } + +size_t git_shallowarray_count(git_shallowarray *array) +{ + return git_array_size(array->array); +} + +const git_oid * git_shallowarray_get(git_shallowarray *array, size_t idx) +{ + return git_array_get(array->array, idx); +} + +int git_shallowarray_add(git_shallowarray *array, git_oid *oid) +{ + size_t oid_index; + if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, &oid) < 0) { + git_oid *tmp = git_array_alloc(array->array); + git_oid_cpy(tmp, oid); + } + return 0; +} + +int git_shallowarray_remove(git_shallowarray *array, git_oid *oid) +{ + GIT_UNUSED(array); + GIT_UNUSED(oid); + /* no git_array_remove… meh */ + return -1; +} diff --git a/src/transports/smart.h b/src/transports/smart.h index a05d4c9e3a2..6e49237ea6f 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -14,6 +14,7 @@ #include "netops.h" #include "buffer.h" #include "push.h" +#include "oidarray.h" #include "git2/sys/transport.h" #define GIT_SIDE_BAND_DATA 1 @@ -30,6 +31,7 @@ #define GIT_CAP_REPORT_STATUS "report-status" #define GIT_CAP_THIN_PACK "thin-pack" #define GIT_CAP_SYMREF "symref" +#define GIT_CAP_SHALLOW "shallow" extern bool git_smart__ofs_delta_enabled; @@ -47,6 +49,8 @@ typedef enum { GIT_PKT_OK, GIT_PKT_NG, GIT_PKT_UNPACK, + GIT_PKT_SHALLOW, + GIT_PKT_UNSHALLOW, } git_pkt_type; /* Used for multi_ack and multi_ack_detailed */ @@ -118,6 +122,11 @@ typedef struct { int unpack_ok; } git_pkt_unpack; +typedef struct { + git_pkt_type type; + git_oid oid; +} git_pkt_shallow; + typedef struct transport_smart_caps { int common:1, ofs_delta:1, @@ -128,7 +137,8 @@ typedef struct transport_smart_caps { include_tag:1, delete_refs:1, report_status:1, - thin_pack:1; + thin_pack:1, + shallow:1; } transport_smart_caps; typedef int (*packetsize_cb)(size_t received, void *payload); @@ -171,8 +181,7 @@ int git_smart__push(git_transport *transport, git_push *push, const git_remote_c int git_smart__negotiate_fetch( git_transport *transport, git_repository *repo, - const git_remote_head * const *refs, - size_t count); + const git_fetch_negotiation *wants); int git_smart__download_pack( git_transport *transport, @@ -192,8 +201,12 @@ int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, si int git_pkt_buffer_flush(git_buf *buf); int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_buffer_done(git_buf *buf); -int git_pkt_buffer_wants(const git_remote_head * const *refs, size_t count, transport_smart_caps *caps, git_buf *buf); +int git_pkt_buffer_wants(const git_fetch_negotiation *wants, transport_smart_caps *caps, git_buf *buf); int git_pkt_buffer_have(git_oid *oid, git_buf *buf); void git_pkt_free(git_pkt *pkt); +struct git_shallowarray { + git_array_oid_t array; +}; + #endif diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index 56b680d281e..6a1e842eeb9 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -363,6 +363,50 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len) return 0; } +static int shallow_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_shallow *pkt; + + pkt = git__calloc(1, sizeof(git_pkt_shallow)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_SHALLOW; + line += 7; + len -= 7; + + if (len >= GIT_OID_HEXSZ) { + git_oid_fromstr(&pkt->oid, line + 1); + line += GIT_OID_HEXSZ + 1; + len -= GIT_OID_HEXSZ + 1; + } + + *out = (git_pkt *) pkt; + + return 0; +} + +static int unshallow_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_shallow *pkt; + + pkt = git__calloc(1, sizeof(git_pkt_shallow)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_UNSHALLOW; + line += 9; + len -= 9; + + if (len >= GIT_OID_HEXSZ) { + git_oid_fromstr(&pkt->oid, line + 1); + line += GIT_OID_HEXSZ + 1; + len -= GIT_OID_HEXSZ + 1; + } + + *out = (git_pkt *) pkt; + + return 0; +} + static int parse_len(size_t *out, const char *line, size_t linelen) { char num[PKT_LEN_SIZE + 1]; @@ -489,6 +533,10 @@ int git_pkt_parse_line( error = ng_pkt(pkt, line, len); else if (!git__prefixncmp(line, len, "unpack")) error = unpack_pkt(pkt, line, len); + else if (!git__prefixcmp(line, "shallow")) + error = shallow_pkt(pkt, line, len); + else if (!git__prefixcmp(line, "unshallow")) + error = unshallow_pkt(pkt, line, len); else error = ref_pkt(pkt, line, len); @@ -554,6 +602,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca if (caps->ofs_delta) git_buf_puts(&str, GIT_CAP_OFS_DELTA " "); + if (caps->shallow) + git_buf_puts(&str, GIT_CAP_SHALLOW " "); + if (git_buf_oom(&str)) return -1; @@ -583,8 +634,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca */ int git_pkt_buffer_wants( - const git_remote_head * const *refs, - size_t count, + const git_fetch_negotiation *wants, transport_smart_caps *caps, git_buf *buf) { @@ -592,22 +642,22 @@ int git_pkt_buffer_wants( const git_remote_head *head; if (caps->common) { - for (; i < count; ++i) { - head = refs[i]; + for (; i < wants->count; ++i) { + head = wants->refs[i]; if (!head->local) break; } - if (buffer_want_with_caps(refs[i], caps, buf) < 0) + if (buffer_want_with_caps(wants->refs[i], caps, buf) < 0) return -1; i++; } - for (; i < count; ++i) { + for (; i < wants->count; ++i) { char oid[GIT_OID_HEXSZ]; - head = refs[i]; + head = wants->refs[i]; if (head->local) continue; @@ -619,6 +669,32 @@ int git_pkt_buffer_wants( return -1; } + /* Tell the server about our shallow objects */ + for (i = 0; i < git_shallowarray_count(wants->shallow_roots); i++) { + char oid[GIT_OID_HEXSZ]; + git_buf shallow_buf = GIT_BUF_INIT; + + git_oid_fmt(oid, git_shallowarray_get(wants->shallow_roots, i)); + git_buf_puts(&shallow_buf, "shallow "); + git_buf_put(&shallow_buf, oid, GIT_OID_HEXSZ); + git_buf_putc(&shallow_buf, '\n'); + + git_buf_printf(buf, "%04x%s", (unsigned int)git_buf_len(&shallow_buf) + 4, git_buf_cstr(&shallow_buf)); + + if (git_buf_oom(buf)) + return -1; + } + + if (wants->depth > 0) { + git_buf deepen_buf = GIT_BUF_INIT; + + git_buf_printf(&deepen_buf, "deepen %d\n", wants->depth); + git_buf_printf(buf,"%04x%s", (unsigned int)git_buf_len(&deepen_buf) + 4, git_buf_cstr(&deepen_buf)); + + if (git_buf_oom(buf)) + return -1; + } + return git_pkt_buffer_flush(buf); } diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 91de163e91f..df19311914a 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -205,6 +205,12 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec continue; } + if (!git__prefixcmp(ptr, GIT_CAP_SHALLOW)) { + caps->common = caps->shallow = 1; + ptr += strlen(GIT_CAP_SHALLOW); + continue; + } + /* We don't know this capability, so skip it */ ptr = strchr(ptr, ' '); } @@ -305,7 +311,26 @@ static int wait_while_ack(gitno_buffer *buf) return 0; } -int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *wants, size_t count) +static int cap_not_sup_err(const char *cap_name) +{ + git_error_set(GIT_ERROR_NET, "server doesn't support %s", cap_name); + return GIT_EINVALID; +} + +/* Disables server capabilities we're not interested in */ +static int setup_caps(transport_smart_caps *caps, const git_fetch_negotiation *wants) +{ + if (wants->depth) { + if (!caps->shallow) + return cap_not_sup_err(GIT_CAP_SHALLOW); + } else { + caps->shallow = 0; + } + + return 0; +} + +int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_fetch_negotiation *wants) { transport_smart *t = (transport_smart *)transport; git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT; @@ -317,7 +342,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c unsigned int i; git_oid oid; - if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) + if ((error = setup_caps(&t->caps, wants)) < 0) + return error; + + if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0) return error; if ((error = git_revwalk_new(&walk, repo)) < 0) @@ -327,6 +355,33 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0) goto on_error; + if (wants->depth > 0) { + git_pkt_shallow *pkt; + + if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) + goto on_error; + + while ((error = recv_pkt((git_pkt **)&pkt, NULL, buf)) == 0) { + + if (pkt->type == GIT_PKT_SHALLOW) { + printf("shallow %s\n", git_oid_tostr_s(&pkt->oid)); + git_shallowarray_add(wants->shallow_roots, &pkt->oid); + } else if (pkt->type == GIT_PKT_UNSHALLOW) { + printf("unshallow %s\n", git_oid_tostr_s(&pkt->oid)); + git_shallowarray_remove(wants->shallow_roots, &pkt->oid); + } else if (pkt->type == GIT_PKT_FLUSH) { + /* Server is done, stop processing shallow oids */ + break; + } else { + git_error_set(GIT_ERROR_NET, "Unexpected pkt type"); + goto on_error; + } + } + + if (error < 0) { + goto on_error; + } + } /* * Our support for ACK extensions is simply to parse them. On * the first ACK we will accept that as enough common @@ -389,7 +444,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c git_pkt_ack *pkt; unsigned int j; - if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) + if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, j, pkt) { @@ -409,7 +464,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c git_pkt_ack *pkt; unsigned int j; - if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) + if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, j, pkt) { diff --git a/tests/clone/shallow.c b/tests/clone/shallow.c new file mode 100644 index 00000000000..d0527206597 --- /dev/null +++ b/tests/clone/shallow.c @@ -0,0 +1,55 @@ +#include "clar_libgit2.h" +#include "futils.h" + +void test_clone_shallow__initialize(void) +{ + +} + +void test_clone_shallow__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + + +#define CLONE_DEPTH 5 + +void test_clone_shallow__clone_depth(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + git_revwalk *walk; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_oid oid; + git_oidarray roots; + size_t depth = 0; + int error = 0; + + clone_opts.fetch_opts.depth = CLONE_DEPTH; + + git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone"); + + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_buf_cstr(&path), &clone_opts)); + + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + cl_git_pass(git_repository_shallow_roots(&roots, repo)); + cl_assert_equal_i(1, roots.count); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ids[0])); + + git_revwalk_new(&walk, repo); + + git_revwalk_push_head(walk); + + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + if (depth + 1 > CLONE_DEPTH) + cl_fail("expected depth mismatch"); + depth++; + } + + cl_git_pass(error); + + git_buf_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +} diff --git a/tests/repo/grafts.c b/tests/repo/grafts.c new file mode 100644 index 00000000000..82bd0ad7a21 --- /dev/null +++ b/tests/repo/grafts.c @@ -0,0 +1,119 @@ +#include "clar_libgit2.h" +#include "futils.h" +#include "grafts.h" + +static git_repository *g_repo; + +void test_repo_grafts__initialize(void) +{ + g_repo = cl_git_sandbox_init("grafted.git"); +} + +void test_repo_grafts__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_repo_grafts__graft_register(void) +{ + git_oid oid_src; + git_commit_graft *graft; + git_graftmap *grafts = git_oidmap_alloc(); + git_array_oid_t parents = GIT_ARRAY_INIT; + + git_oid *oid1 = git_array_alloc(parents); + cl_git_pass(git_oid_fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9")); + git_oid_cpy(oid1, &oid_src); + + git_oid_fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7"); + cl_git_pass(git__graft_register(grafts, &oid_src, parents)); + git_array_clear(parents); + + cl_assert_equal_i(1, git_oidmap_size(grafts)); + cl_git_pass(git__graft_for_oid(&graft, grafts, &oid_src)); + cl_assert_equal_s("f503807ffa920e407a600cfaee96b7152259acc7", git_oid_tostr_s(&graft->oid)); + cl_assert_equal_i(1, git_array_size(graft->parents)); + cl_assert_equal_s("2f3053cbff8a4ca2f0666de364ddb734a28a31a9", git_oid_tostr_s(git_array_get(graft->parents, 0))); + + git__graft_clear(grafts); + git_oidmap_free(grafts); +} + +void test_repo_grafts__grafted_revwalk(void) +{ + git_revwalk *w; + git_oid oids[10]; + size_t i = 0; + git_commit *commit; + + cl_git_pass(git_revwalk_new(&w, g_repo)); + cl_git_pass(git_revwalk_push_ref(w, "refs/heads/branch")); + + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[0]), "8a00e91619098618be97c0d2ceabb05a2c58edd9"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[1]), "f503807ffa920e407a600cfaee96b7152259acc7"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[2]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9"); + + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w)); + + cl_git_pass(git_commit_lookup(&commit, g_repo, &oids[0])); + + cl_assert_equal_i(1, git_commit_parentcount(commit)); + + git_commit_free(commit); + git_revwalk_free(w); +} + +void test_repo_grafts__grafted_objects(void) +{ + git_oid oid; + git_commit *commit; + + cl_git_pass(git_oid_fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7")); + cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); + cl_assert_equal_i(1, git_commit_parentcount(commit)); + git_commit_free(commit); + + cl_git_pass(git_oid_fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e")); + cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); + cl_assert_equal_i(1, git_commit_parentcount(commit)); + git_commit_free(commit); + + cl_git_pass(git_oid_fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade")); + cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); + cl_assert_equal_i(4, git_commit_parentcount(commit)); + git_commit_free(commit); +} + +void test_repo_grafts__grafted_merge_revwalk(void) +{ + git_revwalk *w; + git_oid oids[10]; + size_t i = 0; + + cl_git_pass(git_revwalk_new(&w, g_repo)); + cl_git_pass(git_revwalk_push_ref(w, "refs/heads/bottom")); + + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "66cc22a015f6ca75b34c82d28f78ba663876bade"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "e414f42f4e6bc6934563a2349a8600f0ab68618e"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "8a00e91619098618be97c0d2ceabb05a2c58edd9"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "1c18e80a276611bb9b146590616bbc5aebdf2945"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "d7224d49d6d5aff6ade596ed74f4bcd4f77b29e2"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "0512adebd3782157f0d5c9b22b043f87b4aaff9e"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "f503807ffa920e407a600cfaee96b7152259acc7"); + cl_git_pass(git_revwalk_next(&oids[i++], w)); + cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9"); + + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w)); + + git_revwalk_free(w); +} diff --git a/tests/repo/shallow.c b/tests/repo/shallow.c new file mode 100644 index 00000000000..a73dfc013b3 --- /dev/null +++ b/tests/repo/shallow.c @@ -0,0 +1,125 @@ +#include "clar_libgit2.h" +#include "futils.h" + +static git_repository *g_repo; +static git_oid g_shallow_oid; + +void test_repo_shallow__initialize(void) +{ + cl_git_pass(git_oid_fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); +} + +void test_repo_shallow__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_repo_shallow__no_shallow_file(void) +{ + g_repo = cl_git_sandbox_init("testrepo.git"); + cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); +} + +void test_repo_shallow__empty_shallow_file(void) +{ + g_repo = cl_git_sandbox_init("testrepo.git"); + cl_git_mkfile("testrepo.git/shallow", ""); + cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); +} + +void test_repo_shallow__shallow_repo(void) +{ + g_repo = cl_git_sandbox_init("shallow.git"); + cl_assert_equal_i(1, git_repository_is_shallow(g_repo)); +} + +void test_repo_shallow__clears_errors(void) +{ + g_repo = cl_git_sandbox_init("testrepo.git"); + cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); + cl_assert_equal_p(NULL, git_error_last()); +} + +void test_repo_shallow__shallow_oids(void) +{ + git_oidarray oids, oids2; + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); + cl_assert_equal_i(1, oids.count); + cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); + + cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); + cl_assert_equal_p(oids.ids, oids2.ids); +} + +void test_repo_shallow__cache_clearing(void) +{ + git_oidarray oids, oids2; + git_oid tmp_oid; + + git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000"); + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); + cl_assert_equal_i(1, oids.count); + cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); + + cl_git_mkfile("shallow.git/shallow", + "be3563ae3f795b2b4353bcce3a527ad0a4f7f644\n" + "0000000000000000000000000000000000000000\n" + ); + + cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); + cl_assert_equal_i(2, oids2.count); + cl_assert_equal_oid(&g_shallow_oid, &oids2.ids[0]); + cl_assert_equal_oid(&tmp_oid, &oids2.ids[1]); +} + +void test_repo_shallow__errors_on_borked(void) +{ + git_oidarray oids; + + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_mkfile("shallow.git/shallow", "lolno"); + + cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); + + cl_git_mkfile("shallow.git/shallow", "lolno\n"); + + cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); +} + +void test_repo_shallow__revwalk_behavior(void) +{ + git_revwalk *w; + git_oid oid_1, oid_2, oid_3; + + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_revwalk_new(&w, g_repo)); + cl_git_pass(git_revwalk_push_head(w)); + + cl_git_pass(git_revwalk_next(&oid_1, w)); // a65fedf39aefe402d3bb6e24df4d4f5fe4547750 + cl_git_pass(git_revwalk_next(&oid_2, w)); // be3563ae3f795b2b4353bcce3a527ad0a4f7f644 + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid_3, w)); + + cl_assert_equal_s(git_oid_tostr_s(&oid_1), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + cl_assert_equal_s(git_oid_tostr_s(&oid_2), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + + git_revwalk_free(w); +} + +void test_repo_shallow__grafted_object(void) +{ + git_commit *commit; + + g_repo = cl_git_sandbox_init("shallow.git"); + + cl_git_pass(git_commit_lookup(&commit, g_repo, &g_shallow_oid)); + + cl_assert_equal_i(0, git_commit_parentcount(commit)); + + git_commit_free(commit); +} From 10e2573550b0753f4aa0728bb2bbacf57d2377d0 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 5 Jul 2022 09:22:31 +0100 Subject: [PATCH 033/816] attempt to build --- src/repository.c | 148 +++++++++++++++++++++--------------------- tests/clone/shallow.c | 3 +- tests/repo/grafts.c | 119 --------------------------------- tests/repo/shallow.c | 125 ----------------------------------- 4 files changed, 77 insertions(+), 318 deletions(-) delete mode 100644 tests/repo/grafts.c delete mode 100644 tests/repo/shallow.c diff --git a/src/repository.c b/src/repository.c index 537622273fd..bef719f4a2c 100644 --- a/src/repository.c +++ b/src/repository.c @@ -3194,89 +3194,91 @@ int git_repository_state_cleanup(git_repository *repo) int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { - git_buf path = GIT_BUF_INIT; - git_buf contents = GIT_BUF_INIT; - int error, updated, line_num = 1; - char *line; - char *buffer; - - assert(out && repo); - - if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) - return error; - - error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_checksum, &updated); - git_buf_dispose(&path); - - if (error < 0 && error != GIT_ENOTFOUND) - return error; - - /* cancel out GIT_ENOTFOUND */ - git_error_clear(); - error = 0; - - if (!updated) { - *out = repo->shallow_oids; - goto cleanup; - } - - git_array_clear(repo->shallow_oids); - - buffer = contents.ptr; - while ((line = git__strsep(&buffer, "\n")) != NULL) { - git_oid *oid = git_array_alloc(repo->shallow_oids); - - error = git_oid_fromstr(oid, line); - if (error < 0) { - git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); - git_array_clear(repo->shallow_oids); - error = -1; - goto cleanup; - } - ++line_num; - } - - if (*buffer) { - git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); - git_array_clear(repo->shallow_oids); - error = -1; - goto cleanup; - } - - *out = repo->shallow_oids; - -cleanup: - git_buf_dispose(&contents); - - return error; +// git_buf path = GIT_BUF_INIT; +// git_buf contents = GIT_BUF_INIT; +// int error, updated, line_num = 1; +// char *line; +// char *buffer; + +// assert(out && repo); + +// if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) +// return error; + +// //error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_checksum, &updated); +// error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_grafts->git_grafts->path_checksum, &updated); +// git_buf_dispose(&path); + +// if (error < 0 && error != GIT_ENOTFOUND) +// return error; + +// /* cancel out GIT_ENOTFOUND */ +// git_error_clear(); +// error = 0; + +// if (!updated) { +// out = repo->shallow_grafts; +// goto cleanup; +// } + +// git_array_clear(repo->shallow_grafts); + +// buffer = contents.ptr; +// while ((line = git__strsep(&buffer, "\n")) != NULL) { +// git_oid *oid = git_array_alloc(repo->shallow_grafts); + +// error = git_oid_fromstr(oid, line); +// if (error < 0) { +// git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); +// git_array_clear(repo->shallow_grafts); +// error = -1; +// goto cleanup; +// } +// ++line_num; +// } + +// if (*buffer) { +// git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); +// git_array_clear(repo->shallow_grafts); +// error = -1; +// goto cleanup; +// } + +// *out = repo->shallow_grafts; + +// cleanup: +// git_buf_dispose(&contents); + + // return error; + return 0; } int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots) { - git_filebuf file = GIT_FILEBUF_INIT; - git_buf path = GIT_BUF_INIT; - int error = 0; - size_t idx; - git_oid *oid; + // git_filebuf file = GIT_FILEBUF_INIT; + // git_buf path = GIT_BUF_INIT; + // int error = 0; + // size_t idx; + // git_oid *oid; - assert(repo); + // assert(repo); - if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) - return error; + // if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) + // return error; - if ((error = git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) - return error; + // if ((error = git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) + // return error; - git_array_foreach(roots, idx, oid) { - git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); - git_filebuf_write(&file, "\n", 1); - } + // git_array_foreach(roots, idx, oid) { + // git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); + // git_filebuf_write(&file, "\n", 1); + // } - git_filebuf_commit(&file); + // git_filebuf_commit(&file); - /* WIP: reload shallow */ - if (load_shallow(repo) < 0) - return -1; + // /* WIP: reload shallow */ + // if (load_shallow(repo) < 0) + // return -1; return 0; } diff --git a/tests/clone/shallow.c b/tests/clone/shallow.c index d0527206597..6bd98ab0a24 100644 --- a/tests/clone/shallow.c +++ b/tests/clone/shallow.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "futils.h" +#include "repository.h" void test_clone_shallow__initialize(void) { @@ -33,7 +34,7 @@ void test_clone_shallow__clone_depth(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); - cl_git_pass(git_repository_shallow_roots(&roots, repo)); + cl_git_pass(git_repository__shallow_roots(&roots, repo)); cl_assert_equal_i(1, roots.count); cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ids[0])); diff --git a/tests/repo/grafts.c b/tests/repo/grafts.c deleted file mode 100644 index 82bd0ad7a21..00000000000 --- a/tests/repo/grafts.c +++ /dev/null @@ -1,119 +0,0 @@ -#include "clar_libgit2.h" -#include "futils.h" -#include "grafts.h" - -static git_repository *g_repo; - -void test_repo_grafts__initialize(void) -{ - g_repo = cl_git_sandbox_init("grafted.git"); -} - -void test_repo_grafts__cleanup(void) -{ - cl_git_sandbox_cleanup(); -} - -void test_repo_grafts__graft_register(void) -{ - git_oid oid_src; - git_commit_graft *graft; - git_graftmap *grafts = git_oidmap_alloc(); - git_array_oid_t parents = GIT_ARRAY_INIT; - - git_oid *oid1 = git_array_alloc(parents); - cl_git_pass(git_oid_fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9")); - git_oid_cpy(oid1, &oid_src); - - git_oid_fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7"); - cl_git_pass(git__graft_register(grafts, &oid_src, parents)); - git_array_clear(parents); - - cl_assert_equal_i(1, git_oidmap_size(grafts)); - cl_git_pass(git__graft_for_oid(&graft, grafts, &oid_src)); - cl_assert_equal_s("f503807ffa920e407a600cfaee96b7152259acc7", git_oid_tostr_s(&graft->oid)); - cl_assert_equal_i(1, git_array_size(graft->parents)); - cl_assert_equal_s("2f3053cbff8a4ca2f0666de364ddb734a28a31a9", git_oid_tostr_s(git_array_get(graft->parents, 0))); - - git__graft_clear(grafts); - git_oidmap_free(grafts); -} - -void test_repo_grafts__grafted_revwalk(void) -{ - git_revwalk *w; - git_oid oids[10]; - size_t i = 0; - git_commit *commit; - - cl_git_pass(git_revwalk_new(&w, g_repo)); - cl_git_pass(git_revwalk_push_ref(w, "refs/heads/branch")); - - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[0]), "8a00e91619098618be97c0d2ceabb05a2c58edd9"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[1]), "f503807ffa920e407a600cfaee96b7152259acc7"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[2]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9"); - - cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w)); - - cl_git_pass(git_commit_lookup(&commit, g_repo, &oids[0])); - - cl_assert_equal_i(1, git_commit_parentcount(commit)); - - git_commit_free(commit); - git_revwalk_free(w); -} - -void test_repo_grafts__grafted_objects(void) -{ - git_oid oid; - git_commit *commit; - - cl_git_pass(git_oid_fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7")); - cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); - cl_assert_equal_i(1, git_commit_parentcount(commit)); - git_commit_free(commit); - - cl_git_pass(git_oid_fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e")); - cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); - cl_assert_equal_i(1, git_commit_parentcount(commit)); - git_commit_free(commit); - - cl_git_pass(git_oid_fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade")); - cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); - cl_assert_equal_i(4, git_commit_parentcount(commit)); - git_commit_free(commit); -} - -void test_repo_grafts__grafted_merge_revwalk(void) -{ - git_revwalk *w; - git_oid oids[10]; - size_t i = 0; - - cl_git_pass(git_revwalk_new(&w, g_repo)); - cl_git_pass(git_revwalk_push_ref(w, "refs/heads/bottom")); - - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "66cc22a015f6ca75b34c82d28f78ba663876bade"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "e414f42f4e6bc6934563a2349a8600f0ab68618e"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "8a00e91619098618be97c0d2ceabb05a2c58edd9"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "1c18e80a276611bb9b146590616bbc5aebdf2945"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "d7224d49d6d5aff6ade596ed74f4bcd4f77b29e2"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "0512adebd3782157f0d5c9b22b043f87b4aaff9e"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "f503807ffa920e407a600cfaee96b7152259acc7"); - cl_git_pass(git_revwalk_next(&oids[i++], w)); - cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9"); - - cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w)); - - git_revwalk_free(w); -} diff --git a/tests/repo/shallow.c b/tests/repo/shallow.c deleted file mode 100644 index a73dfc013b3..00000000000 --- a/tests/repo/shallow.c +++ /dev/null @@ -1,125 +0,0 @@ -#include "clar_libgit2.h" -#include "futils.h" - -static git_repository *g_repo; -static git_oid g_shallow_oid; - -void test_repo_shallow__initialize(void) -{ - cl_git_pass(git_oid_fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); -} - -void test_repo_shallow__cleanup(void) -{ - cl_git_sandbox_cleanup(); -} - -void test_repo_shallow__no_shallow_file(void) -{ - g_repo = cl_git_sandbox_init("testrepo.git"); - cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); -} - -void test_repo_shallow__empty_shallow_file(void) -{ - g_repo = cl_git_sandbox_init("testrepo.git"); - cl_git_mkfile("testrepo.git/shallow", ""); - cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); -} - -void test_repo_shallow__shallow_repo(void) -{ - g_repo = cl_git_sandbox_init("shallow.git"); - cl_assert_equal_i(1, git_repository_is_shallow(g_repo)); -} - -void test_repo_shallow__clears_errors(void) -{ - g_repo = cl_git_sandbox_init("testrepo.git"); - cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); - cl_assert_equal_p(NULL, git_error_last()); -} - -void test_repo_shallow__shallow_oids(void) -{ - git_oidarray oids, oids2; - g_repo = cl_git_sandbox_init("shallow.git"); - - cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); - cl_assert_equal_i(1, oids.count); - cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); - - cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); - cl_assert_equal_p(oids.ids, oids2.ids); -} - -void test_repo_shallow__cache_clearing(void) -{ - git_oidarray oids, oids2; - git_oid tmp_oid; - - git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000"); - g_repo = cl_git_sandbox_init("shallow.git"); - - cl_git_pass(git_repository_shallow_roots(&oids, g_repo)); - cl_assert_equal_i(1, oids.count); - cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]); - - cl_git_mkfile("shallow.git/shallow", - "be3563ae3f795b2b4353bcce3a527ad0a4f7f644\n" - "0000000000000000000000000000000000000000\n" - ); - - cl_git_pass(git_repository_shallow_roots(&oids2, g_repo)); - cl_assert_equal_i(2, oids2.count); - cl_assert_equal_oid(&g_shallow_oid, &oids2.ids[0]); - cl_assert_equal_oid(&tmp_oid, &oids2.ids[1]); -} - -void test_repo_shallow__errors_on_borked(void) -{ - git_oidarray oids; - - g_repo = cl_git_sandbox_init("shallow.git"); - - cl_git_mkfile("shallow.git/shallow", "lolno"); - - cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); - - cl_git_mkfile("shallow.git/shallow", "lolno\n"); - - cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo)); -} - -void test_repo_shallow__revwalk_behavior(void) -{ - git_revwalk *w; - git_oid oid_1, oid_2, oid_3; - - g_repo = cl_git_sandbox_init("shallow.git"); - - cl_git_pass(git_revwalk_new(&w, g_repo)); - cl_git_pass(git_revwalk_push_head(w)); - - cl_git_pass(git_revwalk_next(&oid_1, w)); // a65fedf39aefe402d3bb6e24df4d4f5fe4547750 - cl_git_pass(git_revwalk_next(&oid_2, w)); // be3563ae3f795b2b4353bcce3a527ad0a4f7f644 - cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid_3, w)); - - cl_assert_equal_s(git_oid_tostr_s(&oid_1), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - cl_assert_equal_s(git_oid_tostr_s(&oid_2), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - - git_revwalk_free(w); -} - -void test_repo_shallow__grafted_object(void) -{ - git_commit *commit; - - g_repo = cl_git_sandbox_init("shallow.git"); - - cl_git_pass(git_commit_lookup(&commit, g_repo, &g_shallow_oid)); - - cl_assert_equal_i(0, git_commit_parentcount(commit)); - - git_commit_free(commit); -} From 2546030d7ed8aea9f050b092e0954b7146978ecf Mon Sep 17 00:00:00 2001 From: Miguel Arroz <750683+arroz@users.noreply.github.com> Date: Wed, 6 Jul 2022 19:04:39 -0700 Subject: [PATCH 034/816] Fixes #6344: git_branch_move now renames the reflog instead of deleting. --- src/libgit2/refdb_fs.c | 21 ++++++++++++++++----- tests/libgit2/refs/branches/move.c | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 0f49b16bba0..8f7febbc8d7 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -1769,6 +1769,15 @@ static int refdb_fs_backend__rename( (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0) return error; + /* Try to rename the refog; it's ok if the old doesn't exist */ + /* Must be done before calling refdb_fs_backend__delete, otherwise */ + /* the reflog is deleted before being renamed. */ + error = refdb_reflog_fs__rename(_backend, old_name, new_name); + if ((error != 0) && (error != GIT_ENOTFOUND)) { + git_reference_free(old); + return error; + } + if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) { git_reference_free(old); return error; @@ -1785,10 +1794,7 @@ static int refdb_fs_backend__rename( return error; } - /* Try to rename the refog; it's ok if the old doesn't exist */ - error = refdb_reflog_fs__rename(_backend, old_name, new_name); - if (((error == 0) || (error == GIT_ENOTFOUND)) && - ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) { + if ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0) { git_reference_free(new); git_filebuf_cleanup(&file); return error; @@ -2368,7 +2374,12 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name if ((error = reflog_path(&path, backend->repo, name)) < 0) goto out; - if (!git_fs_path_exists(path.ptr)) + /* + * If a reference was moved downwards, eg refs/heads/br2 -> refs/heads/br2/new-name, + * refs/heads/br2 does exist but it's a directory. That's a valid situation. + * Proceed only if it's a file. + */ + if (!git_fs_path_isfile(path.ptr)) goto out; if ((error = p_unlink(path.ptr)) < 0) diff --git a/tests/libgit2/refs/branches/move.c b/tests/libgit2/refs/branches/move.c index 46a5082d2fd..f261b2bbba3 100644 --- a/tests/libgit2/refs/branches/move.c +++ b/tests/libgit2/refs/branches/move.c @@ -210,3 +210,25 @@ void test_refs_branches_move__can_move_with_unicode(void) git_reference_free(original_ref); git_reference_free(new_ref); } + +void test_refs_branches_move__moves_reflog_correctly(void) +{ + git_reference *original_ref, *new_ref; + git_reflog *original_reflog, *new_reflog; + + cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); + + cl_git_pass(git_reflog_read(&original_reflog, repo, "refs/heads/br2")); + cl_assert_equal_i(2, git_reflog_entrycount(original_reflog)); + + cl_git_pass(git_branch_move(&new_ref, original_ref, NEW_BRANCH_NAME, 0)); + cl_assert_equal_s(GIT_REFS_HEADS_DIR NEW_BRANCH_NAME, git_reference_name(new_ref)); + + cl_git_pass(git_reflog_read(&new_reflog, repo, GIT_REFS_HEADS_DIR NEW_BRANCH_NAME)); + cl_assert_equal_i(3, git_reflog_entrycount(new_reflog)); + + git_reference_free(original_ref); + git_reference_free(new_ref); + git_reflog_free(original_reflog); + git_reflog_free(new_reflog); +} From 3c79bafcf832a7bcfd1bdf6559f7ff85f6734d9f Mon Sep 17 00:00:00 2001 From: Miguel Arroz <750683+arroz@users.noreply.github.com> Date: Wed, 6 Jul 2022 19:21:13 -0700 Subject: [PATCH 035/816] Add reverting reflog move if an error happens. --- src/libgit2/refdb_fs.c | 3 +++ tests/libgit2/refs/branches/move.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 8f7febbc8d7..11daffdb098 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -1779,17 +1779,20 @@ static int refdb_fs_backend__rename( } if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) { + refdb_reflog_fs__rename(_backend, new_name, old_name); git_reference_free(old); return error; } new = git_reference__realloc(&old, new_name); if (!new) { + refdb_reflog_fs__rename(_backend, new_name, old_name); git_reference_free(old); return -1; } if ((error = loose_lock(&file, backend, new->name)) < 0) { + refdb_reflog_fs__rename(_backend, new_name, old_name); git_reference_free(new); return error; } diff --git a/tests/libgit2/refs/branches/move.c b/tests/libgit2/refs/branches/move.c index f261b2bbba3..4cfb7b83ae6 100644 --- a/tests/libgit2/refs/branches/move.c +++ b/tests/libgit2/refs/branches/move.c @@ -232,3 +232,19 @@ void test_refs_branches_move__moves_reflog_correctly(void) git_reflog_free(original_reflog); git_reflog_free(new_reflog); } + +void test_refs_branches_move__failed_move_restores_reflog(void) +{ + git_reference *original_ref, *new_ref; + git_reflog *recovered_reflog; + + cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); + + cl_assert_equal_i(GIT_EINVALIDSPEC, git_branch_move(&new_ref, original_ref, "Inv@{id", 0)); + + cl_git_pass(git_reflog_read(&recovered_reflog, repo, "refs/heads/br2")); + cl_assert_equal_i(2, git_reflog_entrycount(recovered_reflog)); + + git_reference_free(original_ref); + git_reflog_free(recovered_reflog); +} From 0365f4531f548da842b56be17fd6a6a253bc6763 Mon Sep 17 00:00:00 2001 From: Miguel Arroz <750683+arroz@users.noreply.github.com> Date: Wed, 6 Jul 2022 19:33:16 -0700 Subject: [PATCH 036/816] Codestyle (whitespaces) adjustment. --- src/libgit2/refdb_fs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 11daffdb098..8a7051dead6 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -2377,11 +2377,11 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name if ((error = reflog_path(&path, backend->repo, name)) < 0) goto out; - /* - * If a reference was moved downwards, eg refs/heads/br2 -> refs/heads/br2/new-name, - * refs/heads/br2 does exist but it's a directory. That's a valid situation. - * Proceed only if it's a file. - */ + /* + * If a reference was moved downwards, eg refs/heads/br2 -> refs/heads/br2/new-name, + * refs/heads/br2 does exist but it's a directory. That's a valid situation. + * Proceed only if it's a file. + */ if (!git_fs_path_isfile(path.ptr)) goto out; From 3e64f150ccfae3b7828a293fdd78daaf61e76ccf Mon Sep 17 00:00:00 2001 From: yuangli Date: Thu, 7 Jul 2022 09:26:18 +0100 Subject: [PATCH 037/816] rewrite shallow_root --- src/repository.c | 110 +++++++++++++++++++++++++++++++++--------- tests/clone/shallow.c | 10 ++-- 2 files changed, 94 insertions(+), 26 deletions(-) diff --git a/src/repository.c b/src/repository.c index bef719f4a2c..42ee263a3a4 100644 --- a/src/repository.c +++ b/src/repository.c @@ -3192,13 +3192,56 @@ int git_repository_state_cleanup(git_repository *repo) return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); } -int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) -{ +// int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) +// { // git_buf path = GIT_BUF_INIT; // git_buf contents = GIT_BUF_INIT; // int error, updated, line_num = 1; // char *line; -// char *buffer; +// chror = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_grafts->git_grafts->path_checksum, &updated); +// git_buf_dispose(&path); + +// if (error < 0 && error != GIT_ENOTFOUND) +// return error; + +// /* cancel out GIT_ENOTFOUND */ +// git_error_clear(); +// error = 0; + +// if (!updated) { +// out = repo->shallow_grafts; +// goto cleanup; +// } + +// git_array_clear(repo->shallow_grafts); + +// buffer = contents.ptr; +// while ((line = git__strsep(&buffer, "\n")) != NULL) { +// git_oid *oid = git_array_alloc(repo->shallow_grafts); + +// error = git_oid_fromstr(oid, line); +// if (error < 0) { +// git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); +// git_array_clear(repo->shallow_grafts); +// error = -1; +// goto cleanup; +// } +// ++line_num; +// } + +// if (*buffer) { +// git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); +// git_array_clear(repo->shallow_grafts); +// error = -1; +// goto cleanup; +// } + +// *out = repo->shallow_grafts; + +// cleanup: +// git_buf_dispose(&contents); + +// return error;ar *buffer; // assert(out && repo); @@ -3249,40 +3292,61 @@ int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) // cleanup: // git_buf_dispose(&contents); - // return error; - return 0; +// return error; +// } + +int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { + int error =0; + if (!repo->shallow_grafts) + load_grafts(repo); + + git_grafts_refresh(repo->shallow_grafts); + return git_grafts_get_oids(out, repo->shallow_grafts); } int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots) { - // git_filebuf file = GIT_FILEBUF_INIT; - // git_buf path = GIT_BUF_INIT; - // int error = 0; - // size_t idx; - // git_oid *oid; + git_filebuf file = GIT_FILEBUF_INIT; + git_buf path = GIT_BUF_INIT; + int error = 0; + size_t idx; + git_oid *oid; - // assert(repo); + assert(repo); - // if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) - // return error; + if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) + return error; - // if ((error = git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) - // return error; + if ((error = git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) + return error; - // git_array_foreach(roots, idx, oid) { - // git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); - // git_filebuf_write(&file, "\n", 1); - // } + git_array_foreach(roots, idx, oid) { + git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); + git_filebuf_write(&file, "\n", 1); + } - // git_filebuf_commit(&file); + git_filebuf_commit(&file); - // /* WIP: reload shallow */ - // if (load_shallow(repo) < 0) - // return -1; + if (load_grafts(repo) < 0) + return -1; return 0; } +int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) +{ + int ret; + git_array_oid_t array = GIT_ARRAY_INIT; + + assert(out); + + ret = git_repository__shallow_roots(&array, repo); + + git_oidarray__from_array(out, &array); + + return ret; +} + int git_repository_is_shallow(git_repository *repo) { git_buf path = GIT_BUF_INIT; diff --git a/tests/clone/shallow.c b/tests/clone/shallow.c index 6bd98ab0a24..b41e28d6611 100644 --- a/tests/clone/shallow.c +++ b/tests/clone/shallow.c @@ -34,7 +34,7 @@ void test_clone_shallow__clone_depth(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); - cl_git_pass(git_repository__shallow_roots(&roots, repo)); + cl_git_pass(git_repository_shallow_roots(&roots, repo)); cl_assert_equal_i(1, roots.count); cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ids[0])); @@ -43,8 +43,12 @@ void test_clone_shallow__clone_depth(void) git_revwalk_push_head(walk); while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { - if (depth + 1 > CLONE_DEPTH) - cl_fail("expected depth mismatch"); + //if (depth + 1 > CLONE_DEPTH) + //cl_fail("expected depth mismatch"); + char str[GIT_OID_HEXSZ +1]; + git_oid_fmt(str, &oid); + printf(str); + printf("\n"); depth++; } From 2a4d100ae862bc964c36d41ff69a5f0b17c5515d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 7 Jul 2022 21:30:28 -0400 Subject: [PATCH 038/816] refs: make `git_reference_cmp` consider the name `git_reference_cmp` only considers the target of a reference, and ignores the name. Meaning that a reference `foo` and reference `bar` pointing to the same commit will compare equal. Correct this, comparing the name _and_ target of a reference. --- src/libgit2/refs.c | 4 +++ tests/libgit2/refs/cmp.c | 27 +++++++++++++++++++ .../testrepo2/.gitted/refs/heads/symbolic-one | 1 + .../testrepo2/.gitted/refs/heads/symbolic-two | 1 + 4 files changed, 33 insertions(+) create mode 100644 tests/libgit2/refs/cmp.c create mode 100644 tests/resources/testrepo2/.gitted/refs/heads/symbolic-one create mode 100644 tests/resources/testrepo2/.gitted/refs/heads/symbolic-two diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index 5c875b95b23..72100b6ed3b 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -1054,10 +1054,14 @@ int git_reference_cmp( const git_reference *ref2) { git_reference_t type1, type2; + int ret; GIT_ASSERT_ARG(ref1); GIT_ASSERT_ARG(ref2); + if ((ret = strcmp(ref1->name, ref2->name)) != 0) + return ret; + type1 = git_reference_type(ref1); type2 = git_reference_type(ref2); diff --git a/tests/libgit2/refs/cmp.c b/tests/libgit2/refs/cmp.c new file mode 100644 index 00000000000..78d90b04a98 --- /dev/null +++ b/tests/libgit2/refs/cmp.c @@ -0,0 +1,27 @@ +#include "clar_libgit2.h" +#include "refs.h" + +static git_repository *g_repo; + +void test_refs_cmp__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo2"); +} + +void test_refs_cmp__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_refs_cmp__symbolic(void) +{ + git_reference *one, *two; + + cl_git_pass(git_reference_lookup(&one, g_repo, "refs/heads/symbolic-one")); + cl_git_pass(git_reference_lookup(&two, g_repo, "refs/heads/symbolic-two")); + + cl_assert(git_reference_cmp(one, two) != 0); + + git_reference_free(one); + git_reference_free(two); +} diff --git a/tests/resources/testrepo2/.gitted/refs/heads/symbolic-one b/tests/resources/testrepo2/.gitted/refs/heads/symbolic-one new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/tests/resources/testrepo2/.gitted/refs/heads/symbolic-one @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/testrepo2/.gitted/refs/heads/symbolic-two b/tests/resources/testrepo2/.gitted/refs/heads/symbolic-two new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/tests/resources/testrepo2/.gitted/refs/heads/symbolic-two @@ -0,0 +1 @@ +ref: refs/heads/master From d9de12f88bfb025d0092eaa18f266978577c11f2 Mon Sep 17 00:00:00 2001 From: Alberto Fanjul Date: Sun, 17 Jul 2022 23:52:11 +0200 Subject: [PATCH 039/816] fix log example --- examples/log.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/log.c b/examples/log.c index 4b0a95dcd0d..e9ebe377c87 100644 --- a/examples/log.c +++ b/examples/log.c @@ -81,9 +81,11 @@ int lg2_log(git_repository *repo, int argc, char *argv[]) git_commit *commit = NULL; git_pathspec *ps = NULL; + memset(&s, 0, sizeof(s)); + /** Parse arguments and set up revwalker. */ - last_arg = parse_options(&s, &opt, argc, argv); s.repo = repo; + last_arg = parse_options(&s, &opt, argc, argv); diffopts.pathspec.strings = &argv[last_arg]; diffopts.pathspec.count = argc - last_arg; @@ -407,8 +409,6 @@ static int parse_options( struct log_state *s, struct log_options *opt, int argc, char **argv) { struct args_info args = ARGS_INFO_INIT; - - memset(s, 0, sizeof(*s)); s->sorting = GIT_SORT_TIME; memset(opt, 0, sizeof(*opt)); From 6b86332465b8740b8845043acf377f7d383f6014 Mon Sep 17 00:00:00 2001 From: Alberto Fanjul Date: Mon, 18 Jul 2022 07:57:21 +0200 Subject: [PATCH 040/816] parse arguments correctly --- examples/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/log.c b/examples/log.c index e9ebe377c87..84de5510985 100644 --- a/examples/log.c +++ b/examples/log.c @@ -424,7 +424,7 @@ static int parse_options( else /** Try failed revision parse as filename. */ break; - } else if (!match_arg_separator(&args)) { + } else if (match_arg_separator(&args)) { break; } else if (!strcmp(a, "--date-order")) From c97989e48deb4a68b4a3ca43af4278131dfbd288 Mon Sep 17 00:00:00 2001 From: Alberto Fanjul Date: Mon, 18 Jul 2022 08:02:41 +0200 Subject: [PATCH 041/816] Add oneline option --- examples/log.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/examples/log.c b/examples/log.c index 84de5510985..62a6eb5858f 100644 --- a/examples/log.c +++ b/examples/log.c @@ -50,6 +50,7 @@ static int add_revision(struct log_state *s, const char *revstr); /** log_options holds other command line options that affect log output */ struct log_options { int show_diff; + int show_oneline; int show_log_size; int skip, limit; int min_parents, max_parents; @@ -337,34 +338,45 @@ static void print_commit(git_commit *commit, struct log_options *opts) const char *scan, *eol; git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); - printf("commit %s\n", buf); - if (opts->show_log_size) { - printf("log size %d\n", (int)strlen(git_commit_message(commit))); - } + if (opts->show_oneline) { + printf("%s ", buf); + } else { + printf("commit %s\n", buf); - if ((count = (int)git_commit_parentcount(commit)) > 1) { - printf("Merge:"); - for (i = 0; i < count; ++i) { - git_oid_tostr(buf, 8, git_commit_parent_id(commit, i)); - printf(" %s", buf); + if (opts->show_log_size) { + printf("log size %d\n", (int)strlen(git_commit_message(commit))); + } + + if ((count = (int)git_commit_parentcount(commit)) > 1) { + printf("Merge:"); + for (i = 0; i < count; ++i) { + git_oid_tostr(buf, 8, git_commit_parent_id(commit, i)); + printf(" %s", buf); + } + printf("\n"); } - printf("\n"); - } - if ((sig = git_commit_author(commit)) != NULL) { - printf("Author: %s <%s>\n", sig->name, sig->email); - print_time(&sig->when, "Date: "); + if ((sig = git_commit_author(commit)) != NULL) { + printf("Author: %s <%s>\n", sig->name, sig->email); + print_time(&sig->when, "Date: "); + } + printf("\n"); } - printf("\n"); for (scan = git_commit_message(commit); scan && *scan; ) { for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */; - printf(" %.*s\n", (int)(eol - scan), scan); + if (opts->show_oneline) + printf("%.*s\n", (int)(eol - scan), scan); + else + printf(" %.*s\n", (int)(eol - scan), scan); scan = *eol ? eol + 1 : NULL; + if (opts->show_oneline) + break; } - printf("\n"); + if (!opts->show_oneline) + printf("\n"); } /** Helper to find how many files in a commit changed from its nth parent. */ @@ -474,6 +486,8 @@ static int parse_options( opt->show_diff = 1; else if (!strcmp(a, "--log-size")) opt->show_log_size = 1; + else if (!strcmp(a, "--oneline")) + opt->show_oneline = 1; else usage("Unsupported argument", a); } From c652f3d13372398fc86c72a7b05c90002d1cc763 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 19 Jul 2022 13:54:33 +0100 Subject: [PATCH 042/816] enable cloning of shallow repo --- src/clone.c | 3 ++- tests/clone/shallow.c | 25 ++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/clone.c b/src/clone.c index 752df3b92d8..5750a71af39 100644 --- a/src/clone.c +++ b/src/clone.c @@ -409,7 +409,8 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); fetch_opts.update_fetchhead = 0; - fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; + if (fetch_opts.depth == -1) + fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_buf_cstr(&reflog_message))) != 0) diff --git a/tests/clone/shallow.c b/tests/clone/shallow.c index b41e28d6611..b3e8f161716 100644 --- a/tests/clone/shallow.c +++ b/tests/clone/shallow.c @@ -15,6 +15,15 @@ void test_clone_shallow__cleanup(void) #define CLONE_DEPTH 5 +static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) +{ + GIT_UNUSED(payload); + + cl_git_pass(git_remote_create_with_fetchspec(out, repo, name, url, "+refs/heads/master:refs/remotes/origin/master")); + + return 0; +} + void test_clone_shallow__clone_depth(void) { git_buf path = GIT_BUF_INIT; @@ -27,6 +36,7 @@ void test_clone_shallow__clone_depth(void) int error = 0; clone_opts.fetch_opts.depth = CLONE_DEPTH; + clone_opts.remote_cb = remote_single_branch; git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone"); @@ -35,21 +45,18 @@ void test_clone_shallow__clone_depth(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); cl_git_pass(git_repository_shallow_roots(&roots, repo)); - cl_assert_equal_i(1, roots.count); - cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ids[0])); + cl_assert_equal_i(3, roots.count); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots.ids[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&roots.ids[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ids[2])); git_revwalk_new(&walk, repo); git_revwalk_push_head(walk); while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { - //if (depth + 1 > CLONE_DEPTH) - //cl_fail("expected depth mismatch"); - char str[GIT_OID_HEXSZ +1]; - git_oid_fmt(str, &oid); - printf(str); - printf("\n"); - depth++; + if (depth + 1 > CLONE_DEPTH) + cl_fail("expected depth mismatch"); } cl_git_pass(error); From f19ffc8a6d88432146a87cd3fb2ca21528478be4 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 19 Jul 2022 15:42:12 +0100 Subject: [PATCH 043/816] add test for shallow repo depth 1 --- tests/clone/shallow.c | 60 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/tests/clone/shallow.c b/tests/clone/shallow.c index b3e8f161716..01852dfeddf 100644 --- a/tests/clone/shallow.c +++ b/tests/clone/shallow.c @@ -4,17 +4,15 @@ void test_clone_shallow__initialize(void) { - + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1)); } void test_clone_shallow__cleanup(void) { + git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); cl_git_sandbox_cleanup(); } - -#define CLONE_DEPTH 5 - static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) { GIT_UNUSED(payload); @@ -24,7 +22,47 @@ static int remote_single_branch(git_remote **out, git_repository *repo, const ch return 0; } -void test_clone_shallow__clone_depth(void) +void test_clone_shallow__clone_depth_one(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + git_revwalk *walk; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_oid oid; + git_oidarray roots; + size_t num_commits = 0; + int error = 0; + + clone_opts.fetch_opts.depth = 1; + clone_opts.remote_cb = remote_single_branch; + + git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone_1"); + + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_buf_cstr(&path), &clone_opts)); + + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + cl_git_pass(git_repository_shallow_roots(&roots, repo)); + cl_assert_equal_i(1, roots.count); + cl_assert_equal_s("49322bb17d3acc9146f98c97d078513228bbf3c0", git_oid_tostr_s(&roots.ids[0])); + + git_revwalk_new(&walk, repo); + + git_revwalk_push_head(walk); + + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + + cl_assert_equal_i(num_commits, 1); + cl_assert_equal_i(error, GIT_ITEROVER); + + git_buf_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +} + +void test_clone_shallow__clone_depth_five(void) { git_buf path = GIT_BUF_INIT; git_repository *repo; @@ -32,13 +70,13 @@ void test_clone_shallow__clone_depth(void) git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_oid oid; git_oidarray roots; - size_t depth = 0; + size_t num_commits = 0; int error = 0; - clone_opts.fetch_opts.depth = CLONE_DEPTH; + clone_opts.fetch_opts.depth = 5; clone_opts.remote_cb = remote_single_branch; - git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone"); + git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone_5"); cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_buf_cstr(&path), &clone_opts)); @@ -55,11 +93,11 @@ void test_clone_shallow__clone_depth(void) git_revwalk_push_head(walk); while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { - if (depth + 1 > CLONE_DEPTH) - cl_fail("expected depth mismatch"); + num_commits++; } - cl_git_pass(error); + cl_assert_equal_i(num_commits, 13); + cl_assert_equal_i(error, GIT_ITEROVER); git_buf_dispose(&path); git_revwalk_free(walk); From 7f46bfac14f0502711f8441348fd361175953fd5 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 26 Jul 2022 13:59:00 +0100 Subject: [PATCH 044/816] unset GIT_RAND_GETENTROPY to avoid linux GLIBC issues (#3) --- src/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e108b2e79ce..b81ad272f44 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,7 +70,11 @@ check_function_exists(qsort_s GIT_QSORT_S) # random / entropy data -check_function_exists(getentropy GIT_RAND_GETENTROPY) +# The flag has been unset to prevent issues +# related to Linux GLIBC version dependency + +# check_function_exists(getentropy GIT_RAND_GETENTROPY) +unset(GIT_RAND_GETENTROPY) check_function_exists(getloadavg GIT_RAND_GETLOADAVG) # determine architecture of the machine From 83f71b12e1f26943d3c544901846fb1d55785735 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 26 Jul 2022 16:57:30 +0100 Subject: [PATCH 045/816] fix build errors --- .gitignore | 1 + include/git2/common.h | 2 +- src/{ => libgit2}/grafts.c | 0 src/{ => libgit2}/grafts.h | 0 src/libgit2/repository.c | 6 +++--- 5 files changed, 5 insertions(+), 4 deletions(-) rename src/{ => libgit2}/grafts.c (100%) rename src/{ => libgit2}/grafts.h (100%) diff --git a/.gitignore b/.gitignore index 1b482f038af..d43bd9c7863 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ CMakeSettings.json .vs .idea +.cache diff --git a/include/git2/common.h b/include/git2/common.h index ac035f0afee..4e47488d73f 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -227,7 +227,7 @@ typedef enum { GIT_OPT_GET_EXTENSIONS, GIT_OPT_SET_EXTENSIONS, GIT_OPT_GET_OWNER_VALIDATION, - GIT_OPT_SET_OWNER_VALIDATION + GIT_OPT_SET_OWNER_VALIDATION, GIT_OPT_ENABLE_SHALLOW } git_libgit2_opt_t; diff --git a/src/grafts.c b/src/libgit2/grafts.c similarity index 100% rename from src/grafts.c rename to src/libgit2/grafts.c diff --git a/src/grafts.h b/src/libgit2/grafts.h similarity index 100% rename from src/grafts.h rename to src/libgit2/grafts.h diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 2ecc510b223..e58ab529a0a 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -736,13 +736,13 @@ static int load_grafts(git_repository *repo) int error; if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || - (error = git_buf_joinpath(&path, path.ptr, "grafts")) < 0 || + (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || (error = git_grafts_from_file(&repo->grafts, path.ptr)) < 0) goto error; - git_buf_clear(&path); + git_str_clear(&path); - if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0 || + if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 || (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr)) < 0) goto error; From cfc2ae68b4792f0c64152888869ef69d868079d7 Mon Sep 17 00:00:00 2001 From: yuangli Date: Wed, 27 Jul 2022 11:53:37 +0100 Subject: [PATCH 046/816] eliminate build warnings --- src/libgit2/commit.c | 7 +++---- src/libgit2/grafts.c | 6 +++--- src/libgit2/libgit2.c | 2 ++ src/libgit2/repository.c | 6 +++--- tests/{ => libgit2}/grafts/basic.c | 0 tests/{ => libgit2}/grafts/parse.c | 0 tests/{ => libgit2}/grafts/shallow.c | 0 7 files changed, 11 insertions(+), 10 deletions(-) rename tests/{ => libgit2}/grafts/basic.c (100%) rename tests/{ => libgit2}/grafts/parse.c (100%) rename tests/{ => libgit2}/grafts/shallow.c (100%) diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 7432ef4ec53..2138d6eb210 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -501,8 +501,10 @@ int git_commit__parse_raw(void *commit, const char *data, size_t size) int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) { - + git_repository *repo = git_object_owner((git_object *)commit); + git_commit_graft *graft; int error; + if ((error = commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags)) < 0) return error; @@ -510,9 +512,6 @@ int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned if (!git_shallow__enabled) return 0; - git_repository *repo = git_object_owner((git_object *)commit); - git_commit_graft *graft; - /* Perform necessary grafts */ if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) == 0 || git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) == 0) { diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 00352261670..8bcefbab9e5 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -85,7 +85,7 @@ void git_grafts_clear(git_grafts *grafts) int git_grafts_refresh(git_grafts *grafts) { - git_buf contents = GIT_BUF_INIT; + git_str contents = GIT_STR_INIT; int error, updated = 0; assert(grafts); @@ -94,7 +94,7 @@ int git_grafts_refresh(git_grafts *grafts) return 0; error = git_futils_readbuffer_updated(&contents, grafts->path, - &grafts->path_checksum, &updated); + (grafts->path_checksum).id, &updated); if (error < 0 || error == GIT_ENOTFOUND || !updated) { if (error == GIT_ENOTFOUND) { git_grafts_clear(grafts); @@ -107,7 +107,7 @@ int git_grafts_refresh(git_grafts *grafts) goto cleanup; cleanup: - git_buf_dispose(&contents); + git_str_dispose(&contents); return error; } diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index b76728e0ce4..2537730cf57 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -413,6 +413,8 @@ int git_libgit2_opts(int key, ...) case GIT_OPT_SET_OWNER_VALIDATION: git_repository__validate_ownership = (va_arg(ap, int) != 0); + break; + case GIT_OPT_ENABLE_SHALLOW: git_shallow__enabled = (va_arg(ap, int) != 0); break; diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index e58ab529a0a..809617276f0 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -732,10 +732,10 @@ static int find_repo( static int load_grafts(git_repository *repo) { - git_buf path = GIT_BUF_INIT; + git_str path = GIT_STR_INIT; int error; - if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || + if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || (error = git_grafts_from_file(&repo->grafts, path.ptr)) < 0) goto error; @@ -747,7 +747,7 @@ static int load_grafts(git_repository *repo) goto error; error: - git_buf_dispose(&path); + git_str_dispose(&path); return error; } diff --git a/tests/grafts/basic.c b/tests/libgit2/grafts/basic.c similarity index 100% rename from tests/grafts/basic.c rename to tests/libgit2/grafts/basic.c diff --git a/tests/grafts/parse.c b/tests/libgit2/grafts/parse.c similarity index 100% rename from tests/grafts/parse.c rename to tests/libgit2/grafts/parse.c diff --git a/tests/grafts/shallow.c b/tests/libgit2/grafts/shallow.c similarity index 100% rename from tests/grafts/shallow.c rename to tests/libgit2/grafts/shallow.c From c01b7841b77c08189eae916d21d591027962a831 Mon Sep 17 00:00:00 2001 From: yuangli Date: Thu, 28 Jul 2022 14:24:18 +0100 Subject: [PATCH 047/816] improve error handling --- .gitignore | 1 - include/git2/repository.h | 1 - src/libgit2/grafts.c | 10 +++++++--- src/libgit2/repository.c | 7 ------- src/libgit2/repository.h | 1 - 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index d43bd9c7863..1b482f038af 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ CMakeSettings.json .vs .idea -.cache diff --git a/include/git2/repository.h b/include/git2/repository.h index 258b9ac00a7..c87f3c96252 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -11,7 +11,6 @@ #include "types.h" #include "oid.h" #include "buffer.h" -#include "oidarray.h" /** * @file git2/repository.h diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 8bcefbab9e5..82be2a68069 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -93,13 +93,17 @@ int git_grafts_refresh(git_grafts *grafts) if (!grafts->path) return 0; - error = git_futils_readbuffer_updated(&contents, grafts->path, - (grafts->path_checksum).id, &updated); - if (error < 0 || error == GIT_ENOTFOUND || !updated) { + if ((error = git_futils_readbuffer_updated(&contents, grafts->path, + (grafts->path_checksum).id, &updated)) < 0) { if (error == GIT_ENOTFOUND) { git_grafts_clear(grafts); error = 0; } + + goto cleanup; + } + + if (!updated) { goto cleanup; } diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 809617276f0..c36666c436c 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -735,13 +735,6 @@ static int load_grafts(git_repository *repo) git_str path = GIT_STR_INIT; int error; - if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || - (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || - (error = git_grafts_from_file(&repo->grafts, path.ptr)) < 0) - goto error; - - git_str_clear(&path); - if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 || (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr)) < 0) goto error; diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index 6d39bb92af7..3cca53b3e54 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -25,7 +25,6 @@ #include "submodule.h" #include "diff_driver.h" #include "grafts.h" -#include "oidarray.h" #define DOT_GIT ".git" #define GIT_DIR DOT_GIT "/" From 14d2a60a5bdb6fe62b65751bda0ce01a66ac5e99 Mon Sep 17 00:00:00 2001 From: yuangli Date: Thu, 28 Jul 2022 14:30:30 +0100 Subject: [PATCH 048/816] fix load_grafts --- src/libgit2/repository.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index c36666c436c..809617276f0 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -735,6 +735,13 @@ static int load_grafts(git_repository *repo) git_str path = GIT_STR_INIT; int error; + if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || + (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || + (error = git_grafts_from_file(&repo->grafts, path.ptr)) < 0) + goto error; + + git_str_clear(&path); + if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 || (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr)) < 0) goto error; From 62cc77a16d62410140e31960189e566f16b22772 Mon Sep 17 00:00:00 2001 From: yuangli Date: Thu, 28 Jul 2022 16:03:59 +0100 Subject: [PATCH 049/816] refactor commit parent assignment with graft --- src/libgit2/commit.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 2138d6eb210..6f689e36216 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -499,6 +499,22 @@ int git_commit__parse_raw(void *commit, const char *data, size_t size) return commit_parse(commit, data, size, 0); } +static int assign_parents_from_graft(git_commit *commit, git_commit_graft *graft) { + size_t idx; + git_oid *oid; + + git_array_clear(commit->parent_ids); + git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); + git_array_foreach(graft->parents, idx, oid) { + git_oid *id = git_array_alloc(commit->parent_ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, oid); + } + + return 0; +} + int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) { git_repository *repo = git_object_owner((git_object *)commit); @@ -513,21 +529,11 @@ int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned return 0; /* Perform necessary grafts */ - if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) == 0 || - git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) == 0) { - size_t idx; - git_oid *oid; - git_array_clear(commit->parent_ids); - git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); - git_array_foreach(graft->parents, idx, oid) { - git_oid *id = git_array_alloc(commit->parent_ids); - GIT_ERROR_CHECK_ALLOC(id); - - git_oid_cpy(id, oid); - } - } - - return 0; + if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != 0 && + git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) != 0) + return 0; + + return assign_parents_from_graft(commit, graft); } int git_commit__parse(void *_commit, git_odb_object *odb_obj) From a544a91058cc310a0e36e290debe5ad59040fab1 Mon Sep 17 00:00:00 2001 From: yuangli Date: Thu, 28 Jul 2022 16:05:21 +0100 Subject: [PATCH 050/816] rename function assign_parents_from_graft --- src/libgit2/commit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 6f689e36216..43d04b2c028 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -499,7 +499,7 @@ int git_commit__parse_raw(void *commit, const char *data, size_t size) return commit_parse(commit, data, size, 0); } -static int assign_parents_from_graft(git_commit *commit, git_commit_graft *graft) { +static int assign_commit_parents_from_graft(git_commit *commit, git_commit_graft *graft) { size_t idx; git_oid *oid; @@ -533,7 +533,7 @@ int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) != 0) return 0; - return assign_parents_from_graft(commit, graft); + return assign_commit_parents_from_graft(commit, graft); } int git_commit__parse(void *_commit, git_odb_object *odb_obj) From 73d25f0e7b026d7b744e249d922f248376bcce5d Mon Sep 17 00:00:00 2001 From: yuangli Date: Fri, 29 Jul 2022 13:53:29 +0100 Subject: [PATCH 051/816] remove build errors --- include/git2/remote.h | 12 ++-- include/git2/repository.h | 1 + src/libgit2/clone.c | 2 +- src/libgit2/commit.c | 2 +- src/libgit2/fetch.c | 7 +- src/libgit2/repository.c | 109 +---------------------------- src/libgit2/transports/smart_pkt.c | 16 ++--- 7 files changed, 21 insertions(+), 128 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 871d898e582..33f5103ceaf 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -743,6 +743,11 @@ typedef struct { */ git_proxy_options proxy_opts; + /** + * Depth of the fetch to perform + */ + int depth; + /** * Whether to allow off-site redirects. If this is not * specified, the `http.followRedirects` configuration setting @@ -754,16 +759,11 @@ typedef struct { * Extra headers for this fetch operation */ git_strarray custom_headers; - - /** - * Depth of the fetch to perform - */ - int depth; } git_fetch_options; #define GIT_FETCH_OPTIONS_VERSION 1 #define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ - GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, { NULL }, -1 } + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, -1 } /** * Initialize git_fetch_options structure diff --git a/include/git2/repository.h b/include/git2/repository.h index 24a94118be9..d6b054dc30f 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -11,6 +11,7 @@ #include "types.h" #include "oid.h" #include "buffer.h" +#include "oidarray.h" /** * @file git2/repository.h diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index 101c741b1f7..ee1f2b892d0 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -411,7 +411,7 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch fetch_opts.update_fetchhead = 0; if (fetch_opts.depth == -1) fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; - git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); + git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0) goto cleanup; diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 75cc8837c73..528d8beb79d 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -422,7 +422,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig buffer += tree_len; } - while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { + while (git_object__parse_oid_header(&parent_id, &buffer, buffer_end, "parent ", GIT_OID_SHA1) == 0) { git_oid *new_id = git_array_alloc(commit->parent_ids); GIT_ERROR_CHECK_ALLOC(new_id); diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 10155662dd4..e4a8f038263 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -209,12 +209,7 @@ int git_fetch_download_pack(git_remote *remote) if (!remote->need_pack) return 0; - if (callbacks) { - progress = callbacks->transfer_progress; - payload = callbacks->payload; - } - - if ((error = t->download_pack(t, remote->repo, &remote->stats, progress, payload)) < 0) + if ((error = t->download_pack(t, remote->repo, &remote->stats)) < 0) return error; if ((error = git_repository__shallow_roots_write(remote->repo, remote->nego.shallow_roots->array)) < 0) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index adb4721ad82..d9bc537febc 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3340,109 +3340,6 @@ int git_repository_state_cleanup(git_repository *repo) return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); } -// int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) -// { -// git_buf path = GIT_BUF_INIT; -// git_buf contents = GIT_BUF_INIT; -// int error, updated, line_num = 1; -// char *line; -// chror = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_grafts->git_grafts->path_checksum, &updated); -// git_buf_dispose(&path); - -// if (error < 0 && error != GIT_ENOTFOUND) -// return error; - -// /* cancel out GIT_ENOTFOUND */ -// git_error_clear(); -// error = 0; - -// if (!updated) { -// out = repo->shallow_grafts; -// goto cleanup; -// } - -// git_array_clear(repo->shallow_grafts); - -// buffer = contents.ptr; -// while ((line = git__strsep(&buffer, "\n")) != NULL) { -// git_oid *oid = git_array_alloc(repo->shallow_grafts); - -// error = git_oid_fromstr(oid, line); -// if (error < 0) { -// git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); -// git_array_clear(repo->shallow_grafts); -// error = -1; -// goto cleanup; -// } -// ++line_num; -// } - -// if (*buffer) { -// git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); -// git_array_clear(repo->shallow_grafts); -// error = -1; -// goto cleanup; -// } - -// *out = repo->shallow_grafts; - -// cleanup: -// git_buf_dispose(&contents); - -// return error;ar *buffer; - -// assert(out && repo); - -// if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) -// return error; - -// //error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_checksum, &updated); -// error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_grafts->git_grafts->path_checksum, &updated); -// git_buf_dispose(&path); - -// if (error < 0 && error != GIT_ENOTFOUND) -// return error; - -// /* cancel out GIT_ENOTFOUND */ -// git_error_clear(); -// error = 0; - -// if (!updated) { -// out = repo->shallow_grafts; -// goto cleanup; -// } - -// git_array_clear(repo->shallow_grafts); - -// buffer = contents.ptr; -// while ((line = git__strsep(&buffer, "\n")) != NULL) { -// git_oid *oid = git_array_alloc(repo->shallow_grafts); - -// error = git_oid_fromstr(oid, line); -// if (error < 0) { -// git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num); -// git_array_clear(repo->shallow_grafts); -// error = -1; -// goto cleanup; -// } -// ++line_num; -// } - -// if (*buffer) { -// git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num); -// git_array_clear(repo->shallow_grafts); -// error = -1; -// goto cleanup; -// } - -// *out = repo->shallow_grafts; - -// cleanup: -// git_buf_dispose(&contents); - -// return error; -// } - int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { int error =0; if (!repo->shallow_grafts) @@ -3455,17 +3352,17 @@ int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots) { git_filebuf file = GIT_FILEBUF_INIT; - git_buf path = GIT_BUF_INIT; + git_str path = GIT_STR_INIT; int error = 0; size_t idx; git_oid *oid; assert(repo); - if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) + if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0) return error; - if ((error = git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) + if ((error = git_filebuf_open(&file, git_str_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) return error; git_array_foreach(roots, idx, oid) { diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index e368cb7e235..f9fde00f1c8 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -678,23 +678,23 @@ int git_pkt_buffer_wants( git_buf shallow_buf = GIT_BUF_INIT; git_oid_fmt(oid, git_shallowarray_get(wants->shallow_roots, i)); - git_buf_puts(&shallow_buf, "shallow "); - git_buf_put(&shallow_buf, oid, GIT_OID_HEXSZ); - git_buf_putc(&shallow_buf, '\n'); + git_str_puts(&shallow_buf, "shallow "); + git_str_put(&shallow_buf, oid, GIT_OID_HEXSZ); + git_str_putc(&shallow_buf, '\n'); - git_buf_printf(buf, "%04x%s", (unsigned int)git_buf_len(&shallow_buf) + 4, git_buf_cstr(&shallow_buf)); + git_str_printf(buf, "%04x%s", (unsigned int)git_str_len(&shallow_buf) + 4, git_str_cstr(&shallow_buf)); - if (git_buf_oom(buf)) + if (git_str_oom(buf)) return -1; } if (wants->depth > 0) { git_buf deepen_buf = GIT_BUF_INIT; - git_buf_printf(&deepen_buf, "deepen %d\n", wants->depth); - git_buf_printf(buf,"%04x%s", (unsigned int)git_buf_len(&deepen_buf) + 4, git_buf_cstr(&deepen_buf)); + git_str_printf(&deepen_buf, "deepen %d\n", wants->depth); + git_str_printf(buf,"%04x%s", (unsigned int)git_str_len(&deepen_buf) + 4, git_str_cstr(&deepen_buf)); - if (git_buf_oom(buf)) + if (git_str_oom(buf)) return -1; } From 598ec303c6862f581c22c49228d543442e30257a Mon Sep 17 00:00:00 2001 From: yuangli Date: Fri, 29 Jul 2022 15:04:17 +0100 Subject: [PATCH 052/816] eliminate build warnings --- src/libgit2/fetch.c | 2 -- src/libgit2/grafts.c | 7 ++----- src/libgit2/grafts.h | 2 +- src/libgit2/repository.c | 18 +++++++++++++----- src/libgit2/transports/smart_pkt.c | 4 ++-- tests/{ => libgit2}/clone/shallow.c | 18 +++++++++--------- 6 files changed, 27 insertions(+), 24 deletions(-) rename tests/{ => libgit2}/clone/shallow.c (87%) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index e4a8f038263..b90ce2ee857 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -202,8 +202,6 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) int git_fetch_download_pack(git_remote *remote) { git_transport *t = remote->transport; - git_indexer_progress_cb progress = NULL; - void *payload = NULL; int error; if (!remote->need_pack) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 82be2a68069..f1054fa36ea 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -220,9 +220,8 @@ int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oi return 0; } -int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts) +int git_grafts_get_oids(git_array_oid_t *out, git_grafts *grafts) { - git_array_oid_t oids = GIT_ARRAY_INIT; const git_oid *oid; size_t i = 0; int error; @@ -230,13 +229,11 @@ int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts) assert(out && grafts); while ((error = git_oidmap_iterate(NULL, grafts->commits, &i, &oid)) == 0) { - git_oid *cpy = git_array_alloc(oids); + git_oid *cpy = git_array_alloc(*out); GIT_ERROR_CHECK_ALLOC(cpy); git_oid_cpy(cpy, oid); } - git_oidarray__from_array(out, &oids); - return 0; } diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h index fd9ef673698..4139438bba7 100644 --- a/src/libgit2/grafts.h +++ b/src/libgit2/grafts.h @@ -31,7 +31,7 @@ int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); int git_grafts_remove(git_grafts *grafts, const git_oid *oid); int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); -int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts); +int git_grafts_get_oids(git_array_oid_t *out, git_grafts *grafts); size_t git_grafts_size(git_grafts *grafts); #endif diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index d9bc537febc..bc2aba32413 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3341,12 +3341,20 @@ int git_repository_state_cleanup(git_repository *repo) } int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { - int error =0; - if (!repo->shallow_grafts) - load_grafts(repo); + int error = 0; + + if (!repo->shallow_grafts && (error = load_grafts(repo)) < 0) + return error; + + if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0) { + return error; + } - git_grafts_refresh(repo->shallow_grafts); - return git_grafts_get_oids(out, repo->shallow_grafts); + if ((error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) { + return error; + } + + return 0; } int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index f9fde00f1c8..951356c29b6 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -675,7 +675,7 @@ int git_pkt_buffer_wants( /* Tell the server about our shallow objects */ for (i = 0; i < git_shallowarray_count(wants->shallow_roots); i++) { char oid[GIT_OID_HEXSZ]; - git_buf shallow_buf = GIT_BUF_INIT; + git_str shallow_buf = GIT_STR_INIT; git_oid_fmt(oid, git_shallowarray_get(wants->shallow_roots, i)); git_str_puts(&shallow_buf, "shallow "); @@ -689,7 +689,7 @@ int git_pkt_buffer_wants( } if (wants->depth > 0) { - git_buf deepen_buf = GIT_BUF_INIT; + git_str deepen_buf = GIT_STR_INIT; git_str_printf(&deepen_buf, "deepen %d\n", wants->depth); git_str_printf(buf,"%04x%s", (unsigned int)git_str_len(&deepen_buf) + 4, git_str_cstr(&deepen_buf)); diff --git a/tests/clone/shallow.c b/tests/libgit2/clone/shallow.c similarity index 87% rename from tests/clone/shallow.c rename to tests/libgit2/clone/shallow.c index 01852dfeddf..2cd3d6caca9 100644 --- a/tests/clone/shallow.c +++ b/tests/libgit2/clone/shallow.c @@ -24,21 +24,21 @@ static int remote_single_branch(git_remote **out, git_repository *repo, const ch void test_clone_shallow__clone_depth_one(void) { - git_buf path = GIT_BUF_INIT; + git_str path = GIT_STR_INIT; git_repository *repo; git_revwalk *walk; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_oid oid; - git_oidarray roots; + roots; size_t num_commits = 0; int error = 0; clone_opts.fetch_opts.depth = 1; clone_opts.remote_cb = remote_single_branch; - git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone_1"); + git_str_joinpath(&path, clar_sandbox_path(), "shallowclone_1"); - cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_buf_cstr(&path), &clone_opts)); + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); cl_assert_equal_b(true, git_repository_is_shallow(repo)); @@ -57,14 +57,14 @@ void test_clone_shallow__clone_depth_one(void) cl_assert_equal_i(num_commits, 1); cl_assert_equal_i(error, GIT_ITEROVER); - git_buf_dispose(&path); + git_str_dispose(&path); git_revwalk_free(walk); git_repository_free(repo); } void test_clone_shallow__clone_depth_five(void) { - git_buf path = GIT_BUF_INIT; + git_str path = GIT_STR_INIT; git_repository *repo; git_revwalk *walk; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; @@ -76,9 +76,9 @@ void test_clone_shallow__clone_depth_five(void) clone_opts.fetch_opts.depth = 5; clone_opts.remote_cb = remote_single_branch; - git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone_5"); + git_str_joinpath(&path, clar_sandbox_path(), "shallowclone_5"); - cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_buf_cstr(&path), &clone_opts)); + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); cl_assert_equal_b(true, git_repository_is_shallow(repo)); @@ -99,7 +99,7 @@ void test_clone_shallow__clone_depth_five(void) cl_assert_equal_i(num_commits, 13); cl_assert_equal_i(error, GIT_ITEROVER); - git_buf_dispose(&path); + git_str_dispose(&path); git_revwalk_free(walk); git_repository_free(repo); } From 179aac788d45d3683a93ad478bfb7371c549ca98 Mon Sep 17 00:00:00 2001 From: yuangli Date: Fri, 29 Jul 2022 16:04:43 +0100 Subject: [PATCH 053/816] fix clone::shallow test behaviour --- src/libgit2/transports/smart_protocol.c | 2 -- tests/libgit2/clone/shallow.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index cd90db43f75..f2a6ac50892 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -375,10 +375,8 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c while ((error = recv_pkt((git_pkt **)&pkt, NULL, buf)) == 0) { if (pkt->type == GIT_PKT_SHALLOW) { - printf("shallow %s\n", git_oid_tostr_s(&pkt->oid)); git_shallowarray_add(wants->shallow_roots, &pkt->oid); } else if (pkt->type == GIT_PKT_UNSHALLOW) { - printf("unshallow %s\n", git_oid_tostr_s(&pkt->oid)); git_shallowarray_remove(wants->shallow_roots, &pkt->oid); } else if (pkt->type == GIT_PKT_FLUSH) { /* Server is done, stop processing shallow oids */ diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/clone/shallow.c index 2cd3d6caca9..4b27b27a959 100644 --- a/tests/libgit2/clone/shallow.c +++ b/tests/libgit2/clone/shallow.c @@ -29,7 +29,7 @@ void test_clone_shallow__clone_depth_one(void) git_revwalk *walk; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_oid oid; - roots; + git_oidarray roots; size_t num_commits = 0; int error = 0; From e7294e870398d72b79a436b628170ffcaaa1713c Mon Sep 17 00:00:00 2001 From: yuangli Date: Mon, 1 Aug 2022 21:42:11 +0100 Subject: [PATCH 054/816] fix memory leaks about packets --- src/libgit2/transports/smart_pkt.c | 2 ++ src/libgit2/transports/smart_protocol.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 951356c29b6..5808b8816a9 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -694,6 +694,8 @@ int git_pkt_buffer_wants( git_str_printf(&deepen_buf, "deepen %d\n", wants->depth); git_str_printf(buf,"%04x%s", (unsigned int)git_str_len(&deepen_buf) + 4, git_str_cstr(&deepen_buf)); + git_str_dispose(&deepen_buf); + if (git_str_oom(buf)) return -1; } diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index f2a6ac50892..a44d0c85369 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -385,8 +385,12 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c git_error_set(GIT_ERROR_NET, "Unexpected pkt type"); goto on_error; } + + git_pkt_free((git_pkt *) pkt); } + git_pkt_free((git_pkt *) pkt); + if (error < 0) { goto on_error; } From 2d33fe78858354c508afb77d80f32a5a747b801e Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 2 Aug 2022 13:15:22 +0100 Subject: [PATCH 055/816] refactor git_fetch_option.depth and usage --- include/git2/remote.h | 4 +++- src/libgit2/clone.c | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 33f5103ceaf..f3415d843ec 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -744,7 +744,9 @@ typedef struct { git_proxy_options proxy_opts; /** - * Depth of the fetch to perform + * Depth of the fetch to perform, has to be a positive integer. + * + * The default is -1, which will fetch the full history. */ int depth; diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index ee1f2b892d0..95bddeae6a6 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -389,6 +389,11 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c return error; } +static int git_fetch_is_shallow(git_fetch_options *opts) +{ + return opts->depth > 0; +} + static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch) { int error; @@ -409,8 +414,10 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); fetch_opts.update_fetchhead = 0; - if (fetch_opts.depth == -1) + + if (!git_fetch_is_shallow(opts)) fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; + git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0) From 4536477ee1f884501717b3a4a67da3bc4974e7f8 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 2 Aug 2022 14:35:08 +0100 Subject: [PATCH 056/816] fix memory leak --- src/libgit2/repository.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index bc2aba32413..105ea647fa7 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3380,6 +3380,8 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro git_filebuf_commit(&file); + git_str_dispose(&path); + if (load_grafts(repo) < 0) return -1; From e93d0815a8de2806667851e31dbd06578db00f95 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 2 Aug 2022 14:35:27 +0100 Subject: [PATCH 057/816] attempt to fix nego.shallowarray memory leak --- src/libgit2/remote.c | 3 +++ src/libgit2/transports/smart.c | 6 ++++++ src/libgit2/transports/smart.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 02d271d7d9d..c3d3af530a5 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -22,6 +22,7 @@ #include "git2/types.h" #include "git2/oid.h" #include "git2/net.h" +#include "transports/smart.h" #define CONFIG_URL_FMT "remote.%s.url" #define CONFIG_PUSHURL_FMT "remote.%s.pushurl" @@ -2163,6 +2164,8 @@ void git_remote_free(git_remote *remote) free_heads(&remote->local_heads); git_vector_free(&remote->local_heads); + git_shallowarray_free((remote->nego).shallow_roots); + git_push_free(remote->push); git__free(remote->url); git__free(remote->pushurl); diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index 9d1afeb05f5..df8e4da4ab9 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -510,3 +510,9 @@ int git_shallowarray_remove(git_shallowarray *array, git_oid *oid) /* no git_array_remove… meh */ return -1; } + +void git_shallowarray_free(git_shallowarray *array) +{ + git_array_clear(array->array); + git__free(array); +} diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index bc072d2feab..f9577cdee0b 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -203,4 +203,6 @@ struct git_shallowarray { git_array_oid_t array; }; +void git_shallowarray_free(git_shallowarray *array); + #endif From da04d3fc5e737b990e884129241f2ea3cba4cf6a Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 2 Aug 2022 16:30:48 +0100 Subject: [PATCH 058/816] fix grafts and shallowarray memory leaks --- src/libgit2/grafts.c | 3 +++ src/libgit2/remote.c | 7 +++++-- src/libgit2/repository.c | 6 ++---- src/libgit2/transports/smart.c | 6 ------ src/libgit2/transports/smart.h | 2 -- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index f1054fa36ea..dd1be34342c 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -43,6 +43,9 @@ int git_grafts_from_file(git_grafts **out, const char *path) git_grafts *grafts = NULL; int error; + if (*out) + return git_grafts_refresh(*out); + if ((error = git_grafts_new(&grafts)) < 0) goto error; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index c3d3af530a5..63346e9411c 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2150,6 +2150,11 @@ void git_remote_free(git_remote *remote) remote->transport = NULL; } + if (remote->nego.shallow_roots) { + git_array_clear(remote->nego.shallow_roots->array); + git__free(remote->nego.shallow_roots); + } + git_vector_free(&remote->refs); free_refspecs(&remote->refspecs); @@ -2164,8 +2169,6 @@ void git_remote_free(git_remote *remote) free_heads(&remote->local_heads); git_vector_free(&remote->local_heads); - git_shallowarray_free((remote->nego).shallow_roots); - git_push_free(remote->push); git__free(remote->url); git__free(remote->pushurl); diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 105ea647fa7..0d149a6264f 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3346,13 +3346,11 @@ int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { if (!repo->shallow_grafts && (error = load_grafts(repo)) < 0) return error; - if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0) { + if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0) return error; - } - if ((error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) { + if ((error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) return error; - } return 0; } diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index df8e4da4ab9..9d1afeb05f5 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -510,9 +510,3 @@ int git_shallowarray_remove(git_shallowarray *array, git_oid *oid) /* no git_array_remove… meh */ return -1; } - -void git_shallowarray_free(git_shallowarray *array) -{ - git_array_clear(array->array); - git__free(array); -} diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index f9577cdee0b..bc072d2feab 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -203,6 +203,4 @@ struct git_shallowarray { git_array_oid_t array; }; -void git_shallowarray_free(git_shallowarray *array); - #endif From 8ef492fafcc05ccfa90481057eccc8ba4f5e730a Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 2 Aug 2022 16:46:44 +0100 Subject: [PATCH 059/816] fix build warning --- src/libgit2/clone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index 95bddeae6a6..5e07dc73371 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -389,7 +389,7 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c return error; } -static int git_fetch_is_shallow(git_fetch_options *opts) +static int git_fetch_is_shallow(const git_fetch_options *opts) { return opts->depth > 0; } From 829555a9382f74af5280ab6cc2ac505534a4cecb Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 2 Aug 2022 16:47:01 +0100 Subject: [PATCH 060/816] edit tests for shallow clones --- tests/libgit2/clone/shallow.c | 48 +++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/clone/shallow.c index 4b27b27a959..7fb056f9155 100644 --- a/tests/libgit2/clone/shallow.c +++ b/tests/libgit2/clone/shallow.c @@ -22,6 +22,32 @@ static int remote_single_branch(git_remote **out, git_repository *repo, const ch return 0; } +void test_clone_shallow__clone_depth_zero(void) +{ + git_str path = GIT_STR_INIT; + git_repository *repo; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_array_oid_t roots = GIT_ARRAY_INIT; + + clone_opts.fetch_opts.depth = 0; + clone_opts.remote_cb = remote_single_branch; + + git_str_joinpath(&path, clar_sandbox_path(), "shallowclone_0"); + + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); + + /* cloning with depth 0 results in a full clone. */ + cl_assert_equal_b(false, git_repository_is_shallow(repo)); + + /* full clones do not have shallow roots. */ + cl_git_pass(git_repository__shallow_roots(&roots, repo)); + cl_assert_equal_i(0, roots.size); + + git_array_clear(roots); + git_str_dispose(&path); + git_repository_free(repo); +} + void test_clone_shallow__clone_depth_one(void) { git_str path = GIT_STR_INIT; @@ -29,7 +55,7 @@ void test_clone_shallow__clone_depth_one(void) git_revwalk *walk; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_oid oid; - git_oidarray roots; + git_array_oid_t roots = GIT_ARRAY_INIT; size_t num_commits = 0; int error = 0; @@ -42,9 +68,9 @@ void test_clone_shallow__clone_depth_one(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); - cl_git_pass(git_repository_shallow_roots(&roots, repo)); - cl_assert_equal_i(1, roots.count); - cl_assert_equal_s("49322bb17d3acc9146f98c97d078513228bbf3c0", git_oid_tostr_s(&roots.ids[0])); + cl_git_pass(git_repository__shallow_roots(&roots, repo)); + cl_assert_equal_i(1, roots.size); + cl_assert_equal_s("49322bb17d3acc9146f98c97d078513228bbf3c0", git_oid_tostr_s(&roots.ptr[0])); git_revwalk_new(&walk, repo); @@ -57,6 +83,7 @@ void test_clone_shallow__clone_depth_one(void) cl_assert_equal_i(num_commits, 1); cl_assert_equal_i(error, GIT_ITEROVER); + git_array_clear(roots); git_str_dispose(&path); git_revwalk_free(walk); git_repository_free(repo); @@ -69,7 +96,7 @@ void test_clone_shallow__clone_depth_five(void) git_revwalk *walk; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_oid oid; - git_oidarray roots; + git_array_oid_t roots = GIT_ARRAY_INIT; size_t num_commits = 0; int error = 0; @@ -82,11 +109,11 @@ void test_clone_shallow__clone_depth_five(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); - cl_git_pass(git_repository_shallow_roots(&roots, repo)); - cl_assert_equal_i(3, roots.count); - cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots.ids[0])); - cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&roots.ids[1])); - cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ids[2])); + cl_git_pass(git_repository__shallow_roots(&roots, repo)); + cl_assert_equal_i(3, roots.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots.ptr[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&roots.ptr[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ptr[2])); git_revwalk_new(&walk, repo); @@ -99,6 +126,7 @@ void test_clone_shallow__clone_depth_five(void) cl_assert_equal_i(num_commits, 13); cl_assert_equal_i(error, GIT_ITEROVER); + git_array_clear(roots); git_str_dispose(&path); git_revwalk_free(walk); git_repository_free(repo); From 09b3d33d6dba7f4804b478a72dec3258405856c2 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 9 Aug 2022 19:23:54 +0100 Subject: [PATCH 061/816] fix memory leak --- src/libgit2/transports/smart_pkt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 5808b8816a9..832da450c88 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -684,6 +684,8 @@ int git_pkt_buffer_wants( git_str_printf(buf, "%04x%s", (unsigned int)git_str_len(&shallow_buf) + 4, git_str_cstr(&shallow_buf)); + git_str_dispose(&shallow_buf); + if (git_str_oom(buf)) return -1; } From df5eb3239b1419b3f4382d7bcca9a5d85611d7d3 Mon Sep 17 00:00:00 2001 From: yuangli Date: Tue, 9 Aug 2022 19:24:57 +0100 Subject: [PATCH 062/816] support fetch unshallow option on shallow repos --- include/git2/remote.h | 9 +++- src/libgit2/clone.c | 7 +-- src/libgit2/fetch.c | 9 +++- src/libgit2/repository.c | 19 ++++--- src/libgit2/transports/smart.c | 26 ++++++++-- tests/libgit2/clone/shallow.c | 41 +++++++++++++++ tests/libgit2/transports/smart/shallowarray.c | 52 +++++++++++++++++++ 7 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 tests/libgit2/transports/smart/shallowarray.c diff --git a/include/git2/remote.h b/include/git2/remote.h index f3415d843ec..240e5aa4edf 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -750,6 +750,13 @@ typedef struct { */ int depth; + /** + * Unshallow flag of the fetch to perform. + * + * The default is 0, which means the flag is off. + */ + int unshallow; + /** * Whether to allow off-site redirects. If this is not * specified, the `http.followRedirects` configuration setting @@ -765,7 +772,7 @@ typedef struct { #define GIT_FETCH_OPTIONS_VERSION 1 #define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ - GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, -1 } + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, -1, 0 } /** * Initialize git_fetch_options structure diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index 5e07dc73371..6f34cb7ca35 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -389,11 +389,6 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c return error; } -static int git_fetch_is_shallow(const git_fetch_options *opts) -{ - return opts->depth > 0; -} - static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch) { int error; @@ -415,7 +410,7 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); fetch_opts.update_fetchhead = 0; - if (!git_fetch_is_shallow(opts)) + if (opts->depth <= 0) fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index b90ce2ee857..a015cfbd330 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -61,7 +61,7 @@ static int mark_local(git_remote *remote) git_vector_foreach(&remote->refs, i, head) { /* If we have the object, mark it so we don't ask for it */ - if (git_odb_exists(odb, &head->oid)) + if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid)) head->local = 1; else remote->need_pack = 1; @@ -173,6 +173,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) git_transport *t = remote->transport; remote->need_pack = 0; + remote->nego.depth = opts->unshallow ? INT_MAX : opts->depth; if (filter_wants(remote, opts) < 0) return -1; @@ -181,13 +182,17 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) if (!remote->need_pack) return 0; + if (opts->unshallow && opts->depth > 0) { + git_error_set(GIT_ERROR_INVALID, "options '--depth' and '--unshallow' cannot be used together"); + return -1; + } + /* * Now we have everything set up so we can start tell the * server what we want and what we have. */ remote->nego.refs = (const git_remote_head * const *)remote->refs.contents; remote->nego.count = remote->refs.length; - remote->nego.depth = opts->depth; remote->nego.shallow_roots = git__malloc(sizeof(git_shallowarray)); git_array_init(remote->nego.shallow_roots->array); diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 0d149a6264f..13559ef07bb 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3366,10 +3366,10 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro assert(repo); if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0) - return error; + goto on_error; if ((error = git_filebuf_open(&file, git_str_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0) - return error; + goto on_error; git_array_foreach(roots, idx, oid) { git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); @@ -3378,12 +3378,19 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro git_filebuf_commit(&file); - git_str_dispose(&path); + if ((error = load_grafts(repo)) < 0) { + error = -1; + goto on_error; + } - if (load_grafts(repo) < 0) - return -1; + if (git_array_size(roots) == 0) { + remove(path.ptr); + } - return 0; +on_error: + git_str_dispose(&path); + + return error; } int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index 9d1afeb05f5..b0925c8bb57 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -496,17 +496,35 @@ const git_oid * git_shallowarray_get(git_shallowarray *array, size_t idx) int git_shallowarray_add(git_shallowarray *array, git_oid *oid) { size_t oid_index; + if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, &oid) < 0) { git_oid *tmp = git_array_alloc(array->array); + GIT_ERROR_CHECK_ALLOC(tmp); + git_oid_cpy(tmp, oid); } + return 0; } int git_shallowarray_remove(git_shallowarray *array, git_oid *oid) { - GIT_UNUSED(array); - GIT_UNUSED(oid); - /* no git_array_remove… meh */ - return -1; + git_array_oid_t new_array = GIT_ARRAY_INIT; + git_oid *element; + git_oid *tmp; + size_t i; + + git_array_foreach(array->array, i, element) { + if (git_oid_cmp(oid, element)) { + tmp = git_array_alloc(new_array); + GIT_ERROR_CHECK_ALLOC(tmp); + + git_oid_cpy(tmp, element); + } + } + + git_array_clear(array->array); + array->array = new_array; + + return 0; } diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/clone/shallow.c index 7fb056f9155..2a88d5d057c 100644 --- a/tests/libgit2/clone/shallow.c +++ b/tests/libgit2/clone/shallow.c @@ -131,3 +131,44 @@ void test_clone_shallow__clone_depth_five(void) git_revwalk_free(walk); git_repository_free(repo); } + +void test_clone_shallow__unshallow(void) +{ + git_str path = GIT_STR_INIT; + git_repository *repo; + git_revwalk *walk; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + git_remote *origin = NULL; + git_oid oid; + size_t num_commits = 0; + int error = 0; + + clone_opts.fetch_opts.depth = 5; + clone_opts.remote_cb = remote_single_branch; + + git_str_joinpath(&path, clar_sandbox_path(), "unshallow"); + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + fetch_opts.unshallow = 1; + cl_git_pass(git_remote_lookup(&origin, repo, "origin")); + + cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL)); + cl_assert_equal_b(false, git_repository_is_shallow(repo)); + + git_revwalk_new(&walk, repo); + git_revwalk_push_head(walk); + + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + + cl_assert_equal_i(num_commits, 21); + cl_assert_equal_i(error, GIT_ITEROVER); + + git_remote_free(origin); + git_str_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +} diff --git a/tests/libgit2/transports/smart/shallowarray.c b/tests/libgit2/transports/smart/shallowarray.c new file mode 100644 index 00000000000..c51e62713d3 --- /dev/null +++ b/tests/libgit2/transports/smart/shallowarray.c @@ -0,0 +1,52 @@ +#include "clar_libgit2.h" + +#include "git2/oid.h" +#include "git2/transport.h" + +#include "common.h" +#include "transports/smart.h" +#include "oid.h" + +#include + +#define oid_0 "c070ad8c08840c8116da865b2d65593a6bb9cd2a" +#define oid_1 "0966a434eb1a025db6b71485ab63a3bfbea520b6" +#define oid_2 "83834a7afdaa1a1260568567f6ad90020389f664" + +void test_transports_smart_shallowarray__add_and_remove_oid_from_shallowarray(void) +{ + git_oid oid_0_obj, oid_1_obj, oid_2_obj; + git_shallowarray *shallow_roots = git__malloc(sizeof(git_shallowarray)); + git_array_init(shallow_roots->array); + + git_oid_fromstr(&oid_0_obj, oid_0); + git_oid_fromstr(&oid_1_obj, oid_1); + git_oid_fromstr(&oid_2_obj, oid_2); + + git_shallowarray_add(shallow_roots, &oid_0_obj); + git_shallowarray_add(shallow_roots, &oid_1_obj); + git_shallowarray_add(shallow_roots, &oid_2_obj); + + cl_assert_equal_i(3, shallow_roots->array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&shallow_roots->array.ptr[2])); + + git_shallowarray_remove(shallow_roots, &oid_2_obj); + + cl_assert_equal_i(2, shallow_roots->array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1])); + + git_shallowarray_remove(shallow_roots, &oid_1_obj); + + cl_assert_equal_i(1, shallow_roots->array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); + + git_shallowarray_remove(shallow_roots, &oid_0_obj); + + cl_assert_equal_i(0, shallow_roots->array.size); + + git_array_clear(shallow_roots->array); + git__free(shallow_roots); +} From 49e641be8c5549f6f5731d6d72e9e6902e71d0e1 Mon Sep 17 00:00:00 2001 From: yuangli Date: Thu, 11 Aug 2022 09:32:28 +0100 Subject: [PATCH 063/816] remove unused api --- include/git2/remote.h | 2 +- include/git2/repository.h | 11 ----------- src/libgit2/repository.c | 14 -------------- 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 240e5aa4edf..f1cee17aa97 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -751,7 +751,7 @@ typedef struct { int depth; /** - * Unshallow flag of the fetch to perform. + * Convert a shallow repository to a full repository. * * The default is 0, which means the flag is off. */ diff --git a/include/git2/repository.h b/include/git2/repository.h index d6b054dc30f..258b9ac00a7 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -923,17 +923,6 @@ GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); */ GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); -/** - * Determine the shallow roots of the repository - * - * This oidarray is owned by the library. Do not free it. - * - * @param out An array of shallow oids. - * @param repo The repository - * @return 0 on success, an error otherwise. - */ -GIT_EXTERN(int) git_repository_shallow_roots(git_oidarray *out, git_repository *repo); - /** * Retrieve the configured identity to use for reflogs * diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 13559ef07bb..6b77007aaf2 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3393,20 +3393,6 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro return error; } -int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) -{ - int ret; - git_array_oid_t array = GIT_ARRAY_INIT; - - assert(out); - - ret = git_repository__shallow_roots(&array, repo); - - git_oidarray__from_array(out, &array); - - return ret; -} - int git_repository_is_shallow(git_repository *repo) { git_str path = GIT_STR_INIT; From 8b521f018b734f58db2b9aec184e0f96422f140e Mon Sep 17 00:00:00 2001 From: yuangli Date: Thu, 11 Aug 2022 09:38:21 +0100 Subject: [PATCH 064/816] document unshallow behaviour in fetch.c --- src/libgit2/fetch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index a015cfbd330..3216b261c90 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -60,7 +60,9 @@ static int mark_local(git_remote *remote) return -1; git_vector_foreach(&remote->refs, i, head) { - /* If we have the object, mark it so we don't ask for it */ + /* If we have the object, mark it so we don't ask for it. + However if we are unshallowing, we need to ask for it + even though the head exists locally. */ if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid)) head->local = 1; else From ca0103671f6720c06751b6770269487b9111f661 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Thu, 18 Aug 2022 14:05:42 +0200 Subject: [PATCH 065/816] Extend list of per worktree refs Signed-off-by: Sven Strickroth --- src/libgit2/refdb_fs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 43283b3e472..586d2561ab3 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -403,7 +403,9 @@ static const char *loose_parse_symbolic(git_str *file_content) static bool is_per_worktree_ref(const char *ref_name) { return git__prefixcmp(ref_name, "refs/") != 0 || - git__prefixcmp(ref_name, "refs/bisect/") == 0; + git__prefixcmp(ref_name, "refs/bisect/") == 0 || + git__prefixcmp(ref_name, "refs/worktree/") == 0 || + git__prefixcmp(ref_name, "refs/rewritten/") == 0; } static int loose_lookup( From 4b289c190b6ba434541081d8ca2844c7a03b0384 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Thu, 18 Aug 2022 15:08:23 +0200 Subject: [PATCH 066/816] Make refdb_fs fully aware of per worktree refs Fixes issue isse #5492. Signed-off-by: Sven Strickroth --- src/libgit2/refdb_fs.c | 45 ++++++++++++++++++++++ tests/libgit2/worktree/refs.c | 70 ++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 586d2561ab3..4628e01dc99 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -853,6 +853,8 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) git_str_truncate(&path, ref_prefix_len); git_str_puts(&path, entry->path); ref_name = git_str_cstr(&path); + if (git_repository_is_worktree(backend->repo) == 1 && is_per_worktree_ref(ref_name)) + continue; if (git__suffixcmp(ref_name, ".lock") == 0 || (iter->glob && wildmatch(iter->glob, ref_name, 0) != 0)) @@ -865,6 +867,49 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) error = git_vector_insert(&iter->loose, ref_dup); } + if (!error && git_repository_is_worktree(backend->repo) == 1) { + git_iterator_free(fsit); + git_str_clear(&path); + if ((error = git_str_puts(&path, backend->gitpath)) < 0 || + (error = git_str_put(&path, ref_prefix, ref_prefix_len)) < 0 || + !git_fs_path_exists(git_str_cstr(&path))) { + git_str_dispose(&path); + return error; + } + + if ((error = git_iterator_for_filesystem( + &fsit, path.ptr, &fsit_opts)) < 0) { + git_str_dispose(&path); + return (iter->glob && error == GIT_ENOTFOUND) ? 0 : error; + } + + error = git_str_sets(&path, ref_prefix); + + while (!error && !git_iterator_advance(&entry, fsit)) { + const char *ref_name; + char *ref_dup; + + git_str_truncate(&path, ref_prefix_len); + git_str_puts(&path, entry->path); + ref_name = git_str_cstr(&path); + + if (!is_per_worktree_ref(ref_name)) + continue; + + if (git__suffixcmp(ref_name, ".lock") == 0 || + (iter->glob && + wildmatch(iter->glob, ref_name, 0) != 0)) + continue; + + ref_dup = git_pool_strdup(&iter->pool, ref_name); + if (!ref_dup) + error = -1; + else + error = git_vector_insert( + &iter->loose, ref_dup); + } + } + git_iterator_free(fsit); git_str_dispose(&path); diff --git a/tests/libgit2/worktree/refs.c b/tests/libgit2/worktree/refs.c index 557726aafb6..6bcf7aa9dac 100644 --- a/tests/libgit2/worktree/refs.c +++ b/tests/libgit2/worktree/refs.c @@ -20,7 +20,7 @@ void test_worktree_refs__cleanup(void) cleanup_fixture_worktree(&fixture); } -void test_worktree_refs__list(void) +void test_worktree_refs__list_no_difference_in_worktree(void) { git_strarray refs, wtrefs; unsigned i, j; @@ -61,6 +61,74 @@ void test_worktree_refs__list(void) cl_git_pass(error); } +void test_worktree_refs__list_worktree_specific(void) +{ + git_strarray refs, wtrefs; + git_reference *ref, *new_branch; + int error = 0; + git_oid oid; + + cl_git_pass(git_reference_name_to_id(&oid, fixture.repo, "refs/heads/dir")); + cl_git_fail(git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref")); + cl_git_pass(git_reference_create( + &new_branch, fixture.worktree, "refs/bisect/a-bisect-ref", &oid, + 0, "test")); + + cl_git_fail(git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref")); + cl_git_pass(git_reference_lookup(&ref, fixture.worktree, "refs/bisect/a-bisect-ref")); + + cl_git_pass(git_reference_list(&refs, fixture.repo)); + cl_git_pass(git_reference_list(&wtrefs, fixture.worktree)); + + if (refs.count + 1 != wtrefs.count) { + error = GIT_ERROR; + goto exit; + } + +exit: + git_reference_free(ref); + git_reference_free(new_branch); + git_strarray_dispose(&refs); + git_strarray_dispose(&wtrefs); + cl_git_pass(error); +} + +void test_worktree_refs__list_worktree_specific_hidden_in_main_repo(void) +{ + git_strarray refs, wtrefs; + git_reference *ref, *new_branch; + int error = 0; + git_oid oid; + + cl_git_pass( + git_reference_name_to_id(&oid, fixture.repo, "refs/heads/dir")); + cl_git_fail(git_reference_lookup( + &ref, fixture.worktree, "refs/bisect/a-bisect-ref")); + cl_git_pass(git_reference_create( + &new_branch, fixture.repo, "refs/bisect/a-bisect-ref", &oid, + 0, "test")); + + cl_git_fail(git_reference_lookup( + &ref, fixture.worktree, "refs/bisect/a-bisect-ref")); + cl_git_pass(git_reference_lookup( + &ref, fixture.repo, "refs/bisect/a-bisect-ref")); + + cl_git_pass(git_reference_list(&refs, fixture.repo)); + cl_git_pass(git_reference_list(&wtrefs, fixture.worktree)); + + if (refs.count != wtrefs.count + 1) { + error = GIT_ERROR; + goto exit; + } + +exit: + git_reference_free(ref); + git_reference_free(new_branch); + git_strarray_dispose(&refs); + git_strarray_dispose(&wtrefs); + cl_git_pass(error); +} + void test_worktree_refs__read_head(void) { git_reference *head; From 75b2787091d47f141385c21a1ff2de326da1abed Mon Sep 17 00:00:00 2001 From: Miguel Arroz <750683+arroz@users.noreply.github.com> Date: Tue, 30 Aug 2022 16:55:29 -0700 Subject: [PATCH 067/816] Changed implementation according to review. --- src/libgit2/refdb_fs.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 8a7051dead6..1058a7bd708 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -1769,49 +1769,41 @@ static int refdb_fs_backend__rename( (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0) return error; - /* Try to rename the refog; it's ok if the old doesn't exist */ - /* Must be done before calling refdb_fs_backend__delete, otherwise */ - /* the reflog is deleted before being renamed. */ - error = refdb_reflog_fs__rename(_backend, old_name, new_name); - if ((error != 0) && (error != GIT_ENOTFOUND)) { - git_reference_free(old); - return error; - } - - if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) { - refdb_reflog_fs__rename(_backend, new_name, old_name); + if ((error = loose_lock(&file, backend, old->name)) < 0) { git_reference_free(old); return error; } new = git_reference__realloc(&old, new_name); if (!new) { - refdb_reflog_fs__rename(_backend, new_name, old_name); git_reference_free(old); + git_filebuf_cleanup(&file); return -1; } - if ((error = loose_lock(&file, backend, new->name)) < 0) { - refdb_reflog_fs__rename(_backend, new_name, old_name); + if ((error = refdb_fs_backend__delete_tail(_backend, &file, old_name, NULL, NULL)) < 0) { git_reference_free(new); + git_filebuf_cleanup(&file); return error; } - if ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0) { - git_reference_free(new); - git_filebuf_cleanup(&file); + if ((error = loose_lock(&file, backend, new_name)) < 0) { + git_reference_free(old); return error; } - if (error < 0) { + /* Try to rename the refog; it's ok if the old doesn't exist */ + error = refdb_reflog_fs__rename(_backend, old_name, new_name); + if (((error == 0) || (error == GIT_ENOTFOUND)) && + ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) { git_reference_free(new); git_filebuf_cleanup(&file); return error; } - if ((error = loose_commit(&file, new)) < 0 || out == NULL) { git_reference_free(new); + git_filebuf_cleanup(&file); return error; } From 3e8f4703ca4586d50623b3c6c6404ac69a875f6d Mon Sep 17 00:00:00 2001 From: Miguel Arroz <750683+arroz@users.noreply.github.com> Date: Tue, 30 Aug 2022 17:30:03 -0700 Subject: [PATCH 068/816] Free the correct reference if an error occurrs. It should be the `new` pointer, not the `old` one. --- src/libgit2/refdb_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 1058a7bd708..87b5f875c19 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -1788,7 +1788,7 @@ static int refdb_fs_backend__rename( } if ((error = loose_lock(&file, backend, new_name)) < 0) { - git_reference_free(old); + git_reference_free(new); return error; } From a3bfd284c2d49ef148a7e12fbeb0134b5246b5e6 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 11:09:49 +0100 Subject: [PATCH 069/816] Use GIT_OID_SHA1_HEXSIZE --- src/libgit2/grafts.c | 8 ++++---- src/libgit2/repository.c | 2 +- src/libgit2/transports/smart_pkt.c | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index dd1be34342c..5b078b01db8 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -133,22 +133,22 @@ int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) const char *line_start = parser.line, *line_end = parser.line + parser.line_len; git_oid graft_oid; - if ((error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ)) < 0) { + if ((error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_SHA1_HEXSIZE)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num); goto error; } - line_start += GIT_OID_HEXSZ; + line_start += GIT_OID_SHA1_HEXSIZE; while (line_start < line_end && *line_start == ' ') { git_oid *id = git_array_alloc(parents); GIT_ERROR_CHECK_ALLOC(id); - if ((error = git_oid_fromstrn(id, ++line_start, GIT_OID_HEXSZ)) < 0) { + if ((error = git_oid_fromstrn(id, ++line_start, GIT_OID_SHA1_HEXSIZE)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num); goto error; } - line_start += GIT_OID_HEXSZ; + line_start += GIT_OID_SHA1_HEXSIZE; } if ((error = git_grafts_add(grafts, &graft_oid, parents)) < 0) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 6b77007aaf2..0eb16c22342 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3372,7 +3372,7 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro goto on_error; git_array_foreach(roots, idx, oid) { - git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); + git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_SHA1_HEXSIZE); git_filebuf_write(&file, "\n", 1); } diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 832da450c88..cfdf362444b 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -377,10 +377,10 @@ static int shallow_pkt(git_pkt **out, const char *line, size_t len) line += 7; len -= 7; - if (len >= GIT_OID_HEXSZ) { + if (len >= GIT_OID_SHA1_HEXSIZE) { git_oid_fromstr(&pkt->oid, line + 1); - line += GIT_OID_HEXSZ + 1; - len -= GIT_OID_HEXSZ + 1; + line += GIT_OID_SHA1_HEXSIZE + 1; + len -= GIT_OID_SHA1_HEXSIZE + 1; } *out = (git_pkt *) pkt; @@ -399,10 +399,10 @@ static int unshallow_pkt(git_pkt **out, const char *line, size_t len) line += 9; len -= 9; - if (len >= GIT_OID_HEXSZ) { + if (len >= GIT_OID_SHA1_HEXSIZE) { git_oid_fromstr(&pkt->oid, line + 1); - line += GIT_OID_HEXSZ + 1; - len -= GIT_OID_HEXSZ + 1; + line += GIT_OID_SHA1_HEXSIZE + 1; + len -= GIT_OID_SHA1_HEXSIZE + 1; } *out = (git_pkt *) pkt; @@ -674,12 +674,12 @@ int git_pkt_buffer_wants( /* Tell the server about our shallow objects */ for (i = 0; i < git_shallowarray_count(wants->shallow_roots); i++) { - char oid[GIT_OID_HEXSZ]; + char oid[GIT_OID_SHA1_HEXSIZE]; git_str shallow_buf = GIT_STR_INIT; git_oid_fmt(oid, git_shallowarray_get(wants->shallow_roots, i)); git_str_puts(&shallow_buf, "shallow "); - git_str_put(&shallow_buf, oid, GIT_OID_HEXSZ); + git_str_put(&shallow_buf, oid, GIT_OID_SHA1_HEXSIZE); git_str_putc(&shallow_buf, '\n'); git_str_printf(buf, "%04x%s", (unsigned int)git_str_len(&shallow_buf) + 4, git_str_cstr(&shallow_buf)); From 01cb90be1578b2308f7c69be3b34dd44b0dbbe95 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 14:32:09 +0100 Subject: [PATCH 070/816] restore GIT_RAND_GETENTROPY --- src/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b81ad272f44..14ffa6c4032 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,11 +70,6 @@ check_function_exists(qsort_s GIT_QSORT_S) # random / entropy data -# The flag has been unset to prevent issues -# related to Linux GLIBC version dependency - -# check_function_exists(getentropy GIT_RAND_GETENTROPY) -unset(GIT_RAND_GETENTROPY) check_function_exists(getloadavg GIT_RAND_GETLOADAVG) # determine architecture of the machine From b20f013c129a27a86b5207a2f6ad1d858113f46c Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 14:33:59 +0100 Subject: [PATCH 071/816] restore getentropy --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 14ffa6c4032..e108b2e79ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,6 +70,7 @@ check_function_exists(qsort_s GIT_QSORT_S) # random / entropy data +check_function_exists(getentropy GIT_RAND_GETENTROPY) check_function_exists(getloadavg GIT_RAND_GETLOADAVG) # determine architecture of the machine From f1f9b45dd20b408953eac2d515e8dfa0264aa631 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 15:34:06 +0100 Subject: [PATCH 072/816] fix test failures --- src/libgit2/fetch.c | 6 ++++-- src/libgit2/grafts.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 3216b261c90..69794ed1f3e 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -21,6 +21,7 @@ #include "repository.h" #include "refs.h" #include "transports/smart.h" +#include static int maybe_want(git_remote *remote, git_remote_head *head, git_refspec *tagspec, git_remote_autotag_option_t tagopt) { @@ -175,7 +176,8 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) git_transport *t = remote->transport; remote->need_pack = 0; - remote->nego.depth = opts->unshallow ? INT_MAX : opts->depth; + + remote->nego.depth = (opts && !opts->unshallow) ? opts->depth : INT_MAX; if (filter_wants(remote, opts) < 0) return -1; @@ -184,7 +186,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) if (!remote->need_pack) return 0; - if (opts->unshallow && opts->depth > 0) { + if (opts && opts->unshallow && opts->depth > 0) { git_error_set(GIT_ERROR_INVALID, "options '--depth' and '--unshallow' cannot be used together"); return -1; } diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 5b078b01db8..6662f500901 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -133,7 +133,7 @@ int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) const char *line_start = parser.line, *line_end = parser.line + parser.line_len; git_oid graft_oid; - if ((error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_SHA1_HEXSIZE)) < 0) { + if ((error = git_oid__fromstrn(&graft_oid, line_start, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num); goto error; } @@ -143,7 +143,7 @@ int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) git_oid *id = git_array_alloc(parents); GIT_ERROR_CHECK_ALLOC(id); - if ((error = git_oid_fromstrn(id, ++line_start, GIT_OID_SHA1_HEXSIZE)) < 0) { + if ((error = git_oid__fromstrn(id, ++line_start, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num); goto error; } From 6c46b58e9b284c536168c8b333bbcf50c3431f83 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 15:39:33 +0100 Subject: [PATCH 073/816] include oid.h in grafts.c --- src/libgit2/grafts.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 6662f500901..7cbb1dd7683 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -8,6 +8,7 @@ #include "grafts.h" #include "futils.h" +#include "oid.h" #include "oidarray.h" #include "parse.h" From 4cf19add64e2a705bdf1c87ece4874edef77d290 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 16:02:42 +0100 Subject: [PATCH 074/816] refactor smart_pkt --- src/libgit2/transports/smart_pkt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index cfdf362444b..9e9bda02053 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -378,7 +378,7 @@ static int shallow_pkt(git_pkt **out, const char *line, size_t len) len -= 7; if (len >= GIT_OID_SHA1_HEXSIZE) { - git_oid_fromstr(&pkt->oid, line + 1); + git_oid__fromstr(&pkt->oid, line + 1, GIT_OID_SHA1); line += GIT_OID_SHA1_HEXSIZE + 1; len -= GIT_OID_SHA1_HEXSIZE + 1; } @@ -400,7 +400,7 @@ static int unshallow_pkt(git_pkt **out, const char *line, size_t len) len -= 9; if (len >= GIT_OID_SHA1_HEXSIZE) { - git_oid_fromstr(&pkt->oid, line + 1); + git_oid__fromstr(&pkt->oid, line + 1, GIT_OID_SHA1); line += GIT_OID_SHA1_HEXSIZE + 1; len -= GIT_OID_SHA1_HEXSIZE + 1; } From d0eba8ae58092f0db061e3776f194256d0a56fde Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 17:03:53 +0100 Subject: [PATCH 075/816] fix shallowarray test --- tests/libgit2/transports/smart/shallowarray.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/libgit2/transports/smart/shallowarray.c b/tests/libgit2/transports/smart/shallowarray.c index c51e62713d3..ec4388e42d3 100644 --- a/tests/libgit2/transports/smart/shallowarray.c +++ b/tests/libgit2/transports/smart/shallowarray.c @@ -19,9 +19,9 @@ void test_transports_smart_shallowarray__add_and_remove_oid_from_shallowarray(vo git_shallowarray *shallow_roots = git__malloc(sizeof(git_shallowarray)); git_array_init(shallow_roots->array); - git_oid_fromstr(&oid_0_obj, oid_0); - git_oid_fromstr(&oid_1_obj, oid_1); - git_oid_fromstr(&oid_2_obj, oid_2); + git_oid__fromstr(&oid_0_obj, oid_0, GIT_OID_SHA1); + git_oid__fromstr(&oid_1_obj, oid_1, GIT_OID_SHA1); + git_oid__fromstr(&oid_2_obj, oid_2, GIT_OID_SHA1); git_shallowarray_add(shallow_roots, &oid_0_obj); git_shallowarray_add(shallow_roots, &oid_1_obj); From 89c1b019b7026406834ce0f68a18f255f4b36f99 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Wed, 31 Aug 2022 17:28:27 +0100 Subject: [PATCH 076/816] fix free error --- tests/libgit2/clone/nonetwork.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/libgit2/clone/nonetwork.c b/tests/libgit2/clone/nonetwork.c index eab63363516..0c4e5a87db4 100644 --- a/tests/libgit2/clone/nonetwork.c +++ b/tests/libgit2/clone/nonetwork.c @@ -296,8 +296,6 @@ void test_clone_nonetwork__clone_tag_to_tree(void) cl_git_pass(git_tree_entry_bypath(&tentry, tree, file_path)); git_tree_entry_free(tentry); git_tree_free(tree); - - cl_fixture_cleanup("testrepo.git"); } static void assert_correct_reflog(const char *name) From 34de5c87fb118ffa177bf2e6a023aee72c4f46f7 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 5 Sep 2022 10:38:53 +0100 Subject: [PATCH 077/816] fix seg faults --- tests/libgit2/clone/nonetwork.c | 2 ++ tests/libgit2/clone/shallow.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/libgit2/clone/nonetwork.c b/tests/libgit2/clone/nonetwork.c index 0c4e5a87db4..eab63363516 100644 --- a/tests/libgit2/clone/nonetwork.c +++ b/tests/libgit2/clone/nonetwork.c @@ -296,6 +296,8 @@ void test_clone_nonetwork__clone_tag_to_tree(void) cl_git_pass(git_tree_entry_bypath(&tentry, tree, file_path)); git_tree_entry_free(tentry); git_tree_free(tree); + + cl_fixture_cleanup("testrepo.git"); } static void assert_correct_reflog(const char *name) diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/clone/shallow.c index 2a88d5d057c..b0114081c3e 100644 --- a/tests/libgit2/clone/shallow.c +++ b/tests/libgit2/clone/shallow.c @@ -10,7 +10,7 @@ void test_clone_shallow__initialize(void) void test_clone_shallow__cleanup(void) { git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); - cl_git_sandbox_cleanup(); + /*cl_git_sandbox_cleanup();*/ } static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) From 7122fcd2e4da67905df0d293d0223371b4ffdf01 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 5 Sep 2022 16:24:38 +0100 Subject: [PATCH 078/816] fix depth initialisation --- src/libgit2/fetch.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 69794ed1f3e..df8f0a15484 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -62,8 +62,8 @@ static int mark_local(git_remote *remote) git_vector_foreach(&remote->refs, i, head) { /* If we have the object, mark it so we don't ask for it. - However if we are unshallowing, we need to ask for it - even though the head exists locally. */ + However if we are unshallowing, we need to ask for it + even though the head exists locally. */ if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid)) head->local = 1; else @@ -177,7 +177,10 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) remote->need_pack = 0; - remote->nego.depth = (opts && !opts->unshallow) ? opts->depth : INT_MAX; + if (!opts) + remote->nego.depth = -1; + else + remote->nego.depth = opts->unshallow ? INT_MAX : opts->depth; if (filter_wants(remote, opts) < 0) return -1; From 47f36a937f2ea5c3dc33ed940057134af967b062 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 5 Sep 2022 19:28:29 +0100 Subject: [PATCH 079/816] fix error handling --- src/libgit2/fetch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index df8f0a15484..874813b4e5d 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -219,10 +219,10 @@ int git_fetch_download_pack(git_remote *remote) if (!remote->need_pack) return 0; - if ((error = t->download_pack(t, remote->repo, &remote->stats)) < 0) + if ((error = t->download_pack(t, remote->repo, &remote->stats)) != 0) return error; - if ((error = git_repository__shallow_roots_write(remote->repo, remote->nego.shallow_roots->array)) < 0) + if ((error = git_repository__shallow_roots_write(remote->repo, remote->nego.shallow_roots->array)) != 0) return error; return 0; From d23a7903d107528f9d62608f9b236251d9756b00 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Mon, 5 Sep 2022 19:44:49 +0100 Subject: [PATCH 080/816] remove unused statements --- src/libgit2/fetch.c | 1 - tests/libgit2/clone/shallow.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 874813b4e5d..2a419534ef2 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -21,7 +21,6 @@ #include "repository.h" #include "refs.h" #include "transports/smart.h" -#include static int maybe_want(git_remote *remote, git_remote_head *head, git_refspec *tagspec, git_remote_autotag_option_t tagopt) { diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/clone/shallow.c index b0114081c3e..eacfe1bcfa6 100644 --- a/tests/libgit2/clone/shallow.c +++ b/tests/libgit2/clone/shallow.c @@ -10,7 +10,6 @@ void test_clone_shallow__initialize(void) void test_clone_shallow__cleanup(void) { git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); - /*cl_git_sandbox_cleanup();*/ } static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) From 4f2f91a34f2e66a4511ebf0a650f379bd1c0e41f Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 6 Sep 2022 15:45:07 +0100 Subject: [PATCH 081/816] fix shallow array search --- src/libgit2/transports/smart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index b0925c8bb57..04ee7e74096 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -497,7 +497,7 @@ int git_shallowarray_add(git_shallowarray *array, git_oid *oid) { size_t oid_index; - if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, &oid) < 0) { + if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, oid) < 0) { git_oid *tmp = git_array_alloc(array->array); GIT_ERROR_CHECK_ALLOC(tmp); From a9793ac643a0cd82b00970d0d6e0b67681ec3112 Mon Sep 17 00:00:00 2001 From: Yuang Li Date: Tue, 6 Sep 2022 16:01:52 +0100 Subject: [PATCH 082/816] refactor grafts tests --- tests/libgit2/grafts/basic.c | 10 +++++----- tests/libgit2/grafts/parse.c | 4 ++-- tests/libgit2/grafts/shallow.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/libgit2/grafts/basic.c b/tests/libgit2/grafts/basic.c index 4be4a12bfc2..5ad437b195c 100644 --- a/tests/libgit2/grafts/basic.c +++ b/tests/libgit2/grafts/basic.c @@ -27,10 +27,10 @@ void test_grafts_basic__graft_add(void) cl_git_pass(git_grafts_new(&grafts)); cl_assert(oid1 = git_array_alloc(parents)); - cl_git_pass(git_oid_fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9")); + cl_git_pass(git_oid__fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9", GIT_OID_SHA1)); git_oid_cpy(oid1, &oid_src); - git_oid_fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7"); + git_oid__fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1); cl_git_pass(git_grafts_add(grafts, &oid_src, parents)); git_array_clear(parents); @@ -75,17 +75,17 @@ void test_grafts_basic__grafted_objects(void) git_oid oid; git_commit *commit; - cl_git_pass(git_oid_fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7")); + cl_git_pass(git_oid__fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_assert_equal_i(1, git_commit_parentcount(commit)); git_commit_free(commit); - cl_git_pass(git_oid_fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e")); + cl_git_pass(git_oid__fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_assert_equal_i(1, git_commit_parentcount(commit)); git_commit_free(commit); - cl_git_pass(git_oid_fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade")); + cl_git_pass(git_oid__fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_assert_equal_i(4, git_commit_parentcount(commit)); git_commit_free(commit); diff --git a/tests/libgit2/grafts/parse.c b/tests/libgit2/grafts/parse.c index de110c90110..149b01c8c7b 100644 --- a/tests/libgit2/grafts/parse.c +++ b/tests/libgit2/grafts/parse.c @@ -46,14 +46,14 @@ static void assert_graft_contains(git_grafts *grafts, const char *graft, size_t va_list ap; size_t i = 0; - cl_git_pass(git_oid_fromstr(&oid, graft)); + cl_git_pass(git_oid__fromstr(&oid, graft, GIT_OID_SHA1)); cl_git_pass(git_grafts_get(&commit, grafts, &oid)); cl_assert_equal_oid(&commit->oid, &oid); cl_assert_equal_i(commit->parents.size, n); va_start(ap, n); while (i < n) { - cl_git_pass(git_oid_fromstr(&oid, va_arg(ap, const char *))); + cl_git_pass(git_oid__fromstr(&oid, va_arg(ap, const char *), GIT_OID_SHA1)); cl_assert_equal_oid(&commit->parents.ptr[i], &oid); i++; } diff --git a/tests/libgit2/grafts/shallow.c b/tests/libgit2/grafts/shallow.c index a75b5a0519b..8c272392243 100644 --- a/tests/libgit2/grafts/shallow.c +++ b/tests/libgit2/grafts/shallow.c @@ -20,7 +20,7 @@ void test_grafts_shallow__unset_feature_flag(void) void test_grafts_shallow__initialize(void) { git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1); - cl_git_pass(git_oid_fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); + cl_git_pass(git_oid__fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); } void test_grafts_shallow__cleanup(void) @@ -73,7 +73,7 @@ void test_grafts_shallow__cache_clearing(void) git_grafts *grafts; git_oid tmp_oid; - cl_git_pass(git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000")); + cl_git_pass(git_oid__fromstr(&tmp_oid, "0000000000000000000000000000000000000000", GIT_OID_SHA1)); g_repo = cl_git_sandbox_init("shallow.git"); cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo)); From ecc6f2fb8399d84e5b2bf043376dfc51f43f3e90 Mon Sep 17 00:00:00 2001 From: Russell Sim Date: Fri, 25 Nov 2022 13:35:08 +0100 Subject: [PATCH 083/816] push: support push-options Push options are an optional capability of a git server. If they are listed in the servers capabilities, when the client lists push-options in it's list of capabilities, then the client sends it's list of push options followed by a flush-pkt. So, If we have any declared push options, then we will list it as a client capability, and send the options. If the request contains push options but the server has no push options capability, then error. --- include/git2/remote.h | 5 +++++ include/git2/sys/remote.h | 3 +++ src/libgit2/push.c | 25 +++++++++++++++++++++++++ src/libgit2/push.h | 1 + src/libgit2/remote.c | 7 +++++++ src/libgit2/transports/smart.c | 3 +++ src/libgit2/transports/smart.h | 4 +++- src/libgit2/transports/smart_protocol.c | 19 +++++++++++++++++++ 8 files changed, 66 insertions(+), 1 deletion(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 8c9c26f3fd5..108fcfe716e 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -812,6 +812,11 @@ typedef struct { * Extra headers for this push operation */ git_strarray custom_headers; + + /** + * Push options + */ + git_strarray push_options; } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 diff --git a/include/git2/sys/remote.h b/include/git2/sys/remote.h index 0eae9234deb..07309ab09b6 100644 --- a/include/git2/sys/remote.h +++ b/include/git2/sys/remote.h @@ -26,6 +26,9 @@ typedef enum { /** Remote supports fetching an individual reachable object. */ GIT_REMOTE_CAPABILITY_REACHABLE_OID = (1 << 1), + + /** Remote supports push options. */ + GIT_REMOTE_CAPABILITY_PUSH_OPTIONS = (1 << 2), } git_remote_capability_t; /** diff --git a/src/libgit2/push.c b/src/libgit2/push.c index d477b4f0dc6..b1cbcd4ae10 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -68,6 +68,14 @@ int git_push_new(git_push **out, git_remote *remote, const git_push_options *opt return -1; } + if (git_vector_init(&p->push_options, 0, git__strcmp_cb) < 0) { + git_vector_free(&p->status); + git_vector_free(&p->specs); + git_vector_free(&p->updates); + git__free(p); + return -1; + } + *out = p; return 0; } @@ -472,12 +480,23 @@ static int filter_refs(git_remote *remote) int git_push_finish(git_push *push) { int error; + unsigned int remote_caps; if (!git_remote_connected(push->remote)) { git_error_set(GIT_ERROR_NET, "remote is disconnected"); return -1; } + if ((error = git_remote_capabilities(&remote_caps, push->remote)) < 0){ + git_error_set(GIT_ERROR_INVALID, "remote capabilities not available"); + return -1; + } + + if (git_vector_length(&push->push_options) > 0 && !(remote_caps & GIT_REMOTE_CAPABILITY_PUSH_OPTIONS)) { + git_error_set(GIT_ERROR_INVALID, "push-options not supported by remote"); + return -1; + } + if ((error = filter_refs(push->remote)) < 0 || (error = do_push(push)) < 0) return error; @@ -521,6 +540,7 @@ void git_push_free(git_push *push) push_spec *spec; push_status *status; git_push_update *update; + char *option; unsigned int i; if (push == NULL) @@ -543,6 +563,11 @@ void git_push_free(git_push *push) } git_vector_free(&push->updates); + git_vector_foreach(&push->push_options, i, option) { + git__free(option); + } + git_vector_free(&push->push_options); + git__free(push); } diff --git a/src/libgit2/push.h b/src/libgit2/push.h index fc72e845eee..17c3e2f6845 100644 --- a/src/libgit2/push.h +++ b/src/libgit2/push.h @@ -34,6 +34,7 @@ struct git_push { git_vector specs; git_vector updates; bool report_status; + git_vector push_options; /* report-status */ bool unpack_ok; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 02d271d7d9d..a1be7162906 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2958,6 +2958,13 @@ int git_remote_upload( } } + if (opts && opts->push_options.count > 0) + for (i = 0; i < opts->push_options.count; ++i) { + if ((error = git_vector_insert(&push->push_options, git__strdup(opts->push_options.strings[i]))) < 0) { + goto cleanup; + } + } + if ((error = git_push_finish(push)) < 0) goto cleanup; diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index 7f57dba2a42..4de8a3d78a4 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -233,6 +233,9 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr *capabilities = 0; + if (t->caps.push_options) + *capabilities |= GIT_REMOTE_CAPABILITY_PUSH_OPTIONS; + if (t->caps.want_tip_sha1) *capabilities |= GIT_REMOTE_CAPABILITY_TIP_OID; diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 9323d6c444e..2aea414e940 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -32,6 +32,7 @@ #define GIT_CAP_SYMREF "symref" #define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want" #define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want" +#define GIT_CAP_PUSH_OPTIONS "push-options" extern bool git_smart__ofs_delta_enabled; @@ -132,7 +133,8 @@ typedef struct transport_smart_caps { report_status:1, thin_pack:1, want_tip_sha1:1, - want_reachable_sha1:1; + want_reachable_sha1:1, + push_options:1; } transport_smart_caps; typedef int (*packetsize_cb)(size_t received, void *payload); diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 09778b33575..525053f420e 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -190,6 +190,12 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec continue; } + if (!git__prefixcmp(ptr, GIT_CAP_PUSH_OPTIONS)) { + caps->common = caps->push_options = 1; + ptr += strlen(GIT_CAP_PUSH_OPTIONS); + continue; + } + if (!git__prefixcmp(ptr, GIT_CAP_THIN_PACK)) { caps->common = caps->thin_pack = 1; ptr += strlen(GIT_CAP_THIN_PACK); @@ -642,6 +648,7 @@ int git_smart__download_pack( static int gen_pktline(git_str *buf, git_push *push) { push_spec *spec; + char *option; size_t i, len; char old_id[GIT_OID_SHA1_HEXSIZE+1], new_id[GIT_OID_SHA1_HEXSIZE+1]; @@ -654,6 +661,8 @@ static int gen_pktline(git_str *buf, git_push *push) ++len; /* '\0' */ if (push->report_status) len += strlen(GIT_CAP_REPORT_STATUS) + 1; + if (git_vector_length(&push->push_options) > 0) + len += strlen(GIT_CAP_PUSH_OPTIONS) + 1; len += strlen(GIT_CAP_SIDE_BAND_64K) + 1; } @@ -669,6 +678,10 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_REPORT_STATUS); } + if (git_vector_length(&push->push_options) > 0) { + git_str_putc(buf, ' '); + git_str_printf(buf, GIT_CAP_PUSH_OPTIONS); + } git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_SIDE_BAND_64K); } @@ -676,6 +689,12 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, '\n'); } + if (git_vector_length(&push->push_options) > 0) { + git_str_printf(buf, "0000"); + git_vector_foreach(&push->push_options, i, option) { + git_str_printf(buf, "%04"PRIxZ"%s", strlen(option) + 4 , option); + } + } git_str_puts(buf, "0000"); return git_str_oom(buf) ? -1 : 0; } From c45d1c6e889dd5740970d402eb3642fe8e93e482 Mon Sep 17 00:00:00 2001 From: bansheerubber Date: Tue, 19 Apr 2022 16:23:46 -0700 Subject: [PATCH 084/816] push: implement ci tests We found that the best way to test push options was to receive them via a git hooks script, and output them to a location that the CI tests could read to check and see if the push options were interpreted by git correctly. Co-Authored-By: pireads Co-Authored-By: lotdeef Co-Authored-By: PSI497 <497.psi.497@gmail.com> --- .github/workflows/main.yml | 11 +++ ci/hooks/pre-receive | 2 + ci/test.sh | 46 +++++++++++- tests/libgit2/online/push.c | 144 +++++++++++++++++++++++++++--------- 4 files changed, 168 insertions(+), 35 deletions(-) create mode 100755 ci/hooks/pre-receive diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ec1c828d67c..005d830b3ec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -84,6 +84,17 @@ jobs: strategy: matrix: platform: + - name: "Linux (Focal, Clang, mbedTLS, push-options)" + id: focal-clang-mbedtls + container: + name: focal + env: + CC: clang-10 + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + RUN_PUSH_OPTONS_TESTS: true + SKIP_SSH_TESTS: true + os: ubuntu-latest - name: "Linux (Xenial, GCC, OpenSSL)" id: xenial-gcc-openssl container: diff --git a/ci/hooks/pre-receive b/ci/hooks/pre-receive new file mode 100755 index 00000000000..92be65ce01f --- /dev/null +++ b/ci/hooks/pre-receive @@ -0,0 +1,2 @@ +#!/bin/sh +printf "$GIT_PUSH_OPTION_0$GIT_PUSH_OPTION_1$GIT_PUSH_OPTION_2" > %file% diff --git a/ci/test.sh b/ci/test.sh index 0e1d39e8d4f..63062f07f78 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -e +set -ex if [ -n "$SKIP_TESTS" ]; then exit 0 @@ -106,7 +106,15 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then echo "Starting git daemon (standard)..." GIT_STANDARD_DIR=`mktemp -d ${TMPDIR}/git_standard.XXXXXXXX` git init --bare "${GIT_STANDARD_DIR}/test.git" >/dev/null + git config --file "${GIT_STANDARD_DIR}/test.git/config" receive.advertisePushOptions true + for f in $(ls ${SOURCE_DIR}/ci/hooks) + do + sed "s=%file%=${TMPDIR}/push-option-result-git-daemon=g" "${SOURCE_DIR}/ci/hooks/$f" > "${GIT_STANDARD_DIR}/test.git/hooks/${f}" + chmod +x "$GIT_STANDARD_DIR/test.git/hooks/${f}" + done + git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GIT_STANDARD_DIR}" "${GIT_STANDARD_DIR}" 2>/dev/null & + GIT_STANDARD_PID=$! echo "Starting git daemon (namespace)..." @@ -134,6 +142,14 @@ if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then echo "Starting HTTP server..." HTTP_DIR=`mktemp -d ${TMPDIR}/http.XXXXXXXX` git init --bare "${HTTP_DIR}/test.git" + git config --file "${HTTP_DIR}/test.git/config" receive.advertisePushOptions true + + for f in $(ls ${SOURCE_DIR}/ci/hooks) + do + sed "s=%file%=${TMPDIR}/push-option-result-git-ntlm=g" "${SOURCE_DIR}/ci/hooks/$f" > "${HTTP_DIR}/test.git/hooks/${f}" + chmod +x "$HTTP_DIR/test.git/hooks/${f}" + done + java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${HTTP_DIR}" & HTTP_PID=$! fi @@ -143,6 +159,14 @@ if [ -z "$SKIP_SSH_TESTS" ]; then HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX` SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX` git init --bare "${SSHD_DIR}/test.git" >/dev/null + git config --file "${SSHD_DIR}/test.git/config" receive.advertisePushOptions true + + for f in $(ls ${SOURCE_DIR}/ci/hooks) + do + sed "s=%file%=${TMPDIR}/push-option-result-git-ssh=g" "${SOURCE_DIR}/ci/hooks/$f" > "${SSHD_DIR}/test.git/hooks/${f}" + chmod +x "$SSHD_DIR/test.git/hooks/${f}" + done + cat >"${SSHD_DIR}/sshd_config" <<-EOF Port 2222 ListenAddress 0.0.0.0 @@ -243,8 +267,12 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then echo "Running gitdaemon (standard) tests" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-daemon" + fi export GITTEST_REMOTE_URL="git://localhost/test.git" run_test gitdaemon + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL echo "" @@ -289,10 +317,14 @@ if [ -z "$SKIP_NTLM_TESTS" ]; then echo "Running NTLM tests (IIS emulation)" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" + fi export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" run_test auth_clone_and_push + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS @@ -301,10 +333,14 @@ if [ -z "$SKIP_NTLM_TESTS" ]; then echo "Running NTLM tests (Apache emulation)" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" + fi export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" run_test auth_clone_and_push + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS @@ -354,16 +390,24 @@ if [ -z "$SKIP_SSH_TESTS" ]; then echo "Running ssh tests" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" + fi export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git" run_test ssh + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL echo "" echo "Running ssh tests (scp-style paths)" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" + fi export GITTEST_REMOTE_URL="[localhost:2222]:$SSHD_DIR/test.git" run_test ssh + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index d9208d28a7c..d7dbda3bcad 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -5,6 +5,7 @@ #include "push_util.h" #include "refspec.h" #include "remote.h" +#include "futils.h" static git_repository *_repo; @@ -20,6 +21,8 @@ static char *_remote_ssh_passphrase = NULL; static char *_remote_default = NULL; static char *_remote_expectcontinue = NULL; +static char *_remote_push_options_result = NULL; + static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); static git_remote *_remote; @@ -367,6 +370,7 @@ void test_online_push__initialize(void) _remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE"); _remote_default = cl_getenv("GITTEST_REMOTE_DEFAULT"); _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE"); + _remote_push_options_result = cl_getenv("GITTEST_PUSH_OPTION_RESULT"); _remote = NULL; /* Skip the test if we're missing the remote URL */ @@ -422,6 +426,7 @@ void test_online_push__cleanup(void) git__free(_remote_ssh_passphrase); git__free(_remote_default); git__free(_remote_expectcontinue); + git__free(_remote_push_options_result); /* Freed by cl_git_sandbox_cleanup */ _repo = NULL; @@ -472,7 +477,8 @@ static void do_push( const char *refspecs[], size_t refspecs_len, push_status expected_statuses[], size_t expected_statuses_len, expected_ref expected_refs[], size_t expected_refs_len, - int expected_ret, int check_progress_cb, int check_update_tips_cb) + int expected_ret, int check_progress_cb, int check_update_tips_cb, + git_strarray push_options) { git_push_options opts = GIT_PUSH_OPTIONS_INIT; size_t i; @@ -484,6 +490,9 @@ static void do_push( /* Auto-detect the number of threads to use */ opts.pb_parallelism = 0; + if(push_options.count != 0) + opts.push_options = push_options; + memcpy(&opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks)); data = opts.callbacks.payload; @@ -533,7 +542,8 @@ static void do_push( /* Call push_finish() without ever calling git_push_add_refspec() */ void test_online_push__noop(void) { - do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1); + git_strarray push_options = { 0 }; + do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1, push_options); } void test_online_push__b1(void) @@ -541,9 +551,10 @@ void test_online_push__b1(void) const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats[] = { { "refs/heads/b1", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b2(void) @@ -551,9 +562,10 @@ void test_online_push__b2(void) const char *specs[] = { "refs/heads/b2:refs/heads/b2" }; push_status exp_stats[] = { { "refs/heads/b2", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b2", &_oid_b2 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b3(void) @@ -561,9 +573,10 @@ void test_online_push__b3(void) const char *specs[] = { "refs/heads/b3:refs/heads/b3" }; push_status exp_stats[] = { { "refs/heads/b3", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b3", &_oid_b3 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b4(void) @@ -571,9 +584,10 @@ void test_online_push__b4(void) const char *specs[] = { "refs/heads/b4:refs/heads/b4" }; push_status exp_stats[] = { { "refs/heads/b4", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b4", &_oid_b4 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b5(void) @@ -581,15 +595,17 @@ void test_online_push__b5(void) const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; push_status exp_stats[] = { { "refs/heads/b5", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b5", &_oid_b5 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b5_cancel(void) { const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; - do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1); + git_strarray push_options = { 0 }; + do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1, push_options); } void test_online_push__multi(void) @@ -618,9 +634,10 @@ void test_online_push__multi(void) { "refs/heads/b4", &_oid_b4 }, { "refs/heads/b5", &_oid_b5 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); cl_git_pass(git_reflog_read(&log, _repo, "refs/remotes/test/b1")); entry = git_reflog_entry_byindex(log, 0); @@ -645,12 +662,14 @@ void test_online_push__implicit_tgt(void) { "refs/heads/b2", &_oid_b2 } }; + git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + do_push(specs2, ARRAY_SIZE(specs2), exp_stats2, ARRAY_SIZE(exp_stats2), - exp_refs2, ARRAY_SIZE(exp_refs2), 0, 0, 0); + exp_refs2, ARRAY_SIZE(exp_refs2), 0, 0, 0, push_options); } void test_online_push__fast_fwd(void) @@ -670,21 +689,22 @@ void test_online_push__fast_fwd(void) /* Force should have no effect on a fast forward push */ const char *specs_ff_force[] = { "+refs/heads/b6:refs/heads/b1" }; + git_strarray push_options = { 0 }; do_push(specs_init, ARRAY_SIZE(specs_init), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 1, 1); + exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 1, 1, push_options); do_push(specs_ff, ARRAY_SIZE(specs_ff), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); do_push(specs_reset, ARRAY_SIZE(specs_reset), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 0, 0); + exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 0, 0, push_options); do_push(specs_ff_force, ARRAY_SIZE(specs_ff_force), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); } void test_online_push__tag_commit(void) @@ -692,9 +712,10 @@ void test_online_push__tag_commit(void) const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" }; push_status exp_stats[] = { { "refs/tags/tag-commit", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-commit", &_tag_commit } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_tree(void) @@ -702,9 +723,10 @@ void test_online_push__tag_tree(void) const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" }; push_status exp_stats[] = { { "refs/tags/tag-tree", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tree", &_tag_tree } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_blob(void) @@ -712,9 +734,10 @@ void test_online_push__tag_blob(void) const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" }; push_status exp_stats[] = { { "refs/tags/tag-blob", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-blob", &_tag_blob } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_lightweight(void) @@ -722,9 +745,10 @@ void test_online_push__tag_lightweight(void) const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" }; push_status exp_stats[] = { { "refs/tags/tag-lightweight", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-lightweight", &_tag_lightweight } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_to_tag(void) @@ -732,9 +756,10 @@ void test_online_push__tag_to_tag(void) const char *specs[] = { "refs/tags/tag-tag:refs/tags/tag-tag" }; push_status exp_stats[] = { { "refs/tags/tag-tag", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tag", &_tag_tag } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 0, 0); + exp_refs, ARRAY_SIZE(exp_refs), 0, 0, 0, push_options); } void test_online_push__force(void) @@ -749,19 +774,64 @@ void test_online_push__force(void) push_status exp_stats2_force[] = { { "refs/heads/tgt", 1 } }; expected_ref exp_refs2_force[] = { { "refs/heads/tgt", &_oid_b4 } }; + git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); do_push(specs2, ARRAY_SIZE(specs2), NULL, 0, - exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD, 0, 0, push_options); /* Non-fast-forward update with force should pass. */ record_callbacks_data_clear(&_record_cbs_data); do_push(specs2_force, ARRAY_SIZE(specs2_force), exp_stats2_force, ARRAY_SIZE(exp_stats2_force), - exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0, 1, 1); + exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0, 1, 1, push_options); +} + +static void push_option_test(git_strarray push_options, const char *expected_option) +{ + const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; + push_status exp_stats[] = { { "refs/heads/b1", 1 } }; + expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; + git_str push_options_result = GIT_STR_INIT; + + /* Skip the test if we're missing the push options result file */ + if (!_remote_push_options_result) + cl_skip(); + + do_push(specs, ARRAY_SIZE(specs), + exp_stats, ARRAY_SIZE(exp_stats), + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + + if (git_futils_readbuffer(&push_options_result, _remote_push_options_result) < 0) + cl_fail("Failed to read push options result file"); + + cl_assert_equal_strn(expected_option, git_str_cstr(&push_options_result), + strlen(expected_option)); + + git_str_dispose(&push_options_result); +} + +void test_online_push__options(void) +{ + char *push_options_string_args_test_1[1] = { "test_string" }; + git_strarray push_options_test_1 = { push_options_string_args_test_1, 1 }; + + char *push_options_string_args_test_2[2] = { "test_string", "another arg?" }; + git_strarray push_options_test_2 = { push_options_string_args_test_2, 2 }; + + char *push_options_string_args_test_3[1] = { "👨🏿‍💻 but can it do unicode? 🇺🇦" }; + git_strarray push_options_test_3 = { push_options_string_args_test_3, 1 }; + + char *push_options_string_args_test_4[3] = { "\0", "\0", "\0" }; + git_strarray push_options_test_4 = { push_options_string_args_test_4, 3 }; + + push_option_test(push_options_test_1, "test_string"); + push_option_test(push_options_test_2, "test_stringanother arg?"); + push_option_test(push_options_test_3, "👨🏿‍💻 but can it do unicode? 🇺🇦"); + push_option_test(push_options_test_4, "\0\0\0"); } void test_online_push__delete(void) @@ -790,9 +860,10 @@ void test_online_push__delete(void) /* Force has no effect for delete. */ const char *specs_delete_force[] = { "+:refs/heads/tgt1" }; + git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); /* When deleting a non-existent branch, the git client sends zero for both * the old and new commit id. This should succeed on the server with the @@ -802,23 +873,25 @@ void test_online_push__delete(void) */ do_push(specs_del_fake, ARRAY_SIZE(specs_del_fake), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + do_push(specs_del_fake_force, ARRAY_SIZE(specs_del_fake_force), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); /* Delete one of the pushed branches. */ do_push(specs_delete, ARRAY_SIZE(specs_delete), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); /* Re-push branches and retry delete with force. */ do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + do_push(specs_delete_force, ARRAY_SIZE(specs_delete_force), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); } void test_online_push__bad_refspecs(void) @@ -845,15 +918,17 @@ void test_online_push__expressions(void) const char *specs_left_expr[] = { "refs/heads/b2~1:refs/heads/b2" }; /* TODO: Find a more precise way of checking errors than a exit code of -1. */ + git_strarray push_options = { 0 }; do_push(specs_left_expr, ARRAY_SIZE(specs_left_expr), NULL, 0, - NULL, 0, -1, 0, 0); + NULL, 0, -1, 0, 0, push_options); } void test_online_push__notes(void) { git_oid note_oid, *target_oid, expected_oid; git_signature *signature; + git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -869,13 +944,13 @@ void test_online_push__notes(void) do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0); + NULL, 0, 0, 0, 0, push_options); git_signature_free(signature); } @@ -885,6 +960,7 @@ void test_online_push__configured(void) git_oid note_oid, *target_oid, expected_oid; git_signature *signature; git_remote *old_remote; + git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -905,13 +981,13 @@ void test_online_push__configured(void) do_push(NULL, 0, exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0); + NULL, 0, 0, 0, 0, push_options); git_signature_free(signature); } From f487b8478af3e2eb737443b8d3bbd3dbcbef29b2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 16 Feb 2023 12:59:52 +0000 Subject: [PATCH 085/816] actions: simplify execution with composite action --- .github/actions/run-build/action.yml | 45 ++++++++++++++++++++++++ .github/workflows/main.yml | 51 ++++++++-------------------- 2 files changed, 59 insertions(+), 37 deletions(-) create mode 100644 .github/actions/run-build/action.yml diff --git a/.github/actions/run-build/action.yml b/.github/actions/run-build/action.yml new file mode 100644 index 00000000000..41145d3b4f0 --- /dev/null +++ b/.github/actions/run-build/action.yml @@ -0,0 +1,45 @@ +# Run a build step in a container or directly on the Actions runner +name: Run Build Step +description: Run a build step in a container or directly on the Actions runner + +inputs: + command: + description: Command to run + required: true + type: string + container: + description: Optional container to run in + type: string + container-version: + description: Version of the container to run + type: string + +runs: + using: 'composite' + steps: + - run: | + if [ -n "${{ inputs.container }}" ]; then + docker run \ + --rm \ + --user "$(id -u):$(id -g)" \ + -v "$(pwd)/source:/home/libgit2/source" \ + -v "$(pwd)/build:/home/libgit2/build" \ + -w /home/libgit2 \ + -e ASAN_SYMBOLIZER_PATH \ + -e CC \ + -e CFLAGS \ + -e CMAKE_GENERATOR \ + -e CMAKE_OPTIONS \ + -e GITTEST_NEGOTIATE_PASSWORD \ + -e GITTEST_FLAKY_STAT \ + -e PKG_CONFIG_PATH \ + -e SKIP_NEGOTIATE_TESTS \ + -e SKIP_SSH_TESTS \ + -e TSAN_OPTIONS \ + -e UBSAN_OPTIONS \ + ${{ inputs.container-version }} \ + /bin/bash -c "${{ inputs.command }}" + else + ${{ inputs.command }} + fi + shell: bash diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0eedab87a20..9df073915c8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -286,43 +286,20 @@ jobs: docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . working-directory: ${{ env.docker-config-path }} if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - - name: Build and test - run: | - export GITTEST_NEGOTIATE_PASSWORD="${{ secrets.GITTEST_NEGOTIATE_PASSWORD }}" - export GITTEST_GITHUB_SSH_KEY="${{ secrets.GITTEST_GITHUB_SSH_KEY }}" - export GITTEST_GITHUB_SSH_PUBKEY="${{ secrets.GITTEST_GITHUB_SSH_PUBKEY }}" - export GITTEST_GITHUB_SSH_PASSPHRASE="${{ secrets.GITTEST_GITHUB_SSH_PASSPHRASE }}" - export GITTEST_GITHUB_SSH_REMOTE_HOSTKEY="${{ secrets.GITTEST_GITHUB_SSH_REMOTE_HOSTKEY }}" - - if [ -n "${{ matrix.platform.container.name }}" ]; then - mkdir build - docker run \ - --rm \ - --user "$(id -u):$(id -g)" \ - -v "$(pwd)/source:/home/libgit2/source" \ - -v "$(pwd)/build:/home/libgit2/build" \ - -w /home/libgit2 \ - -e ASAN_SYMBOLIZER_PATH \ - -e CC \ - -e CFLAGS \ - -e CMAKE_GENERATOR \ - -e CMAKE_OPTIONS \ - -e GITTEST_NEGOTIATE_PASSWORD \ - -e GITTEST_FLAKY_STAT \ - -e PKG_CONFIG_PATH \ - -e SKIP_NEGOTIATE_TESTS \ - -e SKIP_SSH_TESTS \ - -e TSAN_OPTIONS \ - -e UBSAN_OPTIONS \ - ${{ env.docker-registry-container-sha }} \ - /bin/bash -c "cd build && ../source/ci/build.sh && ../source/ci/test.sh" - else - mkdir build - cd build - ../source/ci/build.sh - ../source/ci/test.sh - fi - shell: bash + - name: Prepare build + run: mkdir build + - name: Build + uses: ./.github/actions/run-build + with: + command: cd build && ../source/ci/build.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + - name: Test + uses: .github/workflows/run-build.yml@ethomson/workflow + with: + command: cd build && ../source/ci/test.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} - name: Upload test results uses: actions/upload-artifact@v3 if: success() || failure() From 14c86fc268398c7b87a5623696b342960a6e650d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 16 Feb 2023 13:02:36 +0000 Subject: [PATCH 086/816] fixup! actions: simplify execution with composite action --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9df073915c8..bcf8e4c17eb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -295,7 +295,7 @@ jobs: container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} - name: Test - uses: .github/workflows/run-build.yml@ethomson/workflow + uses: ./.github/actions/run-build with: command: cd build && ../source/ci/test.sh container: ${{ matrix.platform.container.name }} From 45e95144f399c6894ef8bfeca46c25511c8461a4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 16 Feb 2023 13:04:48 +0000 Subject: [PATCH 087/816] fixup! fixup! actions: simplify execution with composite action --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bcf8e4c17eb..d64c91587de 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -289,13 +289,13 @@ jobs: - name: Prepare build run: mkdir build - name: Build - uses: ./.github/actions/run-build + uses: ./source/.github/actions/run-build with: command: cd build && ../source/ci/build.sh container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} - name: Test - uses: ./.github/actions/run-build + uses: ./source/.github/actions/run-build with: command: cd build && ../source/ci/test.sh container: ${{ matrix.platform.container.name }} From cf754031ce99f13ee8995d4a6e0d1cd6763da982 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Feb 2023 13:10:39 +0000 Subject: [PATCH 088/816] nightly --- .github/workflows/nightly.yml | 43 ++++++++++++----------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5a0b7d12b0b..8e66e65a2ab 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -324,35 +324,20 @@ jobs: run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ env.dockerfile }} . working-directory: ${{ env.docker-config-path }} if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - - name: Build and test - run: | - export GITTEST_NEGOTIATE_PASSWORD="${{ secrets.GITTEST_NEGOTIATE_PASSWORD }}" - - if [ -n "${{ matrix.platform.container.name }}" ]; then - docker run \ - --rm \ - --user libgit2:libgit2 \ - -v "$(pwd)/source:/home/libgit2/source" \ - -w /home/libgit2 \ - -e ASAN_SYMBOLIZER_PATH \ - -e CC \ - -e CFLAGS \ - -e CMAKE_GENERATOR \ - -e CMAKE_OPTIONS \ - -e GITTEST_NEGOTIATE_PASSWORD \ - -e GITTEST_FLAKY_STAT \ - -e PKG_CONFIG_PATH \ - -e SKIP_NEGOTIATE_TESTS \ - -e SKIP_SSH_TESTS \ - -e TSAN_OPTIONS \ - ${{ env.docker-registry-container-sha }} \ - /bin/bash -c "mkdir build && cd build && ../source/ci/build.sh && ../source/ci/test.sh" - else - mkdir build && cd build - ../source/ci/build.sh - ../source/ci/test.sh - fi - shell: bash + - name: Prepare build + run: mkdir build + - name: Build + uses: ./source/.github/actions/run-build + with: + command: cd build && ../source/ci/build.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + - name: Test + uses: ./source/.github/actions/run-build + with: + command: cd build && ../source/ci/test.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} coverity: # Only run scheduled workflows on the main repository; prevents people From 7eb63188e56bc8cc7d211c9482d8483a507c4a15 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Feb 2023 14:33:59 +0000 Subject: [PATCH 089/816] reusable --- .github/workflows/build-containers.yml | 72 ++++++++++++++++++++++++++ .github/workflows/main.yml | 61 +--------------------- 2 files changed, 73 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/build-containers.yml diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml new file mode 100644 index 00000000000..767798bf6d0 --- /dev/null +++ b/.github/workflows/build-containers.yml @@ -0,0 +1,72 @@ +# Generate the containers that we use for builds. +name: Build Containers + +on: + workflow_call: + +env: + docker-registry: ghcr.io + docker-config-path: source/ci/docker + +jobs: + # Build the docker container images that we will use for our Linux + # builds. This will identify the last commit to the repository that + # updated the docker images, and try to download the image tagged with + # that sha. If it does not exist, we'll do a docker build and push + # the image up to GitHub Packages for the actual CI/CD runs. We tag + # with both the sha and "latest" so that the subsequent runs need not + # know the sha. Only do this on CI builds (when the event is a "push") + # because PR builds from forks lack permission to write packages. + containers: + strategy: + matrix: + container: + - name: xenial + - name: bionic + - name: focal + - name: docurium + - name: bionic-x86 + dockerfile: bionic + base: multiarch/ubuntu-core:x86-bionic + qemu: true + - name: bionic-arm32 + dockerfile: bionic + base: multiarch/ubuntu-core:armhf-bionic + qemu: true + - name: bionic-arm64 + dockerfile: bionic + base: multiarch/ubuntu-core:arm64-bionic + qemu: true + - name: centos7 + - name: centos8 + runs-on: ubuntu-latest + name: "Create container: ${{ matrix.container.name }}" + steps: + - name: Check out repository + uses: actions/checkout@v3 + with: + path: source + fetch-depth: 0 + if: github.event_name != 'pull_request' + - name: Setup QEMU + run: docker run --rm --privileged multiarch/qemu-user-static:register --reset + if: matrix.container.qemu == true + - name: Download existing container + run: | + "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.container.name }}" "${{ matrix.container.dockerfile }}" + env: + DOCKER_REGISTRY: ${{ env.docker-registry }} + GITHUB_TOKEN: ${{ secrets.github_token }} + working-directory: ${{ env.docker-config-path }} + if: github.event_name != 'pull_request' + - name: Build and publish image + run: | + if [ "${{ matrix.container.base }}" != "" ]; then + BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" + fi + docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . + docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} + docker push ${{ env.docker-registry-container-sha }} + docker push ${{ env.docker-registry-container-latest }} + working-directory: ${{ env.docker-config-path }} + if: github.event_name != 'pull_request' && env.docker-container-exists != 'true' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d64c91587de..d4ea86d1802 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,67 +14,8 @@ env: docker-config-path: source/ci/docker jobs: - # Build the docker container images that we will use for our Linux - # builds. This will identify the last commit to the repository that - # updated the docker images, and try to download the image tagged with - # that sha. If it does not exist, we'll do a docker build and push - # the image up to GitHub Packages for the actual CI/CD runs. We tag - # with both the sha and "latest" so that the subsequent runs need not - # know the sha. Only do this on CI builds (when the event is a "push") - # because PR builds from forks lack permission to write packages. containers: - strategy: - matrix: - container: - - name: xenial - - name: bionic - - name: focal - - name: docurium - - name: bionic-x86 - dockerfile: bionic - base: multiarch/ubuntu-core:x86-bionic - qemu: true - - name: bionic-arm32 - dockerfile: bionic - base: multiarch/ubuntu-core:armhf-bionic - qemu: true - - name: bionic-arm64 - dockerfile: bionic - base: multiarch/ubuntu-core:arm64-bionic - qemu: true - - name: centos7 - - name: centos8 - runs-on: ubuntu-latest - name: "Create container: ${{ matrix.container.name }}" - steps: - - name: Check out repository - uses: actions/checkout@v3 - with: - path: source - fetch-depth: 0 - if: github.event_name != 'pull_request' - - name: Setup QEMU - run: docker run --rm --privileged multiarch/qemu-user-static:register --reset - if: matrix.container.qemu == true - - name: Download existing container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.container.name }}" "${{ matrix.container.dockerfile }}" - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} - if: github.event_name != 'pull_request' - - name: Build and publish image - run: | - if [ "${{ matrix.container.base }}" != "" ]; then - BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" - fi - docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . - docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} - docker push ${{ env.docker-registry-container-sha }} - docker push ${{ env.docker-registry-container-latest }} - working-directory: ${{ env.docker-config-path }} - if: github.event_name != 'pull_request' && env.docker-container-exists != 'true' + uses: ./.github/workflows/build-containers.yml # Run our CI/CD builds. We build a matrix with the various build targets # and their details. Then we build either in a docker container (Linux) From e25f9a9bb85e062aeff3d0713e35dd1ad31962d3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 25 Feb 2023 22:24:10 +0000 Subject: [PATCH 090/816] repo: don't allow repeated extensions If a user attempts to add a custom extension that the system already supports, or that is already in their list of custom extensions, de-dup it. --- src/libgit2/repository.c | 38 +++++++++++++++++++++++++++++++++----- tests/libgit2/core/opts.c | 29 +++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 8c41167a1c0..e16413f763f 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1632,7 +1632,7 @@ static const char *builtin_extensions[] = { "objectformat" }; -static git_vector user_extensions = GIT_VECTOR_INIT; +static git_vector user_extensions = { 0, git__strcmp_cb }; static int check_valid_extension(const git_config_entry *entry, void *payload) { @@ -1773,7 +1773,7 @@ int git_repository__extensions(char ***out, size_t *out_len) char *extension; size_t i, j; - if (git_vector_init(&extensions, 8, NULL) < 0) + if (git_vector_init(&extensions, 8, git__strcmp_cb) < 0) return -1; for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) { @@ -1805,21 +1805,49 @@ int git_repository__extensions(char ***out, size_t *out_len) return -1; } + git_vector_sort(&extensions); + *out = (char **)git_vector_detach(out_len, NULL, &extensions); return 0; } +static int dup_ext_err(void **old, void *extension) +{ + GIT_UNUSED(old); + GIT_UNUSED(extension); + return GIT_EEXISTS; +} + int git_repository__set_extensions(const char **extensions, size_t len) { char *extension; - size_t i; + size_t i, j; + int error; git_repository__free_extensions(); for (i = 0; i < len; i++) { - if ((extension = git__strdup(extensions[i])) == NULL || - git_vector_insert(&user_extensions, extension) < 0) + bool is_builtin = false; + + for (j = 0; j < ARRAY_SIZE(builtin_extensions); j++) { + if (strcmp(builtin_extensions[j], extensions[i]) == 0) { + is_builtin = true; + break; + } + } + + if (is_builtin) + continue; + + if ((extension = git__strdup(extensions[i])) == NULL) return -1; + + if ((error = git_vector_insert_sorted(&user_extensions, extension, dup_ext_err)) < 0) { + git__free(extension); + + if (error != GIT_EEXISTS) + return -1; + } } return 0; diff --git a/tests/libgit2/core/opts.c b/tests/libgit2/core/opts.c index 486ff58c6e7..1aa095adf4c 100644 --- a/tests/libgit2/core/opts.c +++ b/tests/libgit2/core/opts.c @@ -50,9 +50,9 @@ void test_core_opts__extensions_add(void) cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); cl_assert_equal_sz(out.count, 3); - cl_assert_equal_s("noop", out.strings[0]); - cl_assert_equal_s("objectformat", out.strings[1]); - cl_assert_equal_s("foo", out.strings[2]); + cl_assert_equal_s("foo", out.strings[0]); + cl_assert_equal_s("noop", out.strings[1]); + cl_assert_equal_s("objectformat", out.strings[2]); git_strarray_dispose(&out); } @@ -66,9 +66,26 @@ void test_core_opts__extensions_remove(void) cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); cl_assert_equal_sz(out.count, 3); - cl_assert_equal_s("objectformat", out.strings[0]); - cl_assert_equal_s("bar", out.strings[1]); - cl_assert_equal_s("baz", out.strings[2]); + cl_assert_equal_s("bar", out.strings[0]); + cl_assert_equal_s("baz", out.strings[1]); + cl_assert_equal_s("objectformat", out.strings[2]); + + git_strarray_dispose(&out); +} + +void test_core_opts__extensions_uniq(void) +{ + const char *in[] = { "foo", "noop", "bar", "bar", "foo", "objectformat" }; + git_strarray out = { 0 }; + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); + cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); + + cl_assert_equal_sz(out.count, 4); + cl_assert_equal_s("bar", out.strings[0]); + cl_assert_equal_s("foo", out.strings[1]); + cl_assert_equal_s("noop", out.strings[2]); + cl_assert_equal_s("objectformat", out.strings[3]); git_strarray_dispose(&out); } From 5c1d7649100175fef2c74ec66e7cb1e57440d89d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 27 Feb 2023 21:49:13 +0000 Subject: [PATCH 091/816] fs_path: let root run the ownership tests The `git_fs_path_owner_is_current_user` expects the root dir on unix (`/`) to be owned by a non-current user. This makes sense unless root (or euid == 0) is running the tests, which often happens during distro build / packaging scripts. Allow them to run the tests. --- tests/util/path.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/util/path.c b/tests/util/path.c index 2c39e088700..02ec42fcea2 100644 --- a/tests/util/path.c +++ b/tests/util/path.c @@ -2,6 +2,10 @@ #include "futils.h" #include "fs_path.h" +#ifndef GIT_WIN32 +# include +#endif + static char *path_save; void test_path__initialize(void) @@ -757,7 +761,7 @@ void test_path__validate_current_user_ownership(void) cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "c:\\path\\does\\not\\exist")); #else cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "/")); - cl_assert_equal_i(is_cur, 0); + cl_assert_equal_i(is_cur, (geteuid() == 0)); cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "/path/does/not/exist")); #endif From 3770bf6766ade2eae8a7771dde8248322e68f879 Mon Sep 17 00:00:00 2001 From: Yuriy Chernyshov Date: Tue, 28 Feb 2023 19:03:51 +0300 Subject: [PATCH 092/816] Remove unused wditer variable Found this randomly while debugging #6517 --- src/libgit2/index.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 1821f6027f7..195ec1d5a2f 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -3397,7 +3397,6 @@ int git_index_add_all( { int error; git_repository *repo; - git_iterator *wditer = NULL; git_pathspec ps; bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0; @@ -3423,7 +3422,6 @@ int git_index_add_all( git_error_set_after_callback(error); cleanup: - git_iterator_free(wditer); git_pathspec__clear(&ps); return error; From e1e0d77c6f1573ab1e332af3f4c7490059d78e3c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 1 Mar 2023 22:16:31 +0000 Subject: [PATCH 093/816] odb: restore `git_odb_open` `git_odb_open` was erroneously removed during a refactoring; add it back. --- src/libgit2/odb.c | 19 +++++++++++++++++++ tests/libgit2/odb/open.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/libgit2/odb/open.c diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 1a02cbad974..0fc48035af2 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -856,6 +856,25 @@ int git_odb__open( return 0; } +#ifdef GIT_EXPERIMENTAL_SHA256 + +int git_odb_open( + git_odb **out, + const char *objects_dir, + const git_odb_options *opts) +{ + return git_odb__open(out, objects_dir, opts); +} + +#else + +int git_odb_open(git_odb **out, const char *objects_dir) +{ + return git_odb__open(out, objects_dir, NULL); +} + +#endif + int git_odb__set_caps(git_odb *odb, int caps) { if (caps == GIT_ODB_CAP_FROM_OWNER) { diff --git a/tests/libgit2/odb/open.c b/tests/libgit2/odb/open.c new file mode 100644 index 00000000000..395406d0f3c --- /dev/null +++ b/tests/libgit2/odb/open.c @@ -0,0 +1,34 @@ +#include "clar_libgit2.h" + +void test_odb_open__initialize(void) +{ + cl_fixture_sandbox("testrepo.git"); +} + +void test_odb_open__cleanup(void) +{ + cl_fixture_cleanup("testrepo.git"); +} + +void test_odb_open__exists(void) +{ + git_odb *odb; + git_oid one, two; + +#ifdef GIT_EXPERIMENTAL_SHA256 + git_odb_options opts = GIT_ODB_OPTIONS_INIT; + + cl_git_pass(git_odb_open(&odb, "testrepo.git/objects", &opts)); + cl_git_pass(git_oid_fromstr(&one, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_oid_fromstr(&two, "00112233445566778899aabbccddeeff00112233", GIT_OID_SHA1)); +#else + cl_git_pass(git_odb_open(&odb, "testrepo.git/objects")); + cl_git_pass(git_oid_fromstr(&one, "1385f264afb75a56a5bec74243be9b367ba4ca08")); + cl_git_pass(git_oid_fromstr(&two, "00112233445566778899aabbccddeeff00112233")); +#endif + + cl_assert(git_odb_exists(odb, &one)); + cl_assert(!git_odb_exists(odb, &two)); + + git_odb_free(odb); +} From 6fb5ab372366a92ae36aac36e1427158c22f3278 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Mar 2023 00:15:08 +0000 Subject: [PATCH 094/816] index: test `git_index_add_all` with ignored folder Ensure that when all files beneath a directory are ignored that we actually ignore the files. --- tests/libgit2/index/addall.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/libgit2/index/addall.c b/tests/libgit2/index/addall.c index 6f95f6386f4..0d3407d48cb 100644 --- a/tests/libgit2/index/addall.c +++ b/tests/libgit2/index/addall.c @@ -441,6 +441,29 @@ void test_index_addall__callback_filtering(void) git_index_free(index); } +void test_index_addall__handles_ignored_files_in_directory(void) +{ + git_index *index; + + g_repo = cl_git_sandbox_init_new(TEST_DIR); + + cl_git_mkfile(TEST_DIR "/file.foo", "a file"); + cl_git_mkfile(TEST_DIR "/file.bar", "another file"); + cl_must_pass(p_mkdir(TEST_DIR "/folder", 0777)); + cl_git_mkfile(TEST_DIR "/folder/asdf", "yet another file"); + + cl_git_mkfile(TEST_DIR "/.gitignore", "folder/\n"); + + check_status(g_repo, 0, 0, 0, 3, 0, 0, 1, 0); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL)); + + check_status(g_repo, 3, 0, 0, 0, 0, 0, 1, 0); + + git_index_free(index); +} + void test_index_addall__adds_conflicts(void) { git_index *index; From 309befe413d7ab68e8e410d8121af98467620792 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Mar 2023 23:21:23 +0000 Subject: [PATCH 095/816] index: test `git_index_add_all` with force Ensure that when all files beneath a directory are ignored that we add the files when FORCE is specified. --- tests/libgit2/index/addall.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/libgit2/index/addall.c b/tests/libgit2/index/addall.c index 0d3407d48cb..e76b6e81d89 100644 --- a/tests/libgit2/index/addall.c +++ b/tests/libgit2/index/addall.c @@ -464,6 +464,29 @@ void test_index_addall__handles_ignored_files_in_directory(void) git_index_free(index); } +void test_index_addall__force_adds_ignored_directories(void) +{ + git_index *index; + + g_repo = cl_git_sandbox_init_new(TEST_DIR); + + cl_git_mkfile(TEST_DIR "/file.foo", "a file"); + cl_git_mkfile(TEST_DIR "/file.bar", "another file"); + cl_must_pass(p_mkdir(TEST_DIR "/folder", 0777)); + cl_git_mkfile(TEST_DIR "/folder/asdf", "yet another file"); + + cl_git_mkfile(TEST_DIR "/.gitignore", "folder/\n"); + + check_status(g_repo, 0, 0, 0, 3, 0, 0, 1, 0); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_all(index, NULL, GIT_INDEX_ADD_FORCE, NULL, NULL)); + + check_status(g_repo, 4, 0, 0, 0, 0, 0, 0, 0); + + git_index_free(index); +} + void test_index_addall__adds_conflicts(void) { git_index *index; From 129cadf9bf9ef1b43dd844d54f2b57a52b69ed2a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Mar 2023 23:20:45 +0000 Subject: [PATCH 096/816] index: support `git_index_add_all` directories with force When the contents of an entire new directory is ignored, and `FORCE` is specified to `git_index_add_all`, ensure that we expand the entire file list. By default, diff will coalesce a fully ignored folder into a single diff entry; expand it. --- src/libgit2/index.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 195ec1d5a2f..d4532c005d0 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -3509,7 +3509,8 @@ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarr GIT_DIFF_RECURSE_UNTRACKED_DIRS; if (flags == GIT_INDEX_ADD_FORCE) - opts.flags |= GIT_DIFF_INCLUDE_IGNORED; + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | + GIT_DIFF_RECURSE_IGNORED_DIRS; } if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0) From 462dbe21d0edc3817d53900702e68d666c303600 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 15 Feb 2023 10:26:50 +0000 Subject: [PATCH 097/816] xdiff: move xdiff to 'deps' xdiff is a dependency (from git core) and more properly belongs in the 'deps' directory. Move it there, and add a stub for cmake to resolve xdiff from the system location in the future. (At present, bundled xdiff remains hardcoded.) --- CMakeLists.txt | 1 + cmake/SelectXdiff.cmake | 9 ++++++++ deps/xdiff/CMakeLists.txt | 28 ++++++++++++++++++++++++ {src/libgit2 => deps}/xdiff/git-xdiff.h | 0 {src/libgit2 => deps}/xdiff/xdiff.h | 0 {src/libgit2 => deps}/xdiff/xdiffi.c | 0 {src/libgit2 => deps}/xdiff/xdiffi.h | 0 {src/libgit2 => deps}/xdiff/xemit.c | 0 {src/libgit2 => deps}/xdiff/xemit.h | 0 {src/libgit2 => deps}/xdiff/xhistogram.c | 0 {src/libgit2 => deps}/xdiff/xinclude.h | 0 {src/libgit2 => deps}/xdiff/xmacros.h | 0 {src/libgit2 => deps}/xdiff/xmerge.c | 0 {src/libgit2 => deps}/xdiff/xpatience.c | 0 {src/libgit2 => deps}/xdiff/xprepare.c | 0 {src/libgit2 => deps}/xdiff/xprepare.h | 0 {src/libgit2 => deps}/xdiff/xtypes.h | 0 {src/libgit2 => deps}/xdiff/xutils.c | 0 {src/libgit2 => deps}/xdiff/xutils.h | 0 src/CMakeLists.txt | 1 + src/libgit2/CMakeLists.txt | 20 +---------------- src/libgit2/blame_git.c | 1 - src/libgit2/diff_xdiff.h | 2 +- src/libgit2/merge_file.c | 2 -- 24 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 cmake/SelectXdiff.cmake create mode 100644 deps/xdiff/CMakeLists.txt rename {src/libgit2 => deps}/xdiff/git-xdiff.h (100%) rename {src/libgit2 => deps}/xdiff/xdiff.h (100%) rename {src/libgit2 => deps}/xdiff/xdiffi.c (100%) rename {src/libgit2 => deps}/xdiff/xdiffi.h (100%) rename {src/libgit2 => deps}/xdiff/xemit.c (100%) rename {src/libgit2 => deps}/xdiff/xemit.h (100%) rename {src/libgit2 => deps}/xdiff/xhistogram.c (100%) rename {src/libgit2 => deps}/xdiff/xinclude.h (100%) rename {src/libgit2 => deps}/xdiff/xmacros.h (100%) rename {src/libgit2 => deps}/xdiff/xmerge.c (100%) rename {src/libgit2 => deps}/xdiff/xpatience.c (100%) rename {src/libgit2 => deps}/xdiff/xprepare.c (100%) rename {src/libgit2 => deps}/xdiff/xprepare.h (100%) rename {src/libgit2 => deps}/xdiff/xtypes.h (100%) rename {src/libgit2 => deps}/xdiff/xutils.c (100%) rename {src/libgit2 => deps}/xdiff/xutils.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 710915da1bd..fc31faecaf5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON option(USE_SHA256 "Enable SHA256. Can be set to HTTPS/Builtin" ON) option(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) set(USE_HTTP_PARSER "" CACHE STRING "Specifies the HTTP Parser implementation; either system or builtin.") +# set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") set(REGEX_BACKEND "" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") option(USE_BUNDLED_ZLIB "Use the bundled version of zlib. Can be set to one of Bundled(ON)/Chromium. The Chromium option requires a x86_64 processor with SSE4.2 and CLMUL" OFF) diff --git a/cmake/SelectXdiff.cmake b/cmake/SelectXdiff.cmake new file mode 100644 index 00000000000..9ab9f3f4f29 --- /dev/null +++ b/cmake/SelectXdiff.cmake @@ -0,0 +1,9 @@ +# Optional external dependency: xdiff +if(USE_XDIFF STREQUAL "system") + message(FATAL_ERROR "external/system xdiff is not yet supported") +else() + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/xdiff" "${PROJECT_BINARY_DIR}/deps/xdiff") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/xdiff") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") + add_feature_info(xdiff ON "xdiff support (bundled)") +endif() diff --git a/deps/xdiff/CMakeLists.txt b/deps/xdiff/CMakeLists.txt new file mode 100644 index 00000000000..743ac636f0a --- /dev/null +++ b/deps/xdiff/CMakeLists.txt @@ -0,0 +1,28 @@ + +file(GLOB SRC_XDIFF "*.c" "*.h") +list(SORT SRC_XDIFF) + +add_library(xdiff OBJECT ${SRC_XDIFF}) +target_include_directories(xdiff SYSTEM PRIVATE + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_SOURCE_DIR}/src/util" + "${PROJECT_BINARY_DIR}/src/util" + ${LIBGIT2_SYSTEM_INCLUDES} + ${LIBGIT2_DEPENDENCY_INCLUDES}) + +# the xdiff dependency is not (yet) warning-free, disable warnings +# as errors for the xdiff sources until we've sorted them out +if(MSVC) + set_source_files_properties(xdiffi.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xemit.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xhistogram.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xmerge.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xutils.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xpatience.c PROPERTIES COMPILE_FLAGS -WX-) +else() + set_source_files_properties(xdiffi.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") + set_source_files_properties(xemit.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") + set_source_files_properties(xhistogram.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") + set_source_files_properties(xutils.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") + set_source_files_properties(xpatience.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") +endif() diff --git a/src/libgit2/xdiff/git-xdiff.h b/deps/xdiff/git-xdiff.h similarity index 100% rename from src/libgit2/xdiff/git-xdiff.h rename to deps/xdiff/git-xdiff.h diff --git a/src/libgit2/xdiff/xdiff.h b/deps/xdiff/xdiff.h similarity index 100% rename from src/libgit2/xdiff/xdiff.h rename to deps/xdiff/xdiff.h diff --git a/src/libgit2/xdiff/xdiffi.c b/deps/xdiff/xdiffi.c similarity index 100% rename from src/libgit2/xdiff/xdiffi.c rename to deps/xdiff/xdiffi.c diff --git a/src/libgit2/xdiff/xdiffi.h b/deps/xdiff/xdiffi.h similarity index 100% rename from src/libgit2/xdiff/xdiffi.h rename to deps/xdiff/xdiffi.h diff --git a/src/libgit2/xdiff/xemit.c b/deps/xdiff/xemit.c similarity index 100% rename from src/libgit2/xdiff/xemit.c rename to deps/xdiff/xemit.c diff --git a/src/libgit2/xdiff/xemit.h b/deps/xdiff/xemit.h similarity index 100% rename from src/libgit2/xdiff/xemit.h rename to deps/xdiff/xemit.h diff --git a/src/libgit2/xdiff/xhistogram.c b/deps/xdiff/xhistogram.c similarity index 100% rename from src/libgit2/xdiff/xhistogram.c rename to deps/xdiff/xhistogram.c diff --git a/src/libgit2/xdiff/xinclude.h b/deps/xdiff/xinclude.h similarity index 100% rename from src/libgit2/xdiff/xinclude.h rename to deps/xdiff/xinclude.h diff --git a/src/libgit2/xdiff/xmacros.h b/deps/xdiff/xmacros.h similarity index 100% rename from src/libgit2/xdiff/xmacros.h rename to deps/xdiff/xmacros.h diff --git a/src/libgit2/xdiff/xmerge.c b/deps/xdiff/xmerge.c similarity index 100% rename from src/libgit2/xdiff/xmerge.c rename to deps/xdiff/xmerge.c diff --git a/src/libgit2/xdiff/xpatience.c b/deps/xdiff/xpatience.c similarity index 100% rename from src/libgit2/xdiff/xpatience.c rename to deps/xdiff/xpatience.c diff --git a/src/libgit2/xdiff/xprepare.c b/deps/xdiff/xprepare.c similarity index 100% rename from src/libgit2/xdiff/xprepare.c rename to deps/xdiff/xprepare.c diff --git a/src/libgit2/xdiff/xprepare.h b/deps/xdiff/xprepare.h similarity index 100% rename from src/libgit2/xdiff/xprepare.h rename to deps/xdiff/xprepare.h diff --git a/src/libgit2/xdiff/xtypes.h b/deps/xdiff/xtypes.h similarity index 100% rename from src/libgit2/xdiff/xtypes.h rename to deps/xdiff/xtypes.h diff --git a/src/libgit2/xdiff/xutils.c b/deps/xdiff/xutils.c similarity index 100% rename from src/libgit2/xdiff/xutils.c rename to deps/xdiff/xutils.c diff --git a/src/libgit2/xdiff/xutils.h b/deps/xdiff/xutils.h similarity index 100% rename from src/libgit2/xdiff/xutils.h rename to deps/xdiff/xutils.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e108b2e79ce..e14bd36c2a3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,7 @@ include(SelectHTTPSBackend) include(SelectHashes) include(SelectHTTPParser) include(SelectRegex) +include(SelectXdiff) include(SelectSSH) include(SelectWinHTTP) include(SelectZlib) diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index 03b57121291..5c453aab9b0 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -25,8 +25,7 @@ target_sources(libgit2 PRIVATE ${SRC_H}) file(GLOB SRC_GIT2 *.c *.h streams/*.c streams/*.h - transports/*.c transports/*.h - xdiff/*.c xdiff/*.h) + transports/*.c transports/*.h) list(SORT SRC_GIT2) target_sources(libgit2 PRIVATE ${SRC_GIT2}) @@ -40,23 +39,6 @@ if(APPLE) set_source_files_properties(streams/stransport.c PROPERTIES COMPILE_FLAGS -Wno-deprecated) endif() -# the xdiff dependency is not (yet) warning-free, disable warnings -# as errors for the xdiff sources until we've sorted them out -if(MSVC) - set_source_files_properties(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xemit.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xmerge.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xutils.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xpatience.c PROPERTIES COMPILE_FLAGS -WX-) -else() - set_source_files_properties(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") - set_source_files_properties(xdiff/xemit.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") - set_source_files_properties(xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") - set_source_files_properties(xdiff/xutils.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") - set_source_files_properties(xdiff/xpatience.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") -endif() - ide_split_sources(libgit2) list(APPEND LIBGIT2_OBJECTS $ $ ${LIBGIT2_DEPENDENCY_OBJECTS}) list(APPEND LIBGIT2_INCLUDES ${LIBGIT2_DEPENDENCY_INCLUDES}) diff --git a/src/libgit2/blame_git.c b/src/libgit2/blame_git.c index 2504b338ac5..69897b3860c 100644 --- a/src/libgit2/blame_git.c +++ b/src/libgit2/blame_git.c @@ -9,7 +9,6 @@ #include "commit.h" #include "blob.h" -#include "xdiff/xinclude.h" #include "diff_xdiff.h" /* diff --git a/src/libgit2/diff_xdiff.h b/src/libgit2/diff_xdiff.h index 9b303e9dc45..327dc7c4ab3 100644 --- a/src/libgit2/diff_xdiff.h +++ b/src/libgit2/diff_xdiff.h @@ -10,7 +10,7 @@ #include "common.h" #include "diff.h" -#include "xdiff/xdiff.h" +#include "xdiff.h" #include "patch_generate.h" /* xdiff cannot cope with large files. these files should not be passed to diff --git a/src/libgit2/merge_file.c b/src/libgit2/merge_file.c index 732a047b1c9..ffe83cf2a3b 100644 --- a/src/libgit2/merge_file.c +++ b/src/libgit2/merge_file.c @@ -19,8 +19,6 @@ #include "git2/index.h" #include "git2/merge.h" -#include "xdiff/xdiff.h" - /* only examine the first 8000 bytes for binaryness. * https://github.com/git/git/blob/77bd3ea9f54f1584147b594abc04c26ca516d987/xdiff-interface.c#L197 */ From 20811c5aa9c528405eaa3f88ff22a9adebafa9e6 Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Wed, 8 Mar 2023 14:00:52 +0100 Subject: [PATCH 098/816] sysdir: Do not declare win32 functions on non-win32 platforms These declaration poses problems on some embedded or retro Linux systems that deliberately disable support for wchar_t from their libc. --- src/libgit2/sysdir.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libgit2/sysdir.h b/src/libgit2/sysdir.h index 1d15bbf43dd..03f59e1de81 100644 --- a/src/libgit2/sysdir.h +++ b/src/libgit2/sysdir.h @@ -134,10 +134,12 @@ extern int git_sysdir_set(git_sysdir_t which, const char *paths); */ extern int git_sysdir_reset(void); +#ifdef GIT_WIN32 /** Sets the registry system dir to a mock; for testing. */ extern int git_win32__set_registry_system_dir(const wchar_t *mock_sysdir); /** Find the given system dir; for testing. */ extern int git_win32__find_system_dirs(git_str *out, const char *subdir); +#endif #endif From 1cc2979a71ba042c20ea3e18484d4a50c4fdf10d Mon Sep 17 00:00:00 2001 From: lmcglash Date: Fri, 10 Mar 2023 08:56:49 +0000 Subject: [PATCH 099/816] Fix merge error --- src/libgit2/commit.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 017c603037e..a7d83111509 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -517,6 +517,18 @@ int git_commit__parse( return git_commit__parse_ext(commit, odb_obj, &parse_options); } +int git_commit__parse_raw( + void *commit, + const char *data, + size_t size, + git_oid_t oid_type) +{ + git_commit__parse_options parse_options = {0}; + parse_options.oid_type = oid_type; + + return commit_parse(commit, data, size, &parse_options); +} + static int assign_commit_parents_from_graft(git_commit *commit, git_commit_graft *graft) { size_t idx; git_oid *oid; @@ -533,14 +545,17 @@ static int assign_commit_parents_from_graft(git_commit *commit, git_commit_graft return 0; } -int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) +int git_commit__parse_ext( + git_commit *commit, + git_odb_object *odb_obj, + git_commit__parse_options *parse_opts) { git_repository *repo = git_object_owner((git_object *)commit); git_commit_graft *graft; int error; if ((error = commit_parse(commit, git_odb_object_data(odb_obj), - git_odb_object_size(odb_obj), flags)) < 0) + git_odb_object_size(odb_obj), parse_opts)) < 0) return error; if (!git_shallow__enabled) @@ -554,30 +569,6 @@ int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned return assign_commit_parents_from_graft(commit, graft); } -int git_commit__parse_raw( - void *commit, - const char *data, - size_t size, - git_oid_t oid_type) -{ - git_commit__parse_options parse_options = {0}; - parse_options.oid_type = oid_type; - - return commit_parse(commit, data, size, &parse_options); -} - -int git_commit__parse_ext( - git_commit *commit, - git_odb_object *odb_obj, - git_commit__parse_options *parse_opts) -{ - return commit_parse( - commit, - git_odb_object_data(odb_obj), - git_odb_object_size(odb_obj), - parse_opts); -} - #define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \ _rvalue git_commit_##_name(const git_commit *commit) \ {\ From 2da3e8c16629cee9736965556a50dc7502e1dec7 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Fri, 10 Mar 2023 09:06:26 +0000 Subject: [PATCH 100/816] Remove stray comma --- src/libgit2/transports/smart.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 15b6c9a0aba..8e06d03ef6e 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -54,7 +54,7 @@ typedef enum { GIT_PKT_NG, GIT_PKT_UNPACK, GIT_PKT_SHALLOW, - GIT_PKT_UNSHALLOW, + GIT_PKT_UNSHALLOW } git_pkt_type; /* Used for multi_ack and multi_ack_detailed */ @@ -144,7 +144,7 @@ typedef struct transport_smart_caps { thin_pack:1, want_tip_sha1:1, want_reachable_sha1:1, - shallow:1; + shallow:1; char *object_format; char *agent; } transport_smart_caps; From d935773743f8f0ed50027bfe3b66133174610cc9 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Fri, 10 Mar 2023 09:30:02 +0000 Subject: [PATCH 101/816] Remove unused git_transport_flags_t --- include/git2/sys/transport.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 8a84515928b..062bcd0edf1 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -25,15 +25,6 @@ GIT_BEGIN_DECL -/** - * Flags to pass to transport - * - * Currently unused. - */ -typedef enum { - GIT_TRANSPORTFLAGS_NONE = 0, -} git_transport_flags_t; - typedef struct git_shallowarray git_shallowarray; typedef struct { From 79ed94e0f86daae2d839f89789952f0e99eef32a Mon Sep 17 00:00:00 2001 From: Laurence McGlashan Date: Fri, 10 Mar 2023 09:30:29 +0000 Subject: [PATCH 102/816] Apply suggestions from code review Co-authored-by: Qix --- include/git2/remote.h | 4 ++-- src/libgit2/transports/smart_protocol.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index f1cee17aa97..9e4043f87bd 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -744,9 +744,9 @@ typedef struct { git_proxy_options proxy_opts; /** - * Depth of the fetch to perform, has to be a positive integer. + * Depth of the fetch to perform. Depth <= 0 fetches the full history. * - * The default is -1, which will fetch the full history. + * The default is -1. */ int depth; diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 2ec3901019e..c37c3cc8dcb 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -359,7 +359,7 @@ static int cap_not_sup_err(const char *cap_name) /* Disables server capabilities we're not interested in */ static int setup_caps(transport_smart_caps *caps, const git_fetch_negotiation *wants) { - if (wants->depth) { + if (wants->depth > 0) { if (!caps->shallow) return cap_not_sup_err(GIT_CAP_SHALLOW); } else { From 5b711335603b6d6abe6ae9bf09f570ada66232ef Mon Sep 17 00:00:00 2001 From: Laurence McGlashan Date: Fri, 10 Mar 2023 09:32:33 +0000 Subject: [PATCH 103/816] Update src/libgit2/fetch.c Co-authored-by: Qix --- src/libgit2/fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 3a574e857d7..6bf16bc0f12 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -195,7 +195,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) */ remote->nego.refs = (const git_remote_head * const *)remote->refs.contents; remote->nego.count = remote->refs.length; - remote->nego.shallow_roots = git__malloc(sizeof(git_shallowarray)); + remote->nego.shallow_roots = git__malloc(sizeof(*remote->nego.shallow_roots)); git_array_init(remote->nego.shallow_roots->array); From cbc5c6adfa8e0988b323d226c0439fe74e94bed6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 10 Mar 2023 22:45:24 +0000 Subject: [PATCH 104/816] cmake: don't include `include/git2` Including the `include/git2` build path is a seemingly unnecessary oversight to include the generated `experimental.h` file. --- src/cli/CMakeLists.txt | 1 - src/libgit2/CMakeLists.txt | 1 - src/util/CMakeLists.txt | 1 - 3 files changed, 3 deletions(-) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index ac1659c17fe..84b6c190151 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -1,7 +1,6 @@ set(CLI_INCLUDES "${libgit2_BINARY_DIR}/src/util" "${libgit2_BINARY_DIR}/include" - "${libgit2_BINARY_DIR}/include/git2" "${libgit2_SOURCE_DIR}/src/util" "${libgit2_SOURCE_DIR}/src/cli" "${libgit2_SOURCE_DIR}/include" diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index 03b57121291..dcb4279c1ef 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -10,7 +10,6 @@ include(PkgBuildConfig) set(LIBGIT2_INCLUDES "${PROJECT_BINARY_DIR}/src/util" "${PROJECT_BINARY_DIR}/include" - "${PROJECT_BINARY_DIR}/include/git2" "${PROJECT_SOURCE_DIR}/src/libgit2" "${PROJECT_SOURCE_DIR}/src/util" "${PROJECT_SOURCE_DIR}/include") diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 2207041ef1a..ee35eb9610e 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -9,7 +9,6 @@ configure_file(git2_features.h.in git2_features.h) set(UTIL_INCLUDES "${PROJECT_BINARY_DIR}/src/util" "${PROJECT_BINARY_DIR}/include" - "${PROJECT_BINARY_DIR}/include/git2" "${PROJECT_SOURCE_DIR}/src/util" "${PROJECT_SOURCE_DIR}/include") From e288f874a3a73ef31f88bb524f6d25d5ff3c5a3a Mon Sep 17 00:00:00 2001 From: lmcglash Date: Mon, 13 Mar 2023 08:46:59 +0000 Subject: [PATCH 105/816] Remove unnecessary include. --- include/git2/repository.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 0de4d755729..560e70ab6df 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -11,7 +11,6 @@ #include "types.h" #include "oid.h" #include "buffer.h" -#include "oidarray.h" /** * @file git2/repository.h From 62b9f803575d261348508c449f8e1698beebb115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 14 Mar 2023 15:51:50 +0100 Subject: [PATCH 106/816] pack: use 64 bits for the number of objects Keeping it as a 32-bit value means the min size calculation overflows or gets truncated which can lead to issues with large packfiles. --- src/libgit2/pack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index c3080184449..6e99d4b71f9 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -200,7 +200,8 @@ static void pack_index_free(struct git_pack_file *p) static int pack_index_check_locked(const char *path, struct git_pack_file *p) { struct git_pack_idx_header *hdr; - uint32_t version, nr, i, *index; + uint32_t version, i, *index; + uint64_t nr = 0; void *idx_map; size_t idx_size; struct stat st; @@ -246,7 +247,6 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) version = 1; } - nr = 0; index = idx_map; if (version > 1) @@ -287,8 +287,8 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) * variable sized table containing 8-byte entries * for offsets larger than 2^31. */ - unsigned long min_size = 8 + (4 * 256) + (nr * (p->oid_size + 4 + 4)) + (p->oid_size * 2); - unsigned long max_size = min_size; + uint64_t min_size = 8 + (4 * 256) + (nr * (p->oid_size + 4 + 4)) + (p->oid_size * 2); + uint64_t max_size = min_size; if (nr) max_size += (nr - 1)*8; From 1d57344cdf51fe4e610615d9a25eb591a4dacaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 16 Mar 2023 09:21:37 +0100 Subject: [PATCH 107/816] pack: cast to uint64_t when calculating index size instead It is a bit too hidden why we want 64 bits when we're assigning to a 32-bit integer later on to store the number of objects, so go back to uint32_t and cast to uint64_t during the size calculation. --- src/libgit2/pack.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index 6e99d4b71f9..d59973aa937 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -200,8 +200,7 @@ static void pack_index_free(struct git_pack_file *p) static int pack_index_check_locked(const char *path, struct git_pack_file *p) { struct git_pack_idx_header *hdr; - uint32_t version, i, *index; - uint64_t nr = 0; + uint32_t version, nr = 0, i, *index; void *idx_map; size_t idx_size; struct stat st; @@ -269,7 +268,7 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) * - 20/32-byte SHA of the packfile * - 20/32-byte SHA file checksum */ - if (idx_size != (4 * 256 + (nr * (p->oid_size + 4)) + (p->oid_size * 2))) { + if (idx_size != (4 * 256 + ((uint64_t) nr * (p->oid_size + 4)) + (p->oid_size * 2))) { git_futils_mmap_free(&p->index_map); return packfile_error("index is corrupted"); } @@ -287,7 +286,7 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) * variable sized table containing 8-byte entries * for offsets larger than 2^31. */ - uint64_t min_size = 8 + (4 * 256) + (nr * (p->oid_size + 4 + 4)) + (p->oid_size * 2); + uint64_t min_size = 8 + (4 * 256) + ((uint64_t)nr * (p->oid_size + 4 + 4)) + (p->oid_size * 2); uint64_t max_size = min_size; if (nr) From f68f542eb63efb0f50e00d2376196f5bd48ed41e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 6 Mar 2023 15:19:29 -0800 Subject: [PATCH 108/816] http: introduce schannel streams for windows Provide a stream interface for Schannel - the native crypto APIs - on Windows. This allows Windows to use the same HTTP transport that all the other platforms use, with its own native crypto. Ultimately this allows us to deprecate WinHTTP and we need not add support for our socket changes in two places (our HTTP stack and the WinHTTP stack). --- .github/workflows/main.yml | 12 +- .github/workflows/nightly.yml | 36 +- CMakeLists.txt | 6 - cmake/SelectHTTPSBackend.cmake | 23 +- cmake/SelectHashes.cmake | 4 + cmake/SelectWinHTTP.cmake | 17 - src/CMakeLists.txt | 1 - src/libgit2/libgit2.c | 2 + src/libgit2/streams/schannel.c | 715 ++++++++++++++++++++++++++++ src/libgit2/streams/schannel.h | 28 ++ src/libgit2/streams/socket.c | 88 ++-- src/libgit2/streams/socket.h | 2 + src/libgit2/streams/tls.c | 5 + src/util/git2_features.h.in | 1 + tests/libgit2/online/clone.c | 13 +- tests/libgit2/stream/registration.c | 6 +- 16 files changed, 879 insertions(+), 80 deletions(-) delete mode 100644 cmake/SelectWinHTTP.cmake create mode 100644 src/libgit2/streams/schannel.c create mode 100644 src/libgit2/streams/schannel.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0eedab87a20..cdcea1644a5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -130,19 +130,19 @@ jobs: SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true setup-script: osx - - name: "Windows (amd64, Visual Studio)" + - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs os: windows-2019 setup-script: win32 env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, Visual Studio)" + - name: "Windows (x86, Visual Studio, WinHTTP)" id: windows-x86-vs os: windows-2019 setup-script: win32 @@ -154,7 +154,7 @@ jobs: BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (amd64, mingw)" + - name: "Windows (amd64, mingw, WinHTTP)" id: windows-amd64-mingw os: windows-2019 setup-script: mingw @@ -166,14 +166,14 @@ jobs: BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, mingw)" + - name: "Windows (x86, mingw, Schannel)" id: windows-x86-mingw os: windows-2019 setup-script: mingw env: ARCH: x86 CMAKE_GENERATOR: MinGW Makefiles - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel BUILD_TEMP: D:\Temp BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin SKIP_SSH_TESTS: true diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5a0b7d12b0b..f461530ae71 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -162,32 +162,39 @@ jobs: SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true setup-script: osx - - name: "Windows (amd64, Visual Studio)" + - name: "Windows (amd64, Visual Studio, WinHTTP)" os: windows-2019 env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=WinHTTP SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (no mmap)" + - name: "Windows (x86, Visual Studio, WinHTTP)" + os: windows-2019 + env: + ARCH: x86 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=WinHTTP -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (amd64, Visual Studio, Schannel)" os: windows-2019 env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 16 2019 - CFLAGS: -DNO_MMAP - CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, Visual Studio)" + - name: "Windows (x86, Visual Studio, Schannel)" os: windows-2019 env: ARCH: x86 CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON + CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_BUNDLED_ZLIB=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (amd64, mingw)" + - name: "Windows (amd64, mingw, WinHTTP)" os: windows-2019 setup-script: mingw env: @@ -198,17 +205,26 @@ jobs: BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, mingw)" + - name: "Windows (x86, mingw, Schannel)" os: windows-2019 setup-script: mingw env: ARCH: x86 CMAKE_GENERATOR: MinGW Makefiles - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel BUILD_TEMP: D:\Temp BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + - name: "Windows (no mmap)" + os: windows-2019 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CFLAGS: -DNO_MMAP + CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true - name: "Linux (Bionic, GCC, dynamically-loaded OpenSSL)" container: name: bionic diff --git a/CMakeLists.txt b/CMakeLists.txt index 710915da1bd..7aed74df67e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,12 +82,6 @@ if(MSVC) option(WIN32_LEAKCHECK "Enable leak reporting via crtdbg" OFF) endif() -if(WIN32) - # By default, libgit2 is built with WinHTTP. To use the built-in - # HTTP transport, invoke CMake with the "-DUSE_WINHTTP=OFF" argument. - option(USE_WINHTTP "Use Win32 WinHTTP routines" ON) -endif() - if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index 20221bf9f64..64c7a1097ce 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -19,7 +19,7 @@ if(USE_HTTPS) message(STATUS "Security framework is too old, falling back to OpenSSL") set(USE_HTTPS "OpenSSL") endif() - elseif(USE_WINHTTP) + elseif(WIN32) set(USE_HTTPS "WinHTTP") elseif(OPENSSL_FOUND) set(USE_HTTPS "OpenSSL") @@ -106,8 +106,27 @@ if(USE_HTTPS) # https://github.com/ARMmbed/mbedtls/issues/228 # For now, pass its link flags as our own list(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) + elseif(USE_HTTPS STREQUAL "Schannel") + set(GIT_SCHANNEL 1) + + list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32" "secur32") + list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32" "-lsecur32") elseif(USE_HTTPS STREQUAL "WinHTTP") - # WinHTTP setup was handled in the WinHTTP-specific block above + set(GIT_WINHTTP 1) + + # Since MinGW does not come with headers or an import library for winhttp, + # we have to include a private header and generate our own import library + if(MINGW) + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/winhttp" "${PROJECT_BINARY_DIR}/deps/winhttp") + list(APPEND LIBGIT2_SYSTEM_LIBS winhttp) + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/winhttp") + else() + list(APPEND LIBGIT2_SYSTEM_LIBS "winhttp") + list(APPEND LIBGIT2_PC_LIBS "-lwinhttp") + endif() + + list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") + list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") set(GIT_OPENSSL 1) set(GIT_OPENSSL_DYNAMIC 1) diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index faf9e2ea31d..5c007e58749 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -13,6 +13,8 @@ if(USE_SHA1 STREQUAL ON) elseif(USE_SHA1 STREQUAL "HTTPS") if(USE_HTTPS STREQUAL "SecureTransport") set(USE_SHA1 "CommonCrypto") + elseif(USE_HTTPS STREQUAL "Schannel") + set(USE_SHA1 "Win32") elseif(USE_HTTPS STREQUAL "WinHTTP") set(USE_SHA1 "Win32") elseif(USE_HTTPS) @@ -51,6 +53,8 @@ endif() if(USE_SHA256 STREQUAL "HTTPS") if(USE_HTTPS STREQUAL "SecureTransport") set(USE_SHA256 "CommonCrypto") + elseif(USE_HTTPS STREQUAL "Schannel") + set(USE_SHA256 "Win32") elseif(USE_HTTPS STREQUAL "WinHTTP") set(USE_SHA256 "Win32") elseif(USE_HTTPS) diff --git a/cmake/SelectWinHTTP.cmake b/cmake/SelectWinHTTP.cmake deleted file mode 100644 index 96e0bdbae54..00000000000 --- a/cmake/SelectWinHTTP.cmake +++ /dev/null @@ -1,17 +0,0 @@ -if(WIN32 AND USE_WINHTTP) - set(GIT_WINHTTP 1) - - # Since MinGW does not come with headers or an import library for winhttp, - # we have to include a private header and generate our own import library - if(MINGW) - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/winhttp" "${PROJECT_BINARY_DIR}/deps/winhttp") - list(APPEND LIBGIT2_SYSTEM_LIBS winhttp) - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/winhttp") - else() - list(APPEND LIBGIT2_SYSTEM_LIBS "winhttp") - list(APPEND LIBGIT2_PC_LIBS "-lwinhttp") - endif() - - list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") - list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") -endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e108b2e79ce..8fd22bc115c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,7 +42,6 @@ include(SelectHashes) include(SelectHTTPParser) include(SelectRegex) include(SelectSSH) -include(SelectWinHTTP) include(SelectZlib) # diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index f225122e548..5d796b1f79b 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -30,6 +30,7 @@ #include "streams/registry.h" #include "streams/mbedtls.h" #include "streams/openssl.h" +#include "streams/socket.h" #include "transports/smart.h" #include "transports/http.h" #include "transports/ssh.h" @@ -78,6 +79,7 @@ int git_libgit2_init(void) git_merge_driver_global_init, git_transport_ssh_global_init, git_stream_registry_global_init, + git_socket_stream_global_init, git_openssl_stream_global_init, git_mbedtls_stream_global_init, git_mwindow_global_init, diff --git a/src/libgit2/streams/schannel.c b/src/libgit2/streams/schannel.c new file mode 100644 index 00000000000..2c1066adb7d --- /dev/null +++ b/src/libgit2/streams/schannel.c @@ -0,0 +1,715 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "streams/schannel.h" + +#ifdef GIT_SCHANNEL + +#define SECURITY_WIN32 + +#include +#include +#include + +#include "stream.h" +#include "streams/socket.h" + +#ifndef SP_PROT_TLS1_2_CLIENT +# define SP_PROT_TLS1_2_CLIENT 2048 +#endif + +#ifndef SP_PROT_TLS1_3_CLIENT +# define SP_PROT_TLS1_3_CLIENT 8192 +#endif + +#ifndef SECBUFFER_ALERT +# define SECBUFFER_ALERT 17 +#endif + +#define READ_BLOCKSIZE (16 * 1024) + +typedef enum { + STATE_NONE = 0, + STATE_CRED = 1, + STATE_CONTEXT = 2, + STATE_CERTIFICATE = 3 +} schannel_state; + +typedef struct { + git_stream parent; + git_stream *io; + int owned; + bool connected; + wchar_t *host_w; + + schannel_state state; + + CredHandle cred; + CtxtHandle context; + SecPkgContext_StreamSizes stream_sizes; + + CERT_CONTEXT *certificate; + const CERT_CHAIN_CONTEXT *cert_chain; + git_cert_x509 x509; + + git_str plaintext_in; + git_str ciphertext_in; +} schannel_stream; + +static int connect_context(schannel_stream *st) +{ + SCHANNEL_CRED cred = { 0 }; + SECURITY_STATUS status = SEC_E_INTERNAL_ERROR; + DWORD context_flags; + static size_t MAX_RETRIES = 1024; + size_t retries; + ssize_t read_len; + int error = 0; + + if (st->owned && (error = git_stream_connect(st->io)) < 0) + return error; + + cred.dwVersion = SCHANNEL_CRED_VERSION; + cred.dwFlags = SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE | + SCH_CRED_MANUAL_CRED_VALIDATION | + SCH_CRED_NO_DEFAULT_CREDS | + SCH_CRED_NO_SERVERNAME_CHECK; + cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | + SP_PROT_TLS1_3_CLIENT; + + if (AcquireCredentialsHandleW(NULL, SCHANNEL_NAME_W, + SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, + NULL, &st->cred, NULL) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not acquire credentials handle"); + return -1; + } + + st->state = STATE_CRED; + + context_flags = ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_STREAM; + + for (retries = 0; retries < MAX_RETRIES; retries++) { + SecBuffer input_buf[] = { + { (unsigned long)st->ciphertext_in.size, + SECBUFFER_TOKEN, + st->ciphertext_in.size ? st->ciphertext_in.ptr : NULL }, + { 0, SECBUFFER_EMPTY, NULL } + }; + SecBuffer output_buf[] = { { 0, SECBUFFER_TOKEN, NULL }, + { 0, SECBUFFER_ALERT, NULL } }; + + SecBufferDesc input_buf_desc = { SECBUFFER_VERSION, 2, input_buf }; + SecBufferDesc output_buf_desc = { SECBUFFER_VERSION, 2, output_buf }; + + status = InitializeSecurityContextW(&st->cred, + retries ? &st->context : NULL, st->host_w, + context_flags, 0, 0, retries ? &input_buf_desc : NULL, 0, + retries ? NULL : &st->context, &output_buf_desc, + &context_flags, NULL); + + if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED) { + st->state = STATE_CONTEXT; + + if (output_buf[0].cbBuffer > 0) { + error = git_stream__write_full(st->io, + output_buf[0].pvBuffer, + output_buf[0].cbBuffer, 0); + + FreeContextBuffer(output_buf[0].pvBuffer); + } + + /* handle any leftover, unprocessed data */ + if (input_buf[1].BufferType == SECBUFFER_EXTRA) { + GIT_ASSERT(st->ciphertext_in.size > input_buf[1].cbBuffer); + + git_str_consume_bytes(&st->ciphertext_in, + st->ciphertext_in.size - input_buf[1].cbBuffer); + } else { + git_str_clear(&st->ciphertext_in); + } + + if (error < 0 || status == SEC_E_OK) + break; + } else if (status == SEC_E_INCOMPLETE_MESSAGE) { + /* we need additional data from the client; */ + if (git_str_grow_by(&st->ciphertext_in, READ_BLOCKSIZE) < 0) { + error = -1; + break; + } + + if ((read_len = git_stream_read(st->io, + st->ciphertext_in.ptr + st->ciphertext_in.size, + (st->ciphertext_in.asize - st->ciphertext_in.size))) < 0) { + error = -1; + break; + } + + GIT_ASSERT((size_t)read_len <= + st->ciphertext_in.asize - st->ciphertext_in.size); + st->ciphertext_in.size += read_len; + } else { + git_error_set(GIT_ERROR_OS, + "could not initialize security context"); + error = -1; + break; + } + + GIT_ASSERT(st->ciphertext_in.size < ULONG_MAX); + } + + if (retries == MAX_RETRIES) { + git_error_set(GIT_ERROR_SSL, + "could not initialize security context: too many retries"); + error = -1; + } + + if (!error) { + if (QueryContextAttributesW(&st->context, + SECPKG_ATTR_STREAM_SIZES, + &st->stream_sizes) != SEC_E_OK) { + git_error_set(GIT_ERROR_SSL, + "could not query stream sizes"); + error = -1; + } + } + + return error; +} + +static int set_certificate_lookup_error(DWORD status) +{ + switch (status) { + case CERT_TRUST_IS_NOT_TIME_VALID: + git_error_set(GIT_ERROR_SSL, + "certificate is expired or not yet valid"); + break; + case CERT_TRUST_IS_REVOKED: + git_error_set(GIT_ERROR_SSL, "certificate is revoked"); + break; + case CERT_TRUST_IS_NOT_SIGNATURE_VALID: + case CERT_TRUST_IS_NOT_VALID_FOR_USAGE: + case CERT_TRUST_INVALID_EXTENSION: + case CERT_TRUST_INVALID_POLICY_CONSTRAINTS: + case CERT_TRUST_INVALID_BASIC_CONSTRAINTS: + case CERT_TRUST_INVALID_NAME_CONSTRAINTS: + case CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT: + case CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT: + case CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT: + case CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT: + case CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY: + case CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT: + git_error_set(GIT_ERROR_SSL, "certificate is not valid"); + break; + case CERT_TRUST_IS_UNTRUSTED_ROOT: + case CERT_TRUST_IS_CYCLIC: + case CERT_TRUST_IS_EXPLICIT_DISTRUST: + git_error_set(GIT_ERROR_SSL, "certificate is not trusted"); + break; + case CERT_TRUST_REVOCATION_STATUS_UNKNOWN: + git_error_set(GIT_ERROR_SSL, + "certificate revocation status could not be verified"); + break; + case CERT_TRUST_IS_OFFLINE_REVOCATION: + git_error_set(GIT_ERROR_SSL, + "certificate revocation is offline or stale"); + break; + case CERT_TRUST_HAS_WEAK_SIGNATURE: + git_error_set(GIT_ERROR_SSL, "certificate has a weak signature"); + break; + default: + git_error_set(GIT_ERROR_SSL, + "unknown certificate lookup failure: %d", status); + return -1; + } + + return GIT_ECERTIFICATE; +} + +static int set_certificate_validation_error(DWORD status) +{ + switch (status) { + case TRUST_E_CERT_SIGNATURE: + git_error_set(GIT_ERROR_SSL, + "the certificate cannot be verified"); + break; + case CRYPT_E_REVOKED: + git_error_set(GIT_ERROR_SSL, + "the certificate or signature has been revoked"); + break; + case CERT_E_UNTRUSTEDROOT: + git_error_set(GIT_ERROR_SSL, + "the certificate root is not trusted"); + break; + case CERT_E_UNTRUSTEDTESTROOT: + git_error_set(GIT_ERROR_SSL, + "the certificate root is a test certificate"); + break; + case CERT_E_CHAINING: + git_error_set(GIT_ERROR_SSL, + "the certificate chain is invalid"); + break; + case CERT_E_WRONG_USAGE: + case CERT_E_PURPOSE: + git_error_set(GIT_ERROR_SSL, + "the certificate is not valid for this usage"); + break; + case CERT_E_EXPIRED: + git_error_set(GIT_ERROR_SSL, + "certificate is expired or not yet valid"); + break; + case CERT_E_INVALID_NAME: + case CERT_E_CN_NO_MATCH: + git_error_set(GIT_ERROR_SSL, + "certificate is not valid for this hostname"); + break; + case CERT_E_INVALID_POLICY: + case TRUST_E_BASIC_CONSTRAINTS: + case CERT_E_CRITICAL: + case CERT_E_VALIDITYPERIODNESTING: + git_error_set(GIT_ERROR_SSL, "certificate is not valid"); + break; + case CRYPT_E_NO_REVOCATION_CHECK: + git_error_set(GIT_ERROR_SSL, + "certificate revocation status could not be verified"); + break; + case CRYPT_E_REVOCATION_OFFLINE: + git_error_set(GIT_ERROR_SSL, + "certificate revocation is offline or stale"); + break; + case CERT_E_ROLE: + git_error_set(GIT_ERROR_SSL, "certificate authority is not valid"); + break; + default: + git_error_set(GIT_ERROR_SSL, + "unknown certificate policy checking failure: %d", + status); + return -1; + } + + return GIT_ECERTIFICATE; +} + +static int check_certificate(schannel_stream* st) +{ + CERT_CHAIN_PARA cert_chain_parameters; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_policy_parameters; + CERT_CHAIN_POLICY_PARA cert_policy_parameters = + { sizeof(CERT_CHAIN_POLICY_PARA), 0, &ssl_policy_parameters }; + CERT_CHAIN_POLICY_STATUS cert_policy_status; + + memset(&cert_chain_parameters, 0, sizeof(CERT_CHAIN_PARA)); + cert_chain_parameters.cbSize = sizeof(CERT_CHAIN_PARA); + + if (QueryContextAttributesW(&st->context, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &st->certificate) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, + "could not query remote certificate context"); + return -1; + } + + /* TODO: do we really want to do revokcation checking ? */ + if (!CertGetCertificateChain(NULL, st->certificate, NULL, + st->certificate->hCertStore, &cert_chain_parameters, + CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, + NULL, &st->cert_chain)) { + git_error_set(GIT_ERROR_OS, "could not query remote certificate chain"); + CertFreeCertificateContext(st->certificate); + return -1; + } + + st->state = STATE_CERTIFICATE; + + /* Set up the x509 certificate data for future callbacks */ + + st->x509.parent.cert_type = GIT_CERT_X509; + st->x509.data = st->certificate->pbCertEncoded; + st->x509.len = st->certificate->cbCertEncoded; + + /* Handle initial certificate validation */ + + if (st->cert_chain->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) + return set_certificate_lookup_error(st->cert_chain->TrustStatus.dwErrorStatus); + + ssl_policy_parameters.cbSize = sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA); + ssl_policy_parameters.dwAuthType = AUTHTYPE_SERVER; + ssl_policy_parameters.pwszServerName = st->host_w; + + if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, + st->cert_chain, &cert_policy_parameters, + &cert_policy_status)) { + git_error_set(GIT_ERROR_OS, "could not verify certificate chain policy"); + return -1; + } + + if (cert_policy_status.dwError != SEC_E_OK) + return set_certificate_validation_error(cert_policy_status.dwError); + + return 0; +} + +static int schannel_connect(git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + int error; + + GIT_ASSERT(st->state == STATE_NONE); + + if ((error = connect_context(st)) < 0 || + (error = check_certificate(st)) < 0) + return error; + + st->connected = 1; + return 0; +} + +static int schannel_certificate(git_cert **out, git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + + *out = &st->x509.parent; + return 0; +} + +static int schannel_set_proxy( + git_stream *stream, + const git_proxy_options *proxy_options) +{ + schannel_stream *st = (schannel_stream *)stream; + return git_stream_set_proxy(st->io, proxy_options); +} + +static ssize_t schannel_write( + git_stream *stream, + const char *data, + size_t data_len, + int flags) +{ + schannel_stream *st = (schannel_stream *)stream; + SecBuffer encrypt_buf[3]; + SecBufferDesc encrypt_buf_desc = { SECBUFFER_VERSION, 3, encrypt_buf }; + git_str ciphertext_out = GIT_STR_INIT; + ssize_t total_len = 0; + + GIT_UNUSED(flags); + + if (data_len > SSIZE_MAX) + data_len = SSIZE_MAX; + + git_str_init(&ciphertext_out, + st->stream_sizes.cbHeader + + st->stream_sizes.cbMaximumMessage + + st->stream_sizes.cbTrailer); + + while (data_len > 0) { + size_t message_len = min(data_len, st->stream_sizes.cbMaximumMessage); + size_t ciphertext_len, ciphertext_written = 0; + + encrypt_buf[0].BufferType = SECBUFFER_STREAM_HEADER; + encrypt_buf[0].cbBuffer = st->stream_sizes.cbHeader; + encrypt_buf[0].pvBuffer = ciphertext_out.ptr; + + encrypt_buf[1].BufferType = SECBUFFER_DATA; + encrypt_buf[1].cbBuffer = (unsigned long)message_len; + encrypt_buf[1].pvBuffer = + ciphertext_out.ptr + st->stream_sizes.cbHeader; + + encrypt_buf[2].BufferType = SECBUFFER_STREAM_TRAILER; + encrypt_buf[2].cbBuffer = st->stream_sizes.cbTrailer; + encrypt_buf[2].pvBuffer = + ciphertext_out.ptr + st->stream_sizes.cbHeader + + message_len; + + memcpy(ciphertext_out.ptr + st->stream_sizes.cbHeader, data, message_len); + + if (EncryptMessage(&st->context, 0, &encrypt_buf_desc, 0) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not encrypt tls message"); + total_len = -1; + goto done; + } + + ciphertext_len = encrypt_buf[0].cbBuffer + + encrypt_buf[1].cbBuffer + + encrypt_buf[2].cbBuffer; + + while (ciphertext_written < ciphertext_len) { + ssize_t chunk_len = git_stream_write(st->io, + ciphertext_out.ptr + ciphertext_written, + ciphertext_len - ciphertext_written, 0); + + if (chunk_len < 0) { + total_len = -1; + goto done; + } + + ciphertext_len -= chunk_len; + ciphertext_written += chunk_len; + } + + total_len += message_len; + + data += message_len; + data_len -= message_len; + } + +done: + git_str_dispose(&ciphertext_out); + return total_len; +} + +static ssize_t schannel_read(git_stream *stream, void *_data, size_t data_len) +{ + schannel_stream *st = (schannel_stream *)stream; + char *data = (char *)_data; + SecBuffer decrypt_buf[4]; + SecBufferDesc decrypt_buf_desc = { SECBUFFER_VERSION, 4, decrypt_buf }; + SECURITY_STATUS status; + ssize_t chunk_len, total_len = 0; + + if (data_len > SSIZE_MAX) + data_len = SSIZE_MAX; + + /* + * Loop until we have some bytes to return - we may have decrypted + * bytes queued or ciphertext from the wire that we can decrypt and + * return. Return any queued bytes if they're available to avoid a + * network read, which may block. We may return less than the + * caller requested, and they can retry for an actual network + */ + while ((size_t)total_len < data_len) { + if (st->plaintext_in.size > 0) { + size_t copy_len = min(st->plaintext_in.size, data_len); + + memcpy(data, st->plaintext_in.ptr, copy_len); + git_str_consume_bytes(&st->plaintext_in, copy_len); + + data += copy_len; + data_len -= copy_len; + + total_len += copy_len; + + continue; + } + + if (st->ciphertext_in.size > 0) { + decrypt_buf[0].BufferType = SECBUFFER_DATA; + decrypt_buf[0].cbBuffer = (unsigned long)min(st->ciphertext_in.size, ULONG_MAX); + decrypt_buf[0].pvBuffer = st->ciphertext_in.ptr; + + decrypt_buf[1].BufferType = SECBUFFER_EMPTY; + decrypt_buf[1].cbBuffer = 0; + decrypt_buf[1].pvBuffer = NULL; + + decrypt_buf[2].BufferType = SECBUFFER_EMPTY; + decrypt_buf[2].cbBuffer = 0; + decrypt_buf[2].pvBuffer = NULL; + + decrypt_buf[3].BufferType = SECBUFFER_EMPTY; + decrypt_buf[3].cbBuffer = 0; + decrypt_buf[3].pvBuffer = NULL; + + status = DecryptMessage(&st->context, &decrypt_buf_desc, 0, NULL); + + if (status == SEC_E_OK) { + GIT_ASSERT(decrypt_buf[0].BufferType == SECBUFFER_STREAM_HEADER); + GIT_ASSERT(decrypt_buf[1].BufferType == SECBUFFER_DATA); + GIT_ASSERT(decrypt_buf[2].BufferType == SECBUFFER_STREAM_TRAILER); + + if (git_str_put(&st->plaintext_in, decrypt_buf[1].pvBuffer, decrypt_buf[1].cbBuffer) < 0) { + total_len = -1; + goto done; + } + + if (decrypt_buf[3].BufferType == SECBUFFER_EXTRA) { + git_str_consume_bytes(&st->ciphertext_in, (st->ciphertext_in.size - decrypt_buf[3].cbBuffer)); + } else { + git_str_clear(&st->ciphertext_in); + } + + continue; + } else if (status == SEC_E_CONTEXT_EXPIRED) { + break; + } else if (status != SEC_E_INCOMPLETE_MESSAGE) { + git_error_set(GIT_ERROR_SSL, "could not decrypt tls message"); + total_len = -1; + goto done; + } + } + + if (total_len != 0) + break; + + if (git_str_grow_by(&st->ciphertext_in, READ_BLOCKSIZE) < 0) { + total_len = -1; + goto done; + } + + if ((chunk_len = git_stream_read(st->io, st->ciphertext_in.ptr + st->ciphertext_in.size, st->ciphertext_in.asize - st->ciphertext_in.size)) < 0) { + total_len = -1; + goto done; + } + + st->ciphertext_in.size += chunk_len; + } + +done: + return total_len; +} + +static int schannel_close(git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + int error = 0; + + if (st->connected) { + SecBuffer shutdown_buf; + SecBufferDesc shutdown_buf_desc = + { SECBUFFER_VERSION, 1, &shutdown_buf }; + DWORD shutdown_message = SCHANNEL_SHUTDOWN, shutdown_flags; + + shutdown_buf.BufferType = SECBUFFER_TOKEN; + shutdown_buf.cbBuffer = sizeof(DWORD); + shutdown_buf.pvBuffer = &shutdown_message; + + if (ApplyControlToken(&st->context, &shutdown_buf_desc) != SEC_E_OK) { + git_error_set(GIT_ERROR_SSL, "could not shutdown stream"); + error = -1; + } + + shutdown_buf.BufferType = SECBUFFER_TOKEN; + shutdown_buf.cbBuffer = 0; + shutdown_buf.pvBuffer = NULL; + + shutdown_flags = ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_STREAM; + + if (InitializeSecurityContext(&st->cred, &st->context, + NULL, shutdown_flags, 0, 0, + &shutdown_buf_desc, 0, NULL, + &shutdown_buf_desc, &shutdown_flags, + NULL) == SEC_E_OK) { + if (shutdown_buf.cbBuffer > 0) { + if (git_stream__write_full(st->io, + shutdown_buf.pvBuffer, + shutdown_buf.cbBuffer, 0) < 0) + error = -1; + + FreeContextBuffer(shutdown_buf.pvBuffer); + } + } + } + + st->connected = false; + + if (st->owned && git_stream_close(st->io) < 0) + error = -1; + + return error; +} + +static void schannel_free(git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + + if (st->state >= STATE_CERTIFICATE) { + CertFreeCertificateContext(st->certificate); + CertFreeCertificateChain(st->cert_chain); + } + + if (st->state >= STATE_CONTEXT) + DeleteSecurityContext(&st->context); + + if (st->state >= STATE_CRED) + FreeCredentialsHandle(&st->cred); + + st->state = STATE_NONE; + + git_str_dispose(&st->ciphertext_in); + git_str_dispose(&st->plaintext_in); + + git__free(st->host_w); + + if (st->owned) + git_stream_free(st->io); + + git__free(st); +} + +static int schannel_stream_wrap( + git_stream **out, + git_stream *in, + const char *host, + int owned) +{ + schannel_stream *st; + + st = git__calloc(1, sizeof(schannel_stream)); + GIT_ERROR_CHECK_ALLOC(st); + + st->io = in; + st->owned = owned; + + if (git__utf8_to_16_alloc(&st->host_w, host) < 0) { + git__free(st); + return -1; + } + + st->parent.version = GIT_STREAM_VERSION; + st->parent.encrypted = 1; + st->parent.proxy_support = git_stream_supports_proxy(st->io); + st->parent.connect = schannel_connect; + st->parent.certificate = schannel_certificate; + st->parent.set_proxy = schannel_set_proxy; + st->parent.read = schannel_read; + st->parent.write = schannel_write; + st->parent.close = schannel_close; + st->parent.free = schannel_free; + + *out = (git_stream *)st; + return 0; +} + +extern int git_schannel_stream_new( + git_stream **out, + const char *host, + const char *port) +{ + git_stream *stream; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(host); + GIT_ASSERT_ARG(port); + + if ((error = git_socket_stream_new(&stream, host, port)) < 0) + return error; + + if ((error = schannel_stream_wrap(out, stream, host, 1)) < 0) { + git_stream_close(stream); + git_stream_free(stream); + } + + return error; +} + +extern int git_schannel_stream_wrap( + git_stream **out, + git_stream *in, + const char *host) +{ + return schannel_stream_wrap(out, in, host, 0); +} + +#endif diff --git a/src/libgit2/streams/schannel.h b/src/libgit2/streams/schannel.h new file mode 100644 index 00000000000..3584970d1f8 --- /dev/null +++ b/src/libgit2/streams/schannel.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_steams_schannel_h__ +#define INCLUDE_steams_schannel_h__ + +#include "common.h" + +#include "git2/sys/stream.h" + +#ifdef GIT_SCHANNEL + +extern int git_schannel_stream_new( + git_stream **out, + const char *host, + const char *port); + +extern int git_schannel_stream_wrap( + git_stream **out, + git_stream *in, + const char *host); + +#endif + +#endif diff --git a/src/libgit2/streams/socket.c b/src/libgit2/streams/socket.c index 908e8c02f9b..8f23e746e51 100644 --- a/src/libgit2/streams/socket.c +++ b/src/libgit2/streams/socket.c @@ -10,22 +10,23 @@ #include "posix.h" #include "netops.h" #include "registry.h" +#include "runtime.h" #include "stream.h" #ifndef _WIN32 -# include -# include -# include -# include -# include -# include -# include +# include +# include +# include +# include +# include +# include +# include #else -# include -# include -# ifdef _MSC_VER -# pragma comment(lib, "ws2_32") -# endif +# include +# include +# ifdef _MSC_VER +# pragma comment(lib, "ws2_32") +# endif #endif #ifdef GIT_WIN32 @@ -54,11 +55,8 @@ static int close_socket(GIT_SOCKET s) return 0; #ifdef GIT_WIN32 - if (SOCKET_ERROR == closesocket(s)) - return -1; - - if (0 != WSACleanup()) { - git_error_set(GIT_ERROR_OS, "winsock cleanup failed"); + if (closesocket(s) != 0) { + net_set_error("could not close socket"); return -1; } @@ -77,23 +75,6 @@ static int socket_connect(git_stream *stream) GIT_SOCKET s = INVALID_SOCKET; int ret; -#ifdef GIT_WIN32 - /* on win32, the WSA context needs to be initialized - * before any socket calls can be performed */ - WSADATA wsd; - - if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { - git_error_set(GIT_ERROR_OS, "winsock init failed"); - return -1; - } - - if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) { - WSACleanup(); - git_error_set(GIT_ERROR_OS, "winsock init failed"); - return -1; - } -#endif - memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; @@ -240,3 +221,42 @@ int git_socket_stream_new( return init(out, host, port); } + +#ifdef GIT_WIN32 + +static void socket_stream_global_shutdown(void) +{ + WSACleanup(); +} + +int git_socket_stream_global_init(void) +{ + WORD winsock_version; + WSADATA wsa_data; + + winsock_version = MAKEWORD(2, 2); + + if (WSAStartup(winsock_version, &wsa_data) != 0) { + git_error_set(GIT_ERROR_OS, "could not initialize Windows Socket Library"); + return -1; + } + + if (LOBYTE(wsa_data.wVersion) != 2 || + HIBYTE(wsa_data.wVersion) != 2) { + git_error_set(GIT_ERROR_SSL, "Windows Socket Library does not support Winsock 2.2"); + return -1; + } + + return git_runtime_shutdown_register(socket_stream_global_shutdown); +} + +#else + +#include "stream.h" + +int git_socket_stream_global_init(void) +{ + return 0; +} + + #endif diff --git a/src/libgit2/streams/socket.h b/src/libgit2/streams/socket.h index 3235f31679c..300e708937f 100644 --- a/src/libgit2/streams/socket.h +++ b/src/libgit2/streams/socket.h @@ -20,4 +20,6 @@ typedef struct { extern int git_socket_stream_new(git_stream **out, const char *host, const char *port); +extern int git_socket_stream_global_init(void); + #endif diff --git a/src/libgit2/streams/tls.c b/src/libgit2/streams/tls.c index e063a33f99a..246ac9ca793 100644 --- a/src/libgit2/streams/tls.c +++ b/src/libgit2/streams/tls.c @@ -13,6 +13,7 @@ #include "streams/mbedtls.h" #include "streams/openssl.h" #include "streams/stransport.h" +#include "streams/schannel.h" int git_tls_stream_new(git_stream **out, const char *host, const char *port) { @@ -33,6 +34,8 @@ int git_tls_stream_new(git_stream **out, const char *host, const char *port) init = git_openssl_stream_new; #elif defined(GIT_MBEDTLS) init = git_mbedtls_stream_new; +#elif defined(GIT_SCHANNEL) + init = git_schannel_stream_new; #endif } else { return error; @@ -63,6 +66,8 @@ int git_tls_stream_wrap(git_stream **out, git_stream *in, const char *host) wrap = git_openssl_stream_wrap; #elif defined(GIT_MBEDTLS) wrap = git_mbedtls_stream_wrap; +#elif defined(GIT_SCHANNEL) + wrap = git_schannel_stream_wrap; #endif } diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index fbf0cab60ea..1575be641e1 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -41,6 +41,7 @@ #cmakedefine GIT_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SECURE_TRANSPORT 1 #cmakedefine GIT_MBEDTLS 1 +#cmakedefine GIT_SCHANNEL 1 #cmakedefine GIT_SHA1_COLLISIONDETECT 1 #cmakedefine GIT_SHA1_WIN32 1 diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 1a4cdb520ce..b635739b676 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -580,6 +580,17 @@ static int succeed_certificate_check(git_cert *cert, int valid, const char *host return 0; } +static int x509_succeed_certificate_check(git_cert *cert, int valid, const char *host, void *payload) +{ + GIT_UNUSED(valid); + GIT_UNUSED(payload); + + cl_assert_equal_s("github.com", host); + cl_assert_equal_i(GIT_CERT_X509, cert->cert_type); + + return 0; +} + static int fail_certificate_check(git_cert *cert, int valid, const char *host, void *payload) { GIT_UNUSED(cert); @@ -901,7 +912,7 @@ void test_online_clone__certificate_invalid(void) void test_online_clone__certificate_valid(void) { - g_options.fetch_opts.callbacks.certificate_check = succeed_certificate_check; + g_options.fetch_opts.callbacks.certificate_check = x509_succeed_certificate_check; cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options)); } diff --git a/tests/libgit2/stream/registration.c b/tests/libgit2/stream/registration.c index bf3c20502a0..ccaecee8c1e 100644 --- a/tests/libgit2/stream/registration.c +++ b/tests/libgit2/stream/registration.c @@ -81,10 +81,10 @@ void test_stream_registration__tls(void) cl_git_pass(git_stream_register(GIT_STREAM_TLS, NULL)); error = git_tls_stream_new(&stream, "localhost", "443"); - /* We don't have TLS support enabled, or we're on Windows, - * which has no arbitrary TLS stream support. + /* We don't have TLS support enabled, or we're on Windows + * with WinHTTP, which is not actually TLS stream support. */ -#if defined(GIT_WIN32) || !defined(GIT_HTTPS) +#if defined(GIT_WINHTTP) || !defined(GIT_HTTPS) cl_git_fail_with(-1, error); #else cl_git_pass(error); From cff0d9b1cc2432ab6a6eab777cdfe230ee07fca1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 11 Mar 2023 00:03:34 -0800 Subject: [PATCH 109/816] http: refactor GSSAPI / negotiate / NTLM auth Name the GSSAPI and ntlmclient authentication providers as such. Today they're named after the authentication mechanism ("Negotiate", "NTLM") instead of their implementation. If we have competing implementations for the same mechanism (eg, a future Windows SSPI-based provider for Negotiate and NTLM) then this will get confusing. --- .../{auth_negotiate.c => auth_gssapi.c} | 64 +++++++++---------- src/libgit2/transports/auth_ntlm.h | 4 +- .../{auth_ntlm.c => auth_ntlmclient.c} | 24 +++---- 3 files changed, 46 insertions(+), 46 deletions(-) rename src/libgit2/transports/{auth_negotiate.c => auth_gssapi.c} (79%) rename src/libgit2/transports/{auth_ntlm.c => auth_ntlmclient.c} (88%) diff --git a/src/libgit2/transports/auth_negotiate.c b/src/libgit2/transports/auth_gssapi.c similarity index 79% rename from src/libgit2/transports/auth_negotiate.c rename to src/libgit2/transports/auth_gssapi.c index 6380504be7e..5005538411b 100644 --- a/src/libgit2/transports/auth_negotiate.c +++ b/src/libgit2/transports/auth_gssapi.c @@ -20,13 +20,13 @@ #include #endif -static gss_OID_desc negotiate_oid_spnego = +static gss_OID_desc gssapi_oid_spnego = { 6, (void *) "\x2b\x06\x01\x05\x05\x02" }; -static gss_OID_desc negotiate_oid_krb5 = +static gss_OID_desc gssapi_oid_krb5 = { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; -static gss_OID negotiate_oids[] = - { &negotiate_oid_spnego, &negotiate_oid_krb5, NULL }; +static gss_OID gssapi_oids[] = + { &gssapi_oid_spnego, &gssapi_oid_krb5, NULL }; typedef struct { git_http_auth_context parent; @@ -36,9 +36,9 @@ typedef struct { char *challenge; gss_ctx_id_t gss_context; gss_OID oid; -} http_auth_negotiate_context; +} http_auth_gssapi_context; -static void negotiate_err_set( +static void gssapi_err_set( OM_uint32 status_major, OM_uint32 status_minor, const char *message) @@ -58,11 +58,11 @@ static void negotiate_err_set( } } -static int negotiate_set_challenge( +static int gssapi_set_challenge( git_http_auth_context *c, const char *challenge) { - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; GIT_ASSERT_ARG(ctx); GIT_ASSERT_ARG(challenge); @@ -76,7 +76,7 @@ static int negotiate_set_challenge( return 0; } -static void negotiate_context_dispose(http_auth_negotiate_context *ctx) +static void gssapi_context_dispose(http_auth_gssapi_context *ctx) { OM_uint32 status_minor; @@ -92,12 +92,12 @@ static void negotiate_context_dispose(http_auth_negotiate_context *ctx) ctx->challenge = NULL; } -static int negotiate_next_token( +static int gssapi_next_token( git_str *buf, git_http_auth_context *c, git_credential *cred) { - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; OM_uint32 status_major, status_minor; gss_buffer_desc target_buffer = GSS_C_EMPTY_BUFFER, input_token = GSS_C_EMPTY_BUFFER, @@ -126,7 +126,7 @@ static int negotiate_next_token( GSS_C_NT_HOSTBASED_SERVICE, &server); if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, + gssapi_err_set(status_major, status_minor, "could not parse principal"); error = -1; goto done; @@ -152,10 +152,10 @@ static int negotiate_next_token( input_token.length = input_buf.size; input_token_ptr = &input_token; } else if (ctx->gss_context != GSS_C_NO_CONTEXT) { - negotiate_context_dispose(ctx); + gssapi_context_dispose(ctx); } - mech = &negotiate_oid_spnego; + mech = &gssapi_oid_spnego; status_major = gss_init_sec_context( &status_minor, @@ -173,14 +173,14 @@ static int negotiate_next_token( NULL); if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, "negotiate failure"); + gssapi_err_set(status_major, status_minor, "negotiate failure"); error = -1; goto done; } /* This message merely told us auth was complete; we do not respond. */ if (status_major == GSS_S_COMPLETE) { - negotiate_context_dispose(ctx); + gssapi_context_dispose(ctx); ctx->complete = 1; goto done; } @@ -204,20 +204,20 @@ static int negotiate_next_token( return error; } -static int negotiate_is_complete(git_http_auth_context *c) +static int gssapi_is_complete(git_http_auth_context *c) { - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; GIT_ASSERT_ARG(ctx); return (ctx->complete == 1); } -static void negotiate_context_free(git_http_auth_context *c) +static void gssapi_context_free(git_http_auth_context *c) { - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; - negotiate_context_dispose(ctx); + gssapi_context_dispose(ctx); ctx->configured = 0; ctx->complete = 0; @@ -226,8 +226,8 @@ static void negotiate_context_free(git_http_auth_context *c) git__free(ctx); } -static int negotiate_init_context( - http_auth_negotiate_context *ctx, +static int gssapi_init_context( + http_auth_gssapi_context *ctx, const git_net_url *url) { OM_uint32 status_major, status_minor; @@ -239,13 +239,13 @@ static int negotiate_init_context( status_major = gss_indicate_mechs(&status_minor, &mechanism_list); if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, + gssapi_err_set(status_major, status_minor, "could not query mechanisms"); return -1; } if (mechanism_list) { - for (oid = negotiate_oids; *oid; oid++) { + for (oid = gssapi_oids; *oid; oid++) { for (i = 0; i < mechanism_list->count; i++) { item = &mechanism_list->elements[i]; @@ -285,14 +285,14 @@ int git_http_auth_negotiate( git_http_auth_context **out, const git_net_url *url) { - http_auth_negotiate_context *ctx; + http_auth_gssapi_context *ctx; *out = NULL; - ctx = git__calloc(1, sizeof(http_auth_negotiate_context)); + ctx = git__calloc(1, sizeof(http_auth_gssapi_context)); GIT_ERROR_CHECK_ALLOC(ctx); - if (negotiate_init_context(ctx, url) < 0) { + if (gssapi_init_context(ctx, url) < 0) { git__free(ctx); return -1; } @@ -300,10 +300,10 @@ int git_http_auth_negotiate( ctx->parent.type = GIT_HTTP_AUTH_NEGOTIATE; ctx->parent.credtypes = GIT_CREDENTIAL_DEFAULT; ctx->parent.connection_affinity = 1; - ctx->parent.set_challenge = negotiate_set_challenge; - ctx->parent.next_token = negotiate_next_token; - ctx->parent.is_complete = negotiate_is_complete; - ctx->parent.free = negotiate_context_free; + ctx->parent.set_challenge = gssapi_set_challenge; + ctx->parent.next_token = gssapi_next_token; + ctx->parent.is_complete = gssapi_is_complete; + ctx->parent.free = gssapi_context_free; *out = (git_http_auth_context *)ctx; diff --git a/src/libgit2/transports/auth_ntlm.h b/src/libgit2/transports/auth_ntlm.h index 40689498cae..2bf8f41f619 100644 --- a/src/libgit2/transports/auth_ntlm.h +++ b/src/libgit2/transports/auth_ntlm.h @@ -5,8 +5,8 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef INCLUDE_transports_auth_ntlm_h__ -#define INCLUDE_transports_auth_ntlm_h__ +#ifndef INCLUDE_transports_auth_ntlmclient_h__ +#define INCLUDE_transports_auth_ntlmclient_h__ #include "auth.h" diff --git a/src/libgit2/transports/auth_ntlm.c b/src/libgit2/transports/auth_ntlmclient.c similarity index 88% rename from src/libgit2/transports/auth_ntlm.c rename to src/libgit2/transports/auth_ntlmclient.c index f49ce101a56..6f26a6179c6 100644 --- a/src/libgit2/transports/auth_ntlm.c +++ b/src/libgit2/transports/auth_ntlmclient.c @@ -23,7 +23,7 @@ typedef struct { bool complete; } http_auth_ntlm_context; -static int ntlm_set_challenge( +static int ntlmclient_set_challenge( git_http_auth_context *c, const char *challenge) { @@ -40,7 +40,7 @@ static int ntlm_set_challenge( return 0; } -static int ntlm_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cred) +static int ntlmclient_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cred) { git_credential_userpass_plaintext *cred; const char *sep, *username; @@ -76,7 +76,7 @@ static int ntlm_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cr return error; } -static int ntlm_next_token( +static int ntlmclient_next_token( git_str *buf, git_http_auth_context *c, git_credential *cred) @@ -104,7 +104,7 @@ static int ntlm_next_token( */ ctx->complete = true; - if (cred && ntlm_set_credentials(ctx, cred) != 0) + if (cred && ntlmclient_set_credentials(ctx, cred) != 0) goto done; if (challenge_len < 4) { @@ -162,7 +162,7 @@ static int ntlm_next_token( return error; } -static int ntlm_is_complete(git_http_auth_context *c) +static int ntlmclient_is_complete(git_http_auth_context *c) { http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; @@ -170,7 +170,7 @@ static int ntlm_is_complete(git_http_auth_context *c) return (ctx->complete == true); } -static void ntlm_context_free(git_http_auth_context *c) +static void ntlmclient_context_free(git_http_auth_context *c) { http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; @@ -179,7 +179,7 @@ static void ntlm_context_free(git_http_auth_context *c) git__free(ctx); } -static int ntlm_init_context( +static int ntlmclient_init_context( http_auth_ntlm_context *ctx, const git_net_url *url) { @@ -206,7 +206,7 @@ int git_http_auth_ntlm( ctx = git__calloc(1, sizeof(http_auth_ntlm_context)); GIT_ERROR_CHECK_ALLOC(ctx); - if (ntlm_init_context(ctx, url) < 0) { + if (ntlmclient_init_context(ctx, url) < 0) { git__free(ctx); return -1; } @@ -214,10 +214,10 @@ int git_http_auth_ntlm( ctx->parent.type = GIT_HTTP_AUTH_NTLM; ctx->parent.credtypes = GIT_CREDENTIAL_USERPASS_PLAINTEXT; ctx->parent.connection_affinity = 1; - ctx->parent.set_challenge = ntlm_set_challenge; - ctx->parent.next_token = ntlm_next_token; - ctx->parent.is_complete = ntlm_is_complete; - ctx->parent.free = ntlm_context_free; + ctx->parent.set_challenge = ntlmclient_set_challenge; + ctx->parent.next_token = ntlmclient_next_token; + ctx->parent.is_complete = ntlmclient_is_complete; + ctx->parent.free = ntlmclient_context_free; *out = (git_http_auth_context *)ctx; From 0d7f3f52918a00a2a07ba965eb65c6ac5d122867 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 11 Mar 2023 04:45:19 -0800 Subject: [PATCH 110/816] utf8: add conversion with size and refactor names Add functions to use convert a string with length, instead of assuming NUL termination. In addition, move the utf8 to 16 conversion routines into the `git_utf8` namespace instead of using namespaceless `git__` prefixed names. --- src/libgit2/streams/schannel.c | 2 +- src/libgit2/transports/winhttp.c | 24 ++--- src/util/fs_path.c | 2 +- src/util/util.c | 2 +- src/util/win32/error.c | 2 +- src/util/win32/path_w32.c | 16 ++-- src/util/win32/posix_w32.c | 2 +- src/util/win32/utf-conv.c | 148 +++++++++++++++---------------- src/util/win32/utf-conv.h | 95 +++++++++++++++++--- src/util/win32/w32_util.c | 2 +- tests/clar/clar_libgit2.c | 4 +- tests/util/link.c | 6 +- 12 files changed, 185 insertions(+), 120 deletions(-) diff --git a/src/libgit2/streams/schannel.c b/src/libgit2/streams/schannel.c index 2c1066adb7d..f096158193c 100644 --- a/src/libgit2/streams/schannel.c +++ b/src/libgit2/streams/schannel.c @@ -661,7 +661,7 @@ static int schannel_stream_wrap( st->io = in; st->owned = owned; - if (git__utf8_to_16_alloc(&st->host_w, host) < 0) { + if (git_utf8_to_16_alloc(&st->host_w, host) < 0) { git__free(st); return -1; } diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index 09822760799..de24a2a41c1 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -158,10 +158,10 @@ static int apply_userpass_credentials(HINTERNET request, DWORD target, int mecha goto done; } - if ((error = user_len = git__utf8_to_16_alloc(&user, c->username)) < 0) + if ((error = user_len = git_utf8_to_16_alloc(&user, c->username)) < 0) goto done; - if ((error = pass_len = git__utf8_to_16_alloc(&pass, c->password)) < 0) + if ((error = pass_len = git_utf8_to_16_alloc(&pass, c->password)) < 0) goto done; if (!WinHttpSetCredentials(request, target, native_scheme, user, pass, NULL)) { @@ -242,7 +242,7 @@ static int acquire_fallback_cred( HRESULT hCoInitResult; /* Convert URL to wide characters */ - if (git__utf8_to_16_alloc(&wide_url, url) < 0) { + if (git_utf8_to_16_alloc(&wide_url, url) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert string to wide form"); return -1; } @@ -397,7 +397,7 @@ static int winhttp_stream_connect(winhttp_stream *s) return -1; /* Convert URL to wide characters */ - if (git__utf8_to_16_alloc(&s->request_uri, git_str_cstr(&buf)) < 0) { + if (git_utf8_to_16_alloc(&s->request_uri, git_str_cstr(&buf)) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert string to wide form"); goto on_error; } @@ -473,7 +473,7 @@ static int winhttp_stream_connect(winhttp_stream *s) } /* Convert URL to wide characters */ - error = git__utf8_to_16_alloc(&proxy_wide, processed_url.ptr); + error = git_utf8_to_16_alloc(&proxy_wide, processed_url.ptr); git_str_dispose(&processed_url); if (error < 0) goto on_error; @@ -531,7 +531,7 @@ static int winhttp_stream_connect(winhttp_stream *s) s->service) < 0) goto on_error; - if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { + if (git_utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert content-type to wide characters"); goto on_error; } @@ -548,7 +548,7 @@ static int winhttp_stream_connect(winhttp_stream *s) s->service) < 0) goto on_error; - if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { + if (git_utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert accept header to wide characters"); goto on_error; } @@ -568,7 +568,7 @@ static int winhttp_stream_connect(winhttp_stream *s) git_str_puts(&buf, t->owner->connect_opts.custom_headers.strings[i]); /* Convert header to wide characters */ - if ((error = git__utf8_to_16_alloc(&custom_header_wide, git_str_cstr(&buf))) < 0) + if ((error = git_utf8_to_16_alloc(&custom_header_wide, git_str_cstr(&buf))) < 0) goto on_error; if (!WinHttpAddRequestHeaders(s->request, custom_header_wide, (ULONG)-1L, @@ -783,7 +783,7 @@ static int winhttp_connect( } /* Prepare host */ - if (git__utf8_to_16_alloc(&wide_host, host) < 0) { + if (git_utf8_to_16_alloc(&wide_host, host) < 0) { git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters"); goto on_error; } @@ -792,7 +792,7 @@ static int winhttp_connect( if (git_http__user_agent(&ua) < 0) goto on_error; - if (git__utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) { + if (git_utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) { git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters"); goto on_error; } @@ -1182,7 +1182,7 @@ static int winhttp_stream_read( } /* Convert the Location header to UTF-8 */ - if (git__utf16_to_8_alloc(&location8, location) < 0) { + if (git_utf8_from_16_alloc(&location8, location) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert Location header to UTF-8"); git__free(location); return -1; @@ -1254,7 +1254,7 @@ static int winhttp_stream_read( else p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service); - if (git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { + if (git_utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert expected content-type to wide characters"); return -1; } diff --git a/src/util/fs_path.c b/src/util/fs_path.c index b52867e779f..e03fcf7c760 100644 --- a/src/util/fs_path.c +++ b/src/util/fs_path.c @@ -2015,7 +2015,7 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable) git_win32_path fullpath_w, executable_w; int error; - if (git__utf8_to_16(executable_w, GIT_WIN_PATH_MAX, executable) < 0) + if (git_utf8_to_16(executable_w, GIT_WIN_PATH_MAX, executable) < 0) return -1; error = git_win32_path_find_executable(fullpath_w, executable_w); diff --git a/src/util/util.c b/src/util/util.c index aee95fddfb5..9c9f2c0403a 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -743,7 +743,7 @@ int git__getenv(git_str *out, const char *name) git_str_clear(out); - if (git__utf8_to_16_alloc(&wide_name, name) < 0) + if (git_utf8_to_16_alloc(&wide_name, name) < 0) return -1; if ((value_len = GetEnvironmentVariableW(wide_name, NULL, 0)) > 0) { diff --git a/src/util/win32/error.c b/src/util/win32/error.c index 3a52fb5a90a..dfd6fa1e8a1 100644 --- a/src/util/win32/error.c +++ b/src/util/win32/error.c @@ -43,7 +43,7 @@ char *git_win32_get_error_message(DWORD error_code) (LPWSTR)&lpMsgBuf, 0, NULL)) { /* Convert the message to UTF-8. If this fails, we will * return NULL, which is a condition expected by the caller */ - if (git__utf16_to_8_alloc(&utf8_msg, lpMsgBuf) < 0) + if (git_utf8_from_16_alloc(&utf8_msg, lpMsgBuf) < 0) utf8_msg = NULL; LocalFree(lpMsgBuf); diff --git a/src/util/win32/path_w32.c b/src/util/win32/path_w32.c index d9fc8292b0c..7a559e45c58 100644 --- a/src/util/win32/path_w32.c +++ b/src/util/win32/path_w32.c @@ -336,13 +336,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) /* See if this is an absolute path (beginning with a drive letter) */ if (git_fs_path_is_absolute(src)) { - if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src) < 0) + if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src) < 0) goto on_error; } /* File-prefixed NT-style paths beginning with \\?\ */ else if (path__is_nt_namespace(src)) { /* Skip the NT prefix, the destination already contains it */ - if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src + PATH__NT_NAMESPACE_LEN) < 0) + if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src + PATH__NT_NAMESPACE_LEN) < 0) goto on_error; } /* UNC paths */ @@ -351,7 +351,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) dest += 4; /* Skip the leading "\\" */ - if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX - 2, src + 2) < 0) + if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX - 2, src + 2) < 0) goto on_error; } /* Absolute paths omitting the drive letter */ @@ -365,7 +365,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) } /* Skip the drive letter specification ("C:") */ - if (git__utf8_to_16(dest + 2, GIT_WIN_PATH_MAX - 2, src) < 0) + if (git_utf8_to_16(dest + 2, GIT_WIN_PATH_MAX - 2, src) < 0) goto on_error; } /* Relative paths */ @@ -377,7 +377,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) dest[cwd_len++] = L'\\'; - if (git__utf8_to_16(dest + cwd_len, GIT_WIN_PATH_MAX - cwd_len, src) < 0) + if (git_utf8_to_16(dest + cwd_len, GIT_WIN_PATH_MAX - cwd_len, src) < 0) goto on_error; } @@ -404,7 +404,7 @@ int git_win32_path_relative_from_utf8(git_win32_path out, const char *src) return git_win32_path_from_utf8(out, src); } - if ((len = git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src)) < 0) + if ((len = git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src)) < 0) return -1; for (p = dest; p < (dest + len); p++) { @@ -433,7 +433,7 @@ int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src) } } - if ((len = git__utf16_to_8(out, GIT_WIN_PATH_UTF8, src)) < 0) + if ((len = git_utf8_from_16(out, GIT_WIN_PATH_UTF8, src)) < 0) return len; git_fs_path_mkposix(dest); @@ -471,7 +471,7 @@ char *git_win32_path_8dot3_name(const char *path) if (namelen > 12 || (shortname = git__malloc(namelen + 1)) == NULL) return NULL; - if ((len = git__utf16_to_8(shortname, namelen + 1, start)) < 0) + if ((len = git_utf8_from_16(shortname, namelen + 1, start)) < 0) return NULL; return shortname; diff --git a/src/util/win32/posix_w32.c b/src/util/win32/posix_w32.c index 5862e5c9ad6..3fec469a648 100644 --- a/src/util/win32/posix_w32.c +++ b/src/util/win32/posix_w32.c @@ -649,7 +649,7 @@ int p_getcwd(char *buffer_out, size_t size) git_win32_path_remove_namespace(cwd, wcslen(cwd)); /* Convert the working directory back to UTF-8 */ - if (git__utf16_to_8(buffer_out, size, cwd) < 0) { + if (git_utf8_from_16(buffer_out, size, cwd) < 0) { DWORD code = GetLastError(); if (code == ERROR_INSUFFICIENT_BUFFER) diff --git a/src/util/win32/utf-conv.c b/src/util/win32/utf-conv.c index 4bde3023ab6..ad35c0c35ff 100644 --- a/src/util/win32/utf-conv.c +++ b/src/util/win32/utf-conv.c @@ -15,108 +15,114 @@ GIT_INLINE(void) git__set_errno(void) errno = EINVAL; } -/** - * Converts a UTF-8 string to wide characters. - * - * @param dest The buffer to receive the wide string. - * @param dest_size The size of the buffer, in characters. - * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure - */ -int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src) +int git_utf8_to_16(wchar_t *dest, size_t dest_size, const char *src) +{ + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_to_16_with_len(dest, dest_size, src, -1); +} + +int git_utf8_to_16_with_len( + wchar_t *dest, + size_t _dest_size, + const char *src, + int src_len) { + int dest_size = (int)min(_dest_size, INT_MAX); int len; - /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to - * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's - * length. MultiByteToWideChar never returns int's minvalue, so underflow is not possible */ - if ((len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size) - 1) < 0) + /* + * Subtract 1 from the result to turn 0 into -1 (an error code) and + * to not count the NULL terminator as part of the string's length. + * MultiByteToWideChar never returns int's minvalue, so underflow + * is not possible. + */ + len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + src, src_len, dest, dest_size) - 1; + + if (len < 0) git__set_errno(); return len; } -/** - * Converts a wide string to UTF-8. - * - * @param dest The buffer to receive the UTF-8 string. - * @param dest_size The size of the buffer, in bytes. - * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure - */ -int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src) +int git_utf8_from_16(char *dest, size_t dest_size, const wchar_t *src) { + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_from_16_with_len(dest, dest_size, src, -1); +} + +int git_utf8_from_16_with_len( + char *dest, + size_t _dest_size, + const wchar_t *src, + int src_len) +{ + int dest_size = (int)min(_dest_size, INT_MAX); int len; - /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to - * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's - * length. WideCharToMultiByte never returns int's minvalue, so underflow is not possible */ - if ((len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size, NULL, NULL) - 1) < 0) + /* + * Subtract 1 from the result to turn 0 into -1 (an error code) and + * to not count the NULL terminator as part of the string's length. + * WideCharToMultiByte never returns int's minvalue, so underflow + * is not possible. + */ + len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + src, src_len, dest, dest_size, NULL, NULL) - 1; + + if (len < 0) git__set_errno(); return len; } -/** - * Converts a UTF-8 string to wide characters. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. - * - * @param dest Receives a pointer to the wide string. - * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure - */ -int git__utf8_to_16_alloc(wchar_t **dest, const char *src) +int git_utf8_to_16_alloc(wchar_t **dest, const char *src) +{ + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_to_16_alloc_with_len(dest, src, -1); +} + +int git_utf8_to_16_alloc_with_len(wchar_t **dest, const char *src, int src_len) { int utf16_size; *dest = NULL; - /* Length of -1 indicates NULL termination of the input string */ - utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0); + utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + src, src_len, NULL, 0); if (!utf16_size) { git__set_errno(); return -1; } - if (!(*dest = git__mallocarray(utf16_size, sizeof(wchar_t)))) { - errno = ENOMEM; - return -1; - } + *dest = git__mallocarray(utf16_size, sizeof(wchar_t)); + GIT_ERROR_CHECK_ALLOC(*dest); - utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size); - - if (!utf16_size) { - git__set_errno(); + utf16_size = git_utf8_to_16_with_len(*dest, (size_t)utf16_size, + src, src_len); + if (utf16_size < 0) { git__free(*dest); *dest = NULL; } - /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL - * terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue, - * so underflow is not possible */ - return utf16_size - 1; + return utf16_size; } -/** - * Converts a wide string to UTF-8. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. - * - * @param dest Receives a pointer to the UTF-8 string. - * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure - */ -int git__utf16_to_8_alloc(char **dest, const wchar_t *src) +int git_utf8_from_16_alloc(char **dest, const wchar_t *src) +{ + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_from_16_alloc_with_len(dest, src, -1); +} + +int git_utf8_from_16_alloc_with_len(char **dest, const wchar_t *src, int src_len) { int utf8_size; *dest = NULL; - /* Length of -1 indicates NULL termination of the input string */ - utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL); + utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + src, src_len, NULL, 0, NULL, NULL); if (!utf8_size) { git__set_errno(); @@ -124,23 +130,15 @@ int git__utf16_to_8_alloc(char **dest, const wchar_t *src) } *dest = git__malloc(utf8_size); + GIT_ERROR_CHECK_ALLOC(*dest); - if (!*dest) { - errno = ENOMEM; - return -1; - } - - utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, *dest, utf8_size, NULL, NULL); - - if (!utf8_size) { - git__set_errno(); + utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + src, src_len, *dest, utf8_size, NULL, NULL); + if (utf8_size < 0) { git__free(*dest); *dest = NULL; } - /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL - * terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue, - * so underflow is not possible */ - return utf8_size - 1; + return utf8_size; } diff --git a/src/util/win32/utf-conv.h b/src/util/win32/utf-conv.h index 120d647efdf..301f5a6d36c 100644 --- a/src/util/win32/utf-conv.h +++ b/src/util/win32/utf-conv.h @@ -15,15 +15,46 @@ # define WC_ERR_INVALID_CHARS 0x80 #endif +/** + * Converts a NUL-terminated UTF-8 string to wide characters. This is a + * convenience function for `git_utf8_to_16_with_len`. + * + * @param dest The buffer to receive the wide string. + * @param dest_size The size of the buffer, in characters. + * @param src The UTF-8 string to convert. + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_to_16(wchar_t *dest, size_t dest_size, const char *src); + /** * Converts a UTF-8 string to wide characters. * * @param dest The buffer to receive the wide string. * @param dest_size The size of the buffer, in characters. * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure + * @param src_len The length of the string to convert. + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_to_16_with_len( + wchar_t *dest, + size_t dest_size, + const char *src, + int src_len); + +/** + * Converts a NUL-terminated wide string to UTF-8. This is a convenience + * function for `git_utf8_from_16_with_len`. + * + * @param dest The buffer to receive the UTF-8 string. + * @param dest_size The size of the buffer, in bytes. + * @param src The wide string to convert. + * @param src_len The length of the string to convert. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure */ -int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src); +int git_utf8_from_16(char *dest, size_t dest_size, const wchar_t *src); /** * Converts a wide string to UTF-8. @@ -31,30 +62,66 @@ int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src); * @param dest The buffer to receive the UTF-8 string. * @param dest_size The size of the buffer, in bytes. * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure + * @param src_len The length of the string to convert. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure */ -int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src); +int git_utf8_from_16_with_len(char *dest, size_t dest_size, const wchar_t *src, int src_len); /** - * Converts a UTF-8 string to wide characters. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. + * Converts a UTF-8 string to wide characters. Memory is allocated to hold + * the converted string. The caller is responsible for freeing the string + * with git__free. * * @param dest Receives a pointer to the wide string. * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure */ -int git__utf8_to_16_alloc(wchar_t **dest, const char *src); +int git_utf8_to_16_alloc(wchar_t **dest, const char *src); /** - * Converts a wide string to UTF-8. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. + * Converts a UTF-8 string to wide characters. Memory is allocated to hold + * the converted string. The caller is responsible for freeing the string + * with git__free. + * + * @param dest Receives a pointer to the wide string. + * @param src The UTF-8 string to convert. + * @param src_len The length of the string. + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_to_16_alloc_with_len( + wchar_t **dest, + const char *src, + int src_len); + +/** + * Converts a wide string to UTF-8. Memory is allocated to hold the + * converted string. The caller is responsible for freeing the string + * with git__free. + * + * @param dest Receives a pointer to the UTF-8 string. + * @param src The wide string to convert. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_from_16_alloc(char **dest, const wchar_t *src); + +/** + * Converts a wide string to UTF-8. Memory is allocated to hold the + * converted string. The caller is responsible for freeing the string + * with git__free. * * @param dest Receives a pointer to the UTF-8 string. * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure + * @param src_len The length of the wide string. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure */ -int git__utf16_to_8_alloc(char **dest, const wchar_t *src); +int git_utf8_from_16_alloc_with_len( + char **dest, + const wchar_t *src, + int src_len); #endif diff --git a/src/util/win32/w32_util.c b/src/util/win32/w32_util.c index fe4b75baefd..f5b006a1974 100644 --- a/src/util/win32/w32_util.c +++ b/src/util/win32/w32_util.c @@ -115,7 +115,7 @@ int git_win32__file_attribute_to_stat( /* st_size gets the UTF-8 length of the target name, in bytes, * not counting the NULL terminator */ - if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) { + if ((st->st_size = git_utf8_from_16(NULL, 0, target)) < 0) { git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path); return -1; } diff --git a/tests/clar/clar_libgit2.c b/tests/clar/clar_libgit2.c index 54122997df7..a1b92fc336e 100644 --- a/tests/clar/clar_libgit2.c +++ b/tests/clar/clar_libgit2.c @@ -103,10 +103,10 @@ int cl_setenv(const char *name, const char *value) { wchar_t *wide_name, *wide_value = NULL; - cl_assert(git__utf8_to_16_alloc(&wide_name, name) >= 0); + cl_assert(git_utf8_to_16_alloc(&wide_name, name) >= 0); if (value) { - cl_assert(git__utf8_to_16_alloc(&wide_value, value) >= 0); + cl_assert(git_utf8_to_16_alloc(&wide_value, value) >= 0); cl_assert(SetEnvironmentVariableW(wide_name, wide_value)); } else { /* Windows XP returns 0 (failed) when passing NULL for lpValue when diff --git a/tests/util/link.c b/tests/util/link.c index 46cafada7e9..5909e26e391 100644 --- a/tests/util/link.c +++ b/tests/util/link.c @@ -98,7 +98,7 @@ static void do_junction(const char *old, const char *new) git_str_putc(&unparsed_buf, '\\'); - subst_utf16_len = git__utf8_to_16(NULL, 0, git_str_cstr(&unparsed_buf)); + subst_utf16_len = git_utf8_to_16(NULL, 0, git_str_cstr(&unparsed_buf)); subst_byte_len = subst_utf16_len * sizeof(WCHAR); print_utf16_len = subst_utf16_len - 4; @@ -124,11 +124,11 @@ static void do_junction(const char *old, const char *new) subst_utf16 = reparse_buf->ReparseBuffer.MountPoint.PathBuffer; print_utf16 = subst_utf16 + subst_utf16_len + 1; - ret = git__utf8_to_16(subst_utf16, subst_utf16_len + 1, + ret = git_utf8_to_16(subst_utf16, subst_utf16_len + 1, git_str_cstr(&unparsed_buf)); cl_assert_equal_i(subst_utf16_len, ret); - ret = git__utf8_to_16(print_utf16, + ret = git_utf8_to_16(print_utf16, print_utf16_len + 1, git_str_cstr(&unparsed_buf) + 4); cl_assert_equal_i(print_utf16_len, ret); From f15c8ac71a916bf186cd5ff81f07ca85eef82afb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 13 Mar 2023 07:08:46 -0700 Subject: [PATCH 111/816] http: add SSPI authentication on Windows Add support for SSPI on Windows, which offers NTLM and Negotiate authentication. --- cmake/SelectGSSAPI.cmake | 6 +- cmake/SelectHTTPSBackend.cmake | 4 +- src/libgit2/transports/auth_negotiate.h | 2 +- src/libgit2/transports/auth_ntlm.h | 6 +- src/libgit2/transports/auth_sspi.c | 341 ++++++++++++++++++++++++ 5 files changed, 350 insertions(+), 9 deletions(-) create mode 100644 src/libgit2/transports/auth_sspi.c diff --git a/cmake/SelectGSSAPI.cmake b/cmake/SelectGSSAPI.cmake index 24e2d68b9a7..5bde11697df 100644 --- a/cmake/SelectGSSAPI.cmake +++ b/cmake/SelectGSSAPI.cmake @@ -29,7 +29,7 @@ if(USE_GSSAPI) list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSFRAMEWORK_LIBRARIES}) set(GIT_GSSFRAMEWORK 1) - add_feature_info(SPNEGO GIT_GSSFRAMEWORK "SPNEGO authentication support (${USE_GSSAPI})") + add_feature_info(GSSAPI GIT_GSSFRAMEWORK "GSSAPI support for SPNEGO authentication (${USE_GSSAPI})") elseif(USE_GSSAPI STREQUAL "gssapi") if(NOT GSSAPI_FOUND) message(FATAL_ERROR "Asked for gssapi GSS backend, but it wasn't found") @@ -38,11 +38,11 @@ if(USE_GSSAPI) list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSAPI_LIBRARIES}) set(GIT_GSSAPI 1) - add_feature_info(SPNEGO GIT_GSSAPI "SPNEGO authentication support (${USE_GSSAPI})") + add_feature_info(GSSAPI GIT_GSSAPI "GSSAPI support for SPNEGO authentication (${USE_GSSAPI})") else() message(FATAL_ERROR "Asked for backend ${USE_GSSAPI} but it wasn't found") endif() else() set(GIT_GSSAPI 0) - add_feature_info(SPNEGO NO "SPNEGO authentication support") + add_feature_info(GSSAPI NO "GSSAPI support for SPNEGO authentication") endif() diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index 64c7a1097ce..d14941643dc 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -125,8 +125,8 @@ if(USE_HTTPS) list(APPEND LIBGIT2_PC_LIBS "-lwinhttp") endif() - list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") - list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") + list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32" "secur32") + list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32" "-lsecur32") elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") set(GIT_OPENSSL 1) set(GIT_OPENSSL_DYNAMIC 1) diff --git a/src/libgit2/transports/auth_negotiate.h b/src/libgit2/transports/auth_negotiate.h index 34aff295b13..4360785c555 100644 --- a/src/libgit2/transports/auth_negotiate.h +++ b/src/libgit2/transports/auth_negotiate.h @@ -12,7 +12,7 @@ #include "git2.h" #include "auth.h" -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) +#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) extern int git_http_auth_negotiate( git_http_auth_context **out, diff --git a/src/libgit2/transports/auth_ntlm.h b/src/libgit2/transports/auth_ntlm.h index 2bf8f41f619..33406ae94c3 100644 --- a/src/libgit2/transports/auth_ntlm.h +++ b/src/libgit2/transports/auth_ntlm.h @@ -5,15 +5,15 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef INCLUDE_transports_auth_ntlmclient_h__ -#define INCLUDE_transports_auth_ntlmclient_h__ +#ifndef INCLUDE_transports_auth_ntlm_h__ +#define INCLUDE_transports_auth_ntlm_h__ #include "auth.h" /* NTLM requires a full request/challenge/response */ #define GIT_AUTH_STEPS_NTLM 2 -#ifdef GIT_NTLM +#if defined(GIT_NTLM) || defined(GIT_WIN32) #if defined(GIT_OPENSSL) # define CRYPT_OPENSSL diff --git a/src/libgit2/transports/auth_sspi.c b/src/libgit2/transports/auth_sspi.c new file mode 100644 index 00000000000..f8269365d7f --- /dev/null +++ b/src/libgit2/transports/auth_sspi.c @@ -0,0 +1,341 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "auth_ntlm.h" +#include "auth_negotiate.h" + +#ifdef GIT_WIN32 + +#define SECURITY_WIN32 + +#include "git2.h" +#include "auth.h" +#include "git2/sys/credential.h" + +#include +#include + +typedef struct { + git_http_auth_context parent; + wchar_t *target; + + const char *package_name; + size_t package_name_len; + wchar_t *package_name_w; + SecPkgInfoW *package_info; + SEC_WINNT_AUTH_IDENTITY_W identity; + CredHandle cred; + CtxtHandle context; + + int has_identity : 1, + has_credentials : 1, + has_context : 1, + complete : 1; + git_str challenge; +} http_auth_sspi_context; + +static void sspi_reset_context(http_auth_sspi_context *ctx) +{ + if (ctx->has_identity) { + git__free(ctx->identity.User); + git__free(ctx->identity.Domain); + git__free(ctx->identity.Password); + + memset(&ctx->identity, 0, sizeof(SEC_WINNT_AUTH_IDENTITY_W)); + + ctx->has_identity = 0; + } + + if (ctx->has_credentials) { + FreeCredentialsHandle(&ctx->cred); + memset(&ctx->cred, 0, sizeof(CredHandle)); + + ctx->has_credentials = 0; + } + + if (ctx->has_context) { + DeleteSecurityContext(&ctx->context); + memset(&ctx->context, 0, sizeof(CtxtHandle)); + + ctx->has_context = 0; + } + + ctx->complete = 0; + + git_str_dispose(&ctx->challenge); +} + +static int sspi_set_challenge( + git_http_auth_context *c, + const char *challenge) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + size_t challenge_len = strlen(challenge); + + git_str_clear(&ctx->challenge); + + if (strncmp(challenge, ctx->package_name, ctx->package_name_len) != 0) { + git_error_set(GIT_ERROR_NET, "invalid %s challenge from server", ctx->package_name); + return -1; + } + + /* + * A package type indicator without a base64 payload indicates the + * mechanism; it's not an actual challenge. Ignore it. + */ + if (challenge[ctx->package_name_len] == 0) { + return 0; + } else if (challenge[ctx->package_name_len] != ' ') { + git_error_set(GIT_ERROR_NET, "invalid %s challenge from server", ctx->package_name); + return -1; + } + + if (git_str_decode_base64(&ctx->challenge, + challenge + (ctx->package_name_len + 1), + challenge_len - (ctx->package_name_len + 1)) < 0) { + git_error_set(GIT_ERROR_NET, "invalid %s challenge from server", ctx->package_name); + return -1; + } + + GIT_ASSERT(ctx->challenge.size <= ULONG_MAX); + return 0; +} + +static int create_identity( + SEC_WINNT_AUTH_IDENTITY_W **out, + http_auth_sspi_context *ctx, + git_credential *cred) +{ + git_credential_userpass_plaintext *userpass; + wchar_t *username = NULL, *domain = NULL, *password = NULL; + int username_len = 0, domain_len = 0, password_len = 0; + const char *sep; + + if (cred->credtype == GIT_CREDENTIAL_DEFAULT) { + *out = NULL; + return 0; + } + + if (cred->credtype != GIT_CREDENTIAL_USERPASS_PLAINTEXT) { + git_error_set(GIT_ERROR_NET, "unknown credential type: %d", cred->credtype); + return -1; + } + + userpass = (git_credential_userpass_plaintext *)cred; + + if ((sep = strchr(userpass->username, '\\')) != NULL) { + GIT_ASSERT(sep - userpass->username < INT_MAX); + + username_len = git_utf8_to_16_alloc(&username, sep + 1); + domain_len = git_utf8_to_16_alloc_with_len(&domain, + userpass->username, (int)(sep - userpass->username)); + } else { + username_len = git_utf8_to_16_alloc(&username, + userpass->username); + } + + password_len = git_utf8_to_16_alloc(&password, userpass->password); + + if (username_len < 0 || domain_len < 0 || password_len < 0) { + git__free(username); + git__free(domain); + git__free(password); + return -1; + } + + ctx->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + ctx->identity.User = username; + ctx->identity.UserLength = (unsigned long)username_len; + ctx->identity.Password = password; + ctx->identity.PasswordLength = (unsigned long)password_len; + ctx->identity.Domain = domain; + ctx->identity.DomainLength = (unsigned long)domain_len; + + ctx->has_identity = 1; + + *out = &ctx->identity; + + return 0; +} + +static int sspi_next_token( + git_str *buf, + git_http_auth_context *c, + git_credential *cred) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + SEC_WINNT_AUTH_IDENTITY_W *identity = NULL; + TimeStamp timestamp; + DWORD context_flags; + SecBuffer input_buf = { 0, SECBUFFER_TOKEN, NULL }; + SecBuffer output_buf = { 0, SECBUFFER_TOKEN, NULL }; + SecBufferDesc input_buf_desc = { SECBUFFER_VERSION, 1, &input_buf }; + SecBufferDesc output_buf_desc = { SECBUFFER_VERSION, 1, &output_buf }; + SECURITY_STATUS status; + + if (ctx->complete) + sspi_reset_context(ctx); + + if (!ctx->has_context) { + if (create_identity(&identity, ctx, cred) < 0) + return -1; + + status = AcquireCredentialsHandleW(NULL, ctx->package_name_w, + SECPKG_CRED_BOTH, NULL, identity, NULL, + NULL, &ctx->cred, ×tamp); + + if (status != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not acquire credentials"); + return -1; + } + + ctx->has_credentials = 1; + } + + context_flags = ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_MUTUAL_AUTH; + + if (ctx->challenge.size > 0) { + input_buf.BufferType = SECBUFFER_TOKEN; + input_buf.cbBuffer = (unsigned long)ctx->challenge.size; + input_buf.pvBuffer = ctx->challenge.ptr; + } + + status = InitializeSecurityContextW(&ctx->cred, + ctx->has_context ? &ctx->context : NULL, + ctx->target, + context_flags, + 0, + SECURITY_NETWORK_DREP, + ctx->has_context ? &input_buf_desc : NULL, + 0, + ctx->has_context ? NULL : &ctx->context, + &output_buf_desc, + &context_flags, + NULL); + + if (status == SEC_I_COMPLETE_AND_CONTINUE || + status == SEC_I_COMPLETE_NEEDED) + status = CompleteAuthToken(&ctx->context, &output_buf_desc); + + if (status == SEC_E_OK) { + ctx->complete = 1; + } else if (status != SEC_I_CONTINUE_NEEDED) { + git_error_set(GIT_ERROR_OS, "could not initialize security context"); + return -1; + } + + ctx->has_context = 1; + git_str_clear(&ctx->challenge); + + if (output_buf.cbBuffer > 0) { + git_str_put(buf, ctx->package_name, ctx->package_name_len); + git_str_putc(buf, ' '); + git_str_encode_base64(buf, output_buf.pvBuffer, output_buf.cbBuffer); + + FreeContextBuffer(output_buf.pvBuffer); + + if (git_str_oom(buf)) + return -1; + } + + return 0; +} + +static int sspi_is_complete(git_http_auth_context *c) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + + return ctx->complete; +} + +static void sspi_context_free(git_http_auth_context *c) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + + sspi_reset_context(ctx); + + FreeContextBuffer(ctx->package_info); + git__free(ctx->target); + git__free(ctx); +} + +static int sspi_init_context( + git_http_auth_context **out, + git_http_auth_t type, + const git_net_url *url) +{ + http_auth_sspi_context *ctx; + git_str target = GIT_STR_INIT; + + *out = NULL; + + ctx = git__calloc(1, sizeof(http_auth_sspi_context)); + GIT_ERROR_CHECK_ALLOC(ctx); + + switch (type) { + case GIT_HTTP_AUTH_NTLM: + ctx->package_name = "NTLM"; + ctx->package_name_len = CONST_STRLEN("NTLM"); + ctx->package_name_w = L"NTLM"; + ctx->parent.credtypes = GIT_CREDENTIAL_USERPASS_PLAINTEXT | + GIT_CREDENTIAL_DEFAULT; + break; + case GIT_HTTP_AUTH_NEGOTIATE: + ctx->package_name = "Negotiate"; + ctx->package_name_len = CONST_STRLEN("Negotiate"); + ctx->package_name_w = L"Negotiate"; + ctx->parent.credtypes = GIT_CREDENTIAL_DEFAULT; + break; + default: + git_error_set(GIT_ERROR_NET, "unknown SSPI auth type: %d", ctx->parent.type); + git__free(ctx); + return -1; + } + + if (QuerySecurityPackageInfoW(ctx->package_name_w, &ctx->package_info) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not query security package"); + git__free(ctx); + return -1; + } + + if (git_str_printf(&target, "http/%s", url->host) < 0 || + git_utf8_to_16_alloc(&ctx->target, target.ptr) < 0) { + FreeContextBuffer(ctx->package_info); + git__free(ctx); + return -1; + } + + ctx->parent.type = type; + ctx->parent.connection_affinity = 1; + ctx->parent.set_challenge = sspi_set_challenge; + ctx->parent.next_token = sspi_next_token; + ctx->parent.is_complete = sspi_is_complete; + ctx->parent.free = sspi_context_free; + + *out = (git_http_auth_context *)ctx; + + git_str_dispose(&target); + return 0; +} + +int git_http_auth_negotiate( + git_http_auth_context **out, + const git_net_url *url) +{ + return sspi_init_context(out, GIT_HTTP_AUTH_NEGOTIATE, url); +} + +int git_http_auth_ntlm( + git_http_auth_context **out, + const git_net_url *url) +{ + return sspi_init_context(out, GIT_HTTP_AUTH_NTLM, url); +} + +#endif /* GIT_WIN32 */ From 2173ca8a4196c762fa34474b583ba6e9f25e67ff Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 21 Mar 2023 10:13:23 +0000 Subject: [PATCH 112/816] v1.6.3: update version numbers --- CMakeLists.txt | 2 +- include/git2/version.h | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 710915da1bd..94627f54dd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.6.2" LANGUAGES C) +project(libgit2 VERSION "1.6.3" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") diff --git a/include/git2/version.h b/include/git2/version.h index 8b5eb31386f..78750740aca 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,7 +11,7 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.6.2" +#define LIBGIT2_VERSION "1.6.3" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 @@ -20,7 +20,7 @@ #define LIBGIT2_VER_MINOR 6 /** The revision ("teeny") version number for this version of libgit2. */ -#define LIBGIT2_VER_REVISION 2 +#define LIBGIT2_VER_REVISION 3 /** The Windows DLL patch number for this version of libgit2. */ #define LIBGIT2_VER_PATCH 0 diff --git a/package.json b/package.json index e29459efddd..5665b4edd02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.6.2", + "version": "1.6.3", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From a1826a8b1ba36027caaa03eb4d29474bd4420fef Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 21 Mar 2023 10:15:25 +0000 Subject: [PATCH 113/816] v1.6.3: update changelog --- docs/changelog.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index f685234aaee..20e48a084de 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,26 @@ +v1.6.3 +------ + +## What's Changed + +### Bug fixes + +* odb: restore `git_odb_open` by @ethomson in https://github.com/libgit2/libgit2/pull/6520 +* Ensure that `git_index_add_all` handles ignored directories by @ethomson in https://github.com/libgit2/libgit2/pull/6521 +* pack: use 64 bits for the number of objects by @carlosmn in https://github.com/libgit2/libgit2/pull/6530 + +### Build and CI improvements + +* Remove unused wditer variable by @georgthegreat in https://github.com/libgit2/libgit2/pull/6518 +* fs_path: let root run the ownership tests by @ethomson in https://github.com/libgit2/libgit2/pull/6513 +* sysdir: Do not declare win32 functions on non-win32 platforms by @Batchyx in https://github.com/libgit2/libgit2/pull/6527 +* cmake: don't include `include/git2` by @ethomson in https://github.com/libgit2/libgit2/pull/6529 + +## New Contributors +* @georgthegreat made their first contribution in https://github.com/libgit2/libgit2/pull/6518 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.6.2...v1.6.3 + v1.6.2 ------ From 4edf6c114118232da86d4de1543222b12ca960ae Mon Sep 17 00:00:00 2001 From: Miguel Arroz <750683+arroz@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:07:57 -0700 Subject: [PATCH 114/816] Partial fix for #6532: insert-by-date order. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes the following issues: 1. In `git_revwalk__push_commit`, if `opts->insert_by_date` is true, `git_commit_list_insert_by_date` is called. However, by this point the commit wasn’t parsed yet, so the `time` field still has 0 as value. Solved by parsing the commit immediately if `opts->insert_by_date` is true. 2. In the same function, there was an error in the boolean logic. When `opts->insert_by_date` was true, the commit would be inserted twice, first “by date” (not really, due to the issue described above) and then in the first position again. Logic was corrected. 3. In `prepare_walk`, when processing `user_input` and building the `commits` list, the order was being inverted. Assuming both fixes above, this would mean we would start negotiation by the oldest reference, not the newest one. This was fixed by producing a `commits` list in the same order as `user_input`. The output list for the list of “have” statements during the negotiation is still not the same as core git’s because there is an optimization missing (excluding ancestors of commits known to be common between the client and the server) but this commit brings it much closer to core git’s. Specifically, the example on the #6532 issue description now fetches exactly the same objects than core git, and other examples I tested as well. --- src/libgit2/commit_list.c | 11 ++++++++--- src/libgit2/commit_list.h | 1 + src/libgit2/revwalk.c | 30 ++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/libgit2/commit_list.c b/src/libgit2/commit_list.c index 12b329b251e..2e28d5caf8a 100644 --- a/src/libgit2/commit_list.c +++ b/src/libgit2/commit_list.c @@ -43,13 +43,18 @@ int git_commit_list_time_cmp(const void *a, const void *b) return 0; } -git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p) -{ +git_commit_list *git_commit_list_create(git_commit_list_node *item, git_commit_list *next) { git_commit_list *new_list = git__malloc(sizeof(git_commit_list)); if (new_list != NULL) { new_list->item = item; - new_list->next = *list_p; + new_list->next = next; } + return new_list; +} + +git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p) +{ + git_commit_list *new_list = git_commit_list_create(item, *list_p); *list_p = new_list; return new_list; } diff --git a/src/libgit2/commit_list.h b/src/libgit2/commit_list.h index aad39f3513b..e2dbd2aaed3 100644 --- a/src/libgit2/commit_list.h +++ b/src/libgit2/commit_list.h @@ -49,6 +49,7 @@ git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk); int git_commit_list_generation_cmp(const void *a, const void *b); int git_commit_list_time_cmp(const void *a, const void *b); void git_commit_list_free(git_commit_list **list_p); +git_commit_list *git_commit_list_create(git_commit_list_node *item, git_commit_list *next); git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p); git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_commit_list **list_p); int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit); diff --git a/src/libgit2/revwalk.c b/src/libgit2/revwalk.c index 3269d9279b6..4ea6fae8ffb 100644 --- a/src/libgit2/revwalk.c +++ b/src/libgit2/revwalk.c @@ -83,8 +83,13 @@ int git_revwalk__push_commit(git_revwalk *walk, const git_oid *oid, const git_re commit->uninteresting = opts->uninteresting; list = walk->user_input; - if ((opts->insert_by_date && - git_commit_list_insert_by_date(commit, &list) == NULL) || + + /* To insert by date, we need to parse so we know the date. */ + if (opts->insert_by_date && ((error = git_commit_list_parse(walk, commit)) < 0)) + return error; + + if ((opts->insert_by_date == 0 || + git_commit_list_insert_by_date(commit, &list) == NULL) && git_commit_list_insert(commit, &list) == NULL) { git_error_set_oom(); return -1; @@ -609,7 +614,7 @@ static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, g static int prepare_walk(git_revwalk *walk) { int error = 0; - git_commit_list *list, *commits = NULL; + git_commit_list *list, *commits = NULL, *commits_last = NULL; git_commit_list_node *next; /* If there were no pushes, we know that the walk is already over */ @@ -618,6 +623,12 @@ static int prepare_walk(git_revwalk *walk) return GIT_ITEROVER; } + /* + * This is a bit convoluted, but necessary to maintain the order of + * the commits. This is especially important in situations where + * git_revwalk__push_glob is called with a git_revwalk__push_options + * setting insert_by_date = 1, which is critical for fetch negotiation. + */ for (list = walk->user_input; list; list = list->next) { git_commit_list_node *commit = list->item; if ((error = git_commit_list_parse(walk, commit)) < 0) @@ -627,8 +638,19 @@ static int prepare_walk(git_revwalk *walk) mark_parents_uninteresting(commit); if (!commit->seen) { + git_commit_list *new_list = NULL; + if ((new_list = git_commit_list_create(commit, NULL)) == NULL) { + git_error_set_oom(); + return -1; + } + commit->seen = 1; - git_commit_list_insert(commit, &commits); + if (commits_last == NULL) + commits = new_list; + else + commits_last->next = new_list; + + commits_last = new_list; } } From dc7bca58eef9c9d2d0589e6363793b9425ff0be0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 4 Apr 2023 09:04:24 +0100 Subject: [PATCH 115/816] repo: free data in the discovery tests Shocked that our leak checkers didn't find this earlier. --- tests/libgit2/repo/discover.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/libgit2/repo/discover.c b/tests/libgit2/repo/discover.c index 523fdf8e395..983d75e3ae5 100644 --- a/tests/libgit2/repo/discover.c +++ b/tests/libgit2/repo/discover.c @@ -122,7 +122,10 @@ void test_repo_discover__cleanup(void) void test_repo_discover__discovering_repo_with_exact_path_succeeds(void) { cl_git_pass(git_repository_discover(&discovered, DISCOVER_FOLDER, 0, ceiling_dirs.ptr)); + git_buf_dispose(&discovered); + cl_git_pass(git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs.ptr)); + git_buf_dispose(&discovered); } void test_repo_discover__discovering_nonexistent_dir_fails(void) From 19065e59601e6fd6f3041d4f9a6de8b105b27cc3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 3 Apr 2023 11:27:03 +0100 Subject: [PATCH 116/816] repo: change error message "Could not find repository from ..." doesn't make sense. "Could not find repository _at_ ..." does not indicate that we walked down the path hierarchy, but at least it's more correct. --- src/libgit2/repository.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index e16413f763f..00c139a6469 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -757,7 +757,7 @@ static int find_repo( /* If we didn't find the repository, and we don't have any other error * to report, report that. */ if (!git_str_len(gitdir_path)) { - git_error_set(GIT_ERROR_REPOSITORY, "could not find repository from '%s'", start_path); + git_error_set(GIT_ERROR_REPOSITORY, "could not find repository at '%s'", start_path); error = GIT_ENOTFOUND; goto out; } From 54a22f536557b9a25752c6b59829dff4cbee99e0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 3 Apr 2023 09:52:30 +0100 Subject: [PATCH 117/816] env: remove the _from_env function Remove the `_git_repository_open_ext_from_env` and make it part of the general repository opening code path. This removes the re-entrancy, and standardizes things like index and config opening to a single place again so that we have predictable ordering of the opening procedure. --- src/libgit2/repository.c | 455 ++++++++++++++++++++------------------- src/libgit2/repository.h | 5 +- 2 files changed, 233 insertions(+), 227 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 00c139a6469..fe0f1a4efae 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -637,14 +637,28 @@ static int validate_ownership(git_repository *repo) return error; } -static int find_repo( - git_str *gitdir_path, - git_str *workdir_path, - git_str *gitlink_path, - git_str *commondir_path, +struct repo_paths { + git_str gitdir; + git_str workdir; + git_str gitlink; + git_str commondir; +}; + +#define REPO_PATHS_INIT { GIT_STR_INIT } + +GIT_INLINE(void) repo_paths_dispose(struct repo_paths *paths) +{ + git_str_dispose(&paths->gitdir); + git_str_dispose(&paths->workdir); + git_str_dispose(&paths->gitlink); + git_str_dispose(&paths->commondir); +} + +static int find_repo_traverse( + struct repo_paths *out, const char *start_path, - uint32_t flags, - const char *ceiling_dirs) + const char *ceiling_dirs, + uint32_t flags) { git_str path = GIT_STR_INIT; git_str repo_link = GIT_STR_INIT; @@ -656,19 +670,23 @@ static int find_repo( size_t ceiling_offset = 0; int error; - git_str_clear(gitdir_path); + git_str_clear(&out->gitdir); - error = git_fs_path_prettify(&path, start_path, NULL); - if (error < 0) + if ((error = git_fs_path_prettify(&path, start_path, NULL)) < 0) return error; - /* in_dot_git toggles each loop: + /* + * In each loop we look first for a `.git` dir within the + * directory, then to see if the directory itself is a repo. + * + * In other words: if we start in /a/b/c, then we look at: * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a - * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, we - * assume we started with /a/b/c.git and don't append .git the first - * time through. - * min_iterations indicates the number of iterations left before going - * further counts as a search. */ + * + * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, + * we assume we started with /a/b/c.git and don't append .git the + * first time through. min_iterations indicates the number of + * iterations left before going further counts as a search. + */ if (flags & (GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT)) { in_dot_git = true; min_iterations = 1; @@ -700,14 +718,13 @@ static int find_repo( if (is_valid) { if ((error = git_fs_path_to_dir(&path)) < 0 || - (error = git_str_set(gitdir_path, path.ptr, path.size)) < 0) + (error = git_str_set(&out->gitdir, path.ptr, path.size)) < 0) goto out; - if (gitlink_path) - if ((error = git_str_attach(gitlink_path, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0) - goto out; - if (commondir_path) - git_str_swap(&common_link, commondir_path); + if ((error = git_str_attach(&out->gitlink, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0) + goto out; + + git_str_swap(&common_link, &out->commondir); break; } @@ -717,26 +734,30 @@ static int find_repo( goto out; if (is_valid) { - git_str_swap(gitdir_path, &repo_link); + git_str_swap(&out->gitdir, &repo_link); - if (gitlink_path) - if ((error = git_str_put(gitlink_path, path.ptr, path.size)) < 0) - goto out; - if (commondir_path) - git_str_swap(&common_link, commondir_path); + if ((error = git_str_put(&out->gitlink, path.ptr, path.size)) < 0) + goto out; + + git_str_swap(&common_link, &out->commondir); } break; } } - /* Move up one directory. If we're in_dot_git, we'll search the - * parent itself next. If we're !in_dot_git, we'll search .git - * in the parent directory next (added at the top of the loop). */ + /* + * Move up one directory. If we're in_dot_git, we'll + * search the parent itself next. If we're !in_dot_git, + * we'll search .git in the parent directory next (added + * at the top of the loop). + */ if ((error = git_fs_path_dirname_r(&path, path.ptr)) < 0) goto out; - /* Once we've checked the directory (and .git if applicable), - * find the ceiling for a search. */ + /* + * Once we've checked the directory (and .git if + * applicable), find the ceiling for a search. + */ if (min_iterations && (--min_iterations == 0)) ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); @@ -746,29 +767,96 @@ static int find_repo( break; } - if (workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { - if (!git_str_len(gitdir_path)) - git_str_clear(workdir_path); - else if ((error = git_fs_path_dirname_r(workdir_path, path.ptr)) < 0 || - (error = git_fs_path_to_dir(workdir_path)) < 0) + if (!(flags & GIT_REPOSITORY_OPEN_BARE)) { + if (!git_str_len(&out->gitdir)) + git_str_clear(&out->workdir); + else if ((error = git_fs_path_dirname_r(&out->workdir, path.ptr)) < 0 || + (error = git_fs_path_to_dir(&out->workdir)) < 0) goto out; } - /* If we didn't find the repository, and we don't have any other error - * to report, report that. */ - if (!git_str_len(gitdir_path)) { + /* If we didn't find the repository, and we don't have any other + * error to report, report that. */ + if (!git_str_len(&out->gitdir)) { git_error_set(GIT_ERROR_REPOSITORY, "could not find repository at '%s'", start_path); error = GIT_ENOTFOUND; goto out; } out: + if (error) + repo_paths_dispose(out); + git_str_dispose(&path); git_str_dispose(&repo_link); git_str_dispose(&common_link); return error; } +static int find_repo( + struct repo_paths *out, + const char *start_path, + const char *ceiling_dirs, + uint32_t flags) +{ + bool use_env = !!(flags & GIT_REPOSITORY_OPEN_FROM_ENV); + git_str gitdir_buf = GIT_STR_INIT, + ceiling_dirs_buf = GIT_STR_INIT, + across_fs_buf = GIT_STR_INIT; + int error; + + if (use_env && !start_path) { + error = git__getenv(&gitdir_buf, "GIT_DIR"); + + if (!error) { + start_path = gitdir_buf.ptr; + flags |= GIT_REPOSITORY_OPEN_NO_SEARCH; + flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT; + } else if (error == GIT_ENOTFOUND) { + start_path = "."; + } else { + goto done; + } + } + + if (use_env && !ceiling_dirs) { + error = git__getenv(&ceiling_dirs_buf, + "GIT_CEILING_DIRECTORIES"); + + if (!error) + ceiling_dirs = ceiling_dirs_buf.ptr; + else if (error != GIT_ENOTFOUND) + goto done; + } + + if (use_env) { + error = git__getenv(&across_fs_buf, + "GIT_DISCOVERY_ACROSS_FILESYSTEM"); + + if (!error) { + int across_fs = 0; + + if ((error = git_config_parse_bool(&across_fs, + git_str_cstr(&across_fs_buf))) < 0) + goto done; + + if (across_fs) + flags |= GIT_REPOSITORY_OPEN_CROSS_FS; + } else if (error != GIT_ENOTFOUND) { + goto done; + } + } + + error = find_repo_traverse(out, start_path, ceiling_dirs, flags); + +done: + git_str_dispose(&gitdir_buf); + git_str_dispose(&ceiling_dirs_buf); + git_str_dispose(&across_fs_buf); + + return error; +} + static int obtain_config_and_set_oid_type( git_config **config_ptr, git_repository *repo) @@ -787,7 +875,7 @@ static int obtain_config_and_set_oid_type( goto out; if (config && - (error = check_repositoryformatversion(&version, config)) < 0) + (error = check_repositoryformatversion(&version, config)) < 0) goto out; if ((error = check_extensions(config, version)) < 0) @@ -851,173 +939,22 @@ int git_repository_open_bare( return error; } -static int _git_repository_open_ext_from_env( - git_repository **out, - const char *start_path) +static int repo_load_namespace(git_repository *repo) { - git_repository *repo = NULL; - git_index *index = NULL; - git_odb *odb = NULL; - git_str dir_buf = GIT_STR_INIT; - git_str ceiling_dirs_buf = GIT_STR_INIT; - git_str across_fs_buf = GIT_STR_INIT; - git_str index_file_buf = GIT_STR_INIT; git_str namespace_buf = GIT_STR_INIT; - git_str object_dir_buf = GIT_STR_INIT; - git_str alts_buf = GIT_STR_INIT; - git_str work_tree_buf = GIT_STR_INIT; - git_str common_dir_buf = GIT_STR_INIT; - const char *ceiling_dirs = NULL; - unsigned flags = 0; int error; - if (!start_path) { - error = git__getenv(&dir_buf, "GIT_DIR"); - if (error == GIT_ENOTFOUND) { - git_error_clear(); - start_path = "."; - } else if (error < 0) - goto error; - else { - start_path = git_str_cstr(&dir_buf); - flags |= GIT_REPOSITORY_OPEN_NO_SEARCH; - flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT; - } - } - - error = git__getenv(&ceiling_dirs_buf, "GIT_CEILING_DIRECTORIES"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else - ceiling_dirs = git_str_cstr(&ceiling_dirs_buf); - - error = git__getenv(&across_fs_buf, "GIT_DISCOVERY_ACROSS_FILESYSTEM"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - int across_fs = 0; - error = git_config_parse_bool(&across_fs, git_str_cstr(&across_fs_buf)); - if (error < 0) - goto error; - if (across_fs) - flags |= GIT_REPOSITORY_OPEN_CROSS_FS; - } - - error = git__getenv(&index_file_buf, "GIT_INDEX_FILE"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - error = git_index_open(&index, git_str_cstr(&index_file_buf)); - if (error < 0) - goto error; - } + if (!repo->use_env) + return 0; error = git__getenv(&namespace_buf, "GIT_NAMESPACE"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - - error = git__getenv(&object_dir_buf, "GIT_OBJECT_DIRECTORY"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - error = git_odb__open(&odb, git_str_cstr(&object_dir_buf), NULL); - if (error < 0) - goto error; - } - - error = git__getenv(&work_tree_buf, "GIT_WORK_TREE"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - git_error_set(GIT_ERROR_INVALID, "GIT_WORK_TREE unimplemented"); - error = GIT_ERROR; - goto error; - } - - error = git__getenv(&work_tree_buf, "GIT_COMMON_DIR"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - git_error_set(GIT_ERROR_INVALID, "GIT_COMMON_DIR unimplemented"); - error = GIT_ERROR; - goto error; - } - error = git_repository_open_ext(&repo, start_path, flags, ceiling_dirs); - if (error < 0) - goto error; - - if (odb) - git_repository_set_odb(repo, odb); - - error = git__getenv(&alts_buf, "GIT_ALTERNATE_OBJECT_DIRECTORIES"); - if (error == GIT_ENOTFOUND) { - git_error_clear(); - error = 0; - } else if (error < 0) - goto error; - else { - const char *end; - char *alt, *sep; - if (!odb) { - error = git_repository_odb(&odb, repo); - if (error < 0) - goto error; - } - - end = git_str_cstr(&alts_buf) + git_str_len(&alts_buf); - for (sep = alt = alts_buf.ptr; sep != end; alt = sep+1) { - for (sep = alt; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++) - ; - if (*sep) - *sep = '\0'; - error = git_odb_add_disk_alternate(odb, alt); - if (error < 0) - goto error; - } - } + if (error == 0) + repo->namespace = git_str_detach(&namespace_buf); + else if (error != GIT_ENOTFOUND) + return error; - if (git_str_len(&namespace_buf)) { - error = git_repository_set_namespace(repo, git_str_cstr(&namespace_buf)); - if (error < 0) - goto error; - } - - git_repository_set_index(repo, index); - - if (out) { - *out = repo; - goto success; - } -error: - git_repository_free(repo); -success: - git_odb_free(odb); - git_index_free(index); - git_str_dispose(&common_dir_buf); - git_str_dispose(&work_tree_buf); - git_str_dispose(&alts_buf); - git_str_dispose(&object_dir_buf); - git_str_dispose(&namespace_buf); - git_str_dispose(&index_file_buf); - git_str_dispose(&across_fs_buf); - git_str_dispose(&ceiling_dirs_buf); - git_str_dispose(&dir_buf); - return error; + return 0; } static int repo_is_worktree(unsigned *out, const git_repository *repo) @@ -1049,21 +986,16 @@ int git_repository_open_ext( unsigned int flags, const char *ceiling_dirs) { - int error; - unsigned is_worktree; - git_str gitdir = GIT_STR_INIT, workdir = GIT_STR_INIT, - gitlink = GIT_STR_INIT, commondir = GIT_STR_INIT; + struct repo_paths paths = { GIT_STR_INIT }; git_repository *repo = NULL; git_config *config = NULL; - - if (flags & GIT_REPOSITORY_OPEN_FROM_ENV) - return _git_repository_open_ext_from_env(repo_ptr, start_path); + unsigned is_worktree; + int error; if (repo_ptr) *repo_ptr = NULL; - error = find_repo( - &gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs); + error = find_repo(&paths, start_path, ceiling_dirs, flags); if (error < 0 || !repo_ptr) goto cleanup; @@ -1071,20 +1003,23 @@ int git_repository_open_ext( repo = repository_alloc(); GIT_ERROR_CHECK_ALLOC(repo); - repo->gitdir = git_str_detach(&gitdir); + repo->use_env = !!(flags & GIT_REPOSITORY_OPEN_FROM_ENV); + + repo->gitdir = git_str_detach(&paths.gitdir); GIT_ERROR_CHECK_ALLOC(repo->gitdir); - if (gitlink.size) { - repo->gitlink = git_str_detach(&gitlink); + if (paths.gitlink.size) { + repo->gitlink = git_str_detach(&paths.gitlink); GIT_ERROR_CHECK_ALLOC(repo->gitlink); } - if (commondir.size) { - repo->commondir = git_str_detach(&commondir); + if (paths.commondir.size) { + repo->commondir = git_str_detach(&paths.commondir); GIT_ERROR_CHECK_ALLOC(repo->commondir); } if ((error = repo_is_worktree(&is_worktree, repo)) < 0) goto cleanup; + repo->is_worktree = is_worktree; error = obtain_config_and_set_oid_type(&config, repo); @@ -1096,10 +1031,13 @@ int git_repository_open_ext( } else { if (config && ((error = load_config_data(repo, config)) < 0 || - (error = load_workdir(repo, config, &workdir)) < 0)) + (error = load_workdir(repo, config, &paths.workdir)) < 0)) goto cleanup; } + if ((error = repo_load_namespace(repo)) < 0) + goto cleanup; + /* * Ensure that the git directory and worktree are * owned by the current user. @@ -1109,10 +1047,7 @@ int git_repository_open_ext( goto cleanup; cleanup: - git_str_dispose(&gitdir); - git_str_dispose(&workdir); - git_str_dispose(&gitlink); - git_str_dispose(&commondir); + repo_paths_dispose(&paths); git_config_free(config); if (error < 0) @@ -1180,11 +1115,17 @@ int git_repository_discover( int across_fs, const char *ceiling_dirs) { + struct repo_paths paths = { GIT_STR_INIT }; uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0; + int error; GIT_ASSERT_ARG(start_path); - GIT_BUF_WRAP_PRIVATE(out, find_repo, NULL, NULL, NULL, start_path, flags, ceiling_dirs); + if ((error = find_repo(&paths, start_path, ceiling_dirs, flags)) == 0) + error = git_buf_fromstr(out, &paths.gitdir); + + repo_paths_dispose(&paths); + return error; } static int load_config( @@ -1329,6 +1270,56 @@ int git_repository_set_config(git_repository *repo, git_config *config) return 0; } +static int repository_odb_path(git_str *out, git_repository *repo) +{ + int error = GIT_ENOTFOUND; + + if (repo->use_env) + error = git__getenv(out, "GIT_OBJECT_DIRECTORY"); + + if (error == GIT_ENOTFOUND) + error = git_repository__item_path(out, repo, + GIT_REPOSITORY_ITEM_OBJECTS); + + return error; +} + +static int repository_odb_alternates( + git_odb *odb, + git_repository *repo) +{ + git_str alternates = GIT_STR_INIT; + char *sep, *alt; + int error; + + if (!repo->use_env) + return 0; + + error = git__getenv(&alternates, "GIT_ALTERNATE_OBJECT_DIRECTORIES"); + + if (error != 0) + return (error == GIT_ENOTFOUND) ? 0 : error; + + alt = alternates.ptr; + + while (*alt) { + sep = strchr(alt, GIT_PATH_LIST_SEPARATOR); + + if (sep) + *sep = '\0'; + + error = git_odb_add_disk_alternate(odb, alt); + + if (sep) + alt = sep + 1; + else + break; + } + + git_str_dispose(&alternates); + return 0; +} + int git_repository_odb__weakptr(git_odb **out, git_repository *repo) { int error = 0; @@ -1344,9 +1335,9 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) odb_opts.oid_type = repo->oid_type; - if ((error = git_repository__item_path(&odb_path, repo, - GIT_REPOSITORY_ITEM_OBJECTS)) < 0 || - (error = git_odb__new(&odb, &odb_opts)) < 0) + if ((error = repository_odb_path(&odb_path, repo)) < 0 || + (error = git_odb__new(&odb, &odb_opts)) < 0 || + (error = repository_odb_alternates(odb, repo)) < 0) return error; GIT_REFCOUNT_OWN(odb, repo); @@ -1430,6 +1421,20 @@ int git_repository_set_refdb(git_repository *repo, git_refdb *refdb) return 0; } +static int repository_index_path(git_str *out, git_repository *repo) +{ + int error = GIT_ENOTFOUND; + + if (repo->use_env) + error = git__getenv(out, "GIT_INDEX_FILE"); + + if (error == GIT_ENOTFOUND) + error = git_repository__item_path(out, repo, + GIT_REPOSITORY_ITEM_INDEX); + + return error; +} + int git_repository_index__weakptr(git_index **out, git_repository *repo) { int error = 0; @@ -1441,7 +1446,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) git_str index_path = GIT_STR_INIT; git_index *index; - if ((error = git_str_joinpath(&index_path, repo->gitdir, GIT_INDEX_FILE)) < 0) + if ((error = repository_index_path(&index_path, repo)) < 0) return error; error = git_index_open(&index, index_path.ptr); diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index 75380ae5347..9a36ef97210 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -151,8 +151,9 @@ struct git_repository { git_array_t(git_str) reserved_names; - unsigned is_bare:1; - unsigned is_worktree:1; + unsigned use_env:1, + is_bare:1, + is_worktree:1; git_oid_t oid_type; unsigned int lru_counter; From b41c3dfce65fec1f6f5f009f050e61c54acf617c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 3 Apr 2023 10:38:57 +0100 Subject: [PATCH 118/816] repo: honor GIT_WORK_TREE environment variable When the repository is opened with `GIT_REPOSITORY_OPEN_FROM_ENV`, honor the `GIT_WORK_TREE` environment variable. --- src/libgit2/repository.c | 55 ++++++++++++++++++++++++++++++---------- tests/libgit2/repo/env.c | 20 +++++++++++++++ 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index fe0f1a4efae..32ffb009e5a 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -337,19 +337,42 @@ static int load_config_data(git_repository *repo, const git_config *config) return 0; } -static int load_workdir(git_repository *repo, git_config *config, git_str *parent_path) +static int load_workdir( + git_repository *repo, + git_config *config, + git_str *parent_path) { - int error; - git_config_entry *ce; + git_config_entry *ce = NULL; git_str worktree = GIT_STR_INIT; git_str path = GIT_STR_INIT; + git_str workdir_env = GIT_STR_INIT; + const char *value = NULL; + int error; if (repo->is_bare) return 0; - if ((error = git_config__lookup_entry( - &ce, config, "core.worktree", false)) < 0) - return error; + /* Environment variables are preferred */ + if (repo->use_env) { + error = git__getenv(&workdir_env, "GIT_WORK_TREE"); + + if (error == 0) + value = workdir_env.ptr; + else if (error == GIT_ENOTFOUND) + error = 0; + else + goto cleanup; + } + + /* Examine configuration values if necessary */ + if (!value) { + if ((error = git_config__lookup_entry(&ce, config, + "core.worktree", false)) < 0) + return error; + + if (ce && ce->value) + value = ce->value; + } if (repo->is_worktree) { char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE); @@ -367,17 +390,21 @@ static int load_workdir(git_repository *repo, git_config *config, git_str *paren } repo->workdir = git_str_detach(&worktree); - } - else if (ce && ce->value) { - if ((error = git_fs_path_prettify_dir( - &worktree, ce->value, repo->gitdir)) < 0) + } else if (value) { + if (!*value) { + git_error_set(GIT_ERROR_NET, "working directory cannot be set to empty path"); + error = -1; + goto cleanup; + } + + if ((error = git_fs_path_prettify_dir(&worktree, + value, repo->gitdir)) < 0) goto cleanup; repo->workdir = git_str_detach(&worktree); - } - else if (parent_path && git_fs_path_isdir(parent_path->ptr)) + } else if (parent_path && git_fs_path_isdir(parent_path->ptr)) { repo->workdir = git_str_detach(parent_path); - else { + } else { if (git_fs_path_dirname_r(&worktree, repo->gitdir) < 0 || git_fs_path_to_dir(&worktree) < 0) { error = -1; @@ -388,8 +415,10 @@ static int load_workdir(git_repository *repo, git_config *config, git_str *paren } GIT_ERROR_CHECK_ALLOC(repo->workdir); + cleanup: git_str_dispose(&path); + git_str_dispose(&workdir_env); git_config_entry_free(ce); return error; } diff --git a/tests/libgit2/repo/env.c b/tests/libgit2/repo/env.c index 790ffd40f0f..5f084ac0078 100644 --- a/tests/libgit2/repo/env.c +++ b/tests/libgit2/repo/env.c @@ -31,6 +31,8 @@ void test_repo_env__cleanup(void) if (git_fs_path_isdir("peeled.git")) git_futils_rmdir_r("peeled.git", NULL, GIT_RMDIR_REMOVE_FILES); + cl_fixture_cleanup("test_workdir"); + clear_git_env(); } @@ -275,3 +277,21 @@ void test_repo_env__open(void) clear_git_env(); } + +void test_repo_env__work_tree(void) +{ + git_repository *repo; + const char *test_path; + + cl_fixture_sandbox("attr"); + cl_git_pass(p_rename("attr/.gitted", "attr/.git")); + + cl_must_pass(p_mkdir("test_workdir", 0777)); + test_path = cl_git_sandbox_path(1, "test_workdir", NULL); + + cl_setenv("GIT_WORK_TREE", test_path); + cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); + cl_assert_equal_s(test_path, git_repository_workdir(repo)); + git_repository_free(repo); + cl_setenv("GIT_WORK_TREE", NULL); +} From 24b9c4b63374e850d165ae5f7055db6e47ff3051 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 3 Apr 2023 11:43:47 +0100 Subject: [PATCH 119/816] repo: honor GIT_COMMON_DIR when respecting env When the repository is opened with `GIT_REPOSITORY_OPEN_FROM_ENV`, honor the `GIT_COMMON_DIR` environment variable. --- src/libgit2/repository.c | 36 ++++++++++++++++++++++++++---------- tests/libgit2/repo/env.c | 20 ++++++++++++++++++++ 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 32ffb009e5a..cd0f4ad74da 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -191,11 +191,23 @@ void git_repository_free(git_repository *repo) } /* Check if we have a separate commondir (e.g. we have a worktree) */ -static int lookup_commondir(bool *separate, git_str *commondir, git_str *repository_path) +static int lookup_commondir( + bool *separate, + git_str *commondir, + git_str *repository_path, + uint32_t flags) { - git_str common_link = GIT_STR_INIT; + git_str common_link = GIT_STR_INIT; int error; + /* Environment variable overrides configuration */ + if ((flags & GIT_REPOSITORY_OPEN_FROM_ENV)) { + error = git__getenv(commondir, "GIT_COMMON_DIR"); + + if (!error || error != GIT_ENOTFOUND) + goto done; + } + /* * If there's no commondir file, the repository path is the * common path, but it needs a trailing slash. @@ -222,12 +234,11 @@ static int lookup_commondir(bool *separate, git_str *commondir, git_str *reposit git_str_swap(commondir, &common_link); } - git_str_dispose(&common_link); - /* Make sure the commondir path always has a trailing slash */ error = git_fs_path_prettify_dir(commondir, commondir->ptr, NULL); done: + git_str_dispose(&common_link); return error; } @@ -252,14 +263,19 @@ GIT_INLINE(int) validate_repo_path(git_str *path) * * Open a repository object from its path */ -static int is_valid_repository_path(bool *out, git_str *repository_path, git_str *common_path) +static int is_valid_repository_path( + bool *out, + git_str *repository_path, + git_str *common_path, + uint32_t flags) { bool separate_commondir = false; int error; *out = false; - if ((error = lookup_commondir(&separate_commondir, common_path, repository_path)) < 0) + if ((error = lookup_commondir(&separate_commondir, + common_path, repository_path, flags)) < 0) return error; /* Ensure HEAD file exists */ @@ -742,7 +758,7 @@ static int find_repo_traverse( break; if (S_ISDIR(st.st_mode)) { - if ((error = is_valid_repository_path(&is_valid, &path, &common_link)) < 0) + if ((error = is_valid_repository_path(&is_valid, &path, &common_link, flags)) < 0) goto out; if (is_valid) { @@ -759,7 +775,7 @@ static int find_repo_traverse( } } else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) { if ((error = read_gitfile(&repo_link, path.ptr)) < 0 || - (error = is_valid_repository_path(&is_valid, &repo_link, &common_link)) < 0) + (error = is_valid_repository_path(&is_valid, &repo_link, &common_link, flags)) < 0) goto out; if (is_valid) { @@ -934,7 +950,7 @@ int git_repository_open_bare( git_config *config; if ((error = git_fs_path_prettify_dir(&path, bare_path, NULL)) < 0 || - (error = is_valid_repository_path(&is_valid, &path, &common_path)) < 0) + (error = is_valid_repository_path(&is_valid, &path, &common_path, 0)) < 0) return error; if (!is_valid) { @@ -2668,7 +2684,7 @@ int git_repository_init_ext( wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_str_cstr(&wd_path); - if ((error = is_valid_repository_path(&is_valid, &repo_path, &common_path)) < 0) + if ((error = is_valid_repository_path(&is_valid, &repo_path, &common_path, opts->flags)) < 0) goto out; if (is_valid) { diff --git a/tests/libgit2/repo/env.c b/tests/libgit2/repo/env.c index 5f084ac0078..4a61581bd6b 100644 --- a/tests/libgit2/repo/env.c +++ b/tests/libgit2/repo/env.c @@ -295,3 +295,23 @@ void test_repo_env__work_tree(void) git_repository_free(repo); cl_setenv("GIT_WORK_TREE", NULL); } + +void test_repo_env__commondir(void) +{ + git_repository *repo; + const char *test_path; + + cl_fixture_sandbox("attr"); + cl_git_pass(p_rename("attr/.gitted", "attr/.git")); + + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(p_rename("testrepo.git", "test_commondir")); + + test_path = cl_git_sandbox_path(1, "test_commondir", NULL); + + cl_setenv("GIT_COMMON_DIR", test_path); + cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); + cl_assert_equal_s(test_path, git_repository_commondir(repo)); + git_repository_free(repo); + cl_setenv("GIT_COMMON_DIR", NULL); +} From 389f9b10e6e71339fe28145098a37975c49a472d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 3 Apr 2023 12:58:23 +0100 Subject: [PATCH 120/816] repo: honor GIT_CONFIG_* environment variables When the repository is opened with `GIT_REPOSITORY_OPEN_FROM_ENV`, honor the `GIT_CONFIG_GLOBAL`, `GIT_CONFIG_SYSTEM` and `GIT_CONFIG_NOSYSTEM` environment variables. --- src/libgit2/repository.c | 129 ++++++++++++++++++++++++++++----------- tests/libgit2/repo/env.c | 52 ++++++++++++++++ 2 files changed, 146 insertions(+), 35 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index cd0f4ad74da..3f57fb23cca 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -66,7 +66,7 @@ static const struct { static int check_repositoryformatversion(int *version, git_config *config); static int check_extensions(git_config *config, int version); -static int load_global_config(git_config **config); +static int load_global_config(git_config **config, bool use_env); static int load_objectformat(git_repository *repo, git_config *config); #define GIT_COMMONDIR_FILE "commondir" @@ -586,7 +586,10 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) return 0; } -static int validate_ownership_config(bool *is_safe, const char *path) +static int validate_ownership_config( + bool *is_safe, + const char *path, + bool use_env) { validate_ownership_data ownership_data = { path, GIT_STR_INIT, is_safe @@ -594,7 +597,7 @@ static int validate_ownership_config(bool *is_safe, const char *path) git_config *config; int error; - if (load_global_config(&config) != 0) + if (load_global_config(&config, use_env) != 0) return 0; error = git_config_get_multivar_foreach(config, @@ -668,7 +671,8 @@ static int validate_ownership(git_repository *repo) } if (is_safe || - (error = validate_ownership_config(&is_safe, validation_paths[0])) < 0) + (error = validate_ownership_config( + &is_safe, validation_paths[0], repo->use_env)) < 0) goto done; if (!is_safe) { @@ -1241,32 +1245,81 @@ static const char *path_unless_empty(git_str *buf) return git_str_len(buf) > 0 ? git_str_cstr(buf) : NULL; } +GIT_INLINE(int) config_path_system(git_str *out, bool use_env) +{ + if (use_env) { + git_str no_system_buf = GIT_STR_INIT; + int no_system = 0; + int error; + + error = git__getenv(&no_system_buf, "GIT_CONFIG_NOSYSTEM"); + + if (error && error != GIT_ENOTFOUND) + return error; + + error = git_config_parse_bool(&no_system, no_system_buf.ptr); + git_str_dispose(&no_system_buf); + + if (no_system) + return 0; + + error = git__getenv(out, "GIT_CONFIG_SYSTEM"); + + if (error == 0 || error != GIT_ENOTFOUND) + return 0; + } + + git_config__find_system(out); + return 0; +} + +GIT_INLINE(int) config_path_global(git_str *out, bool use_env) +{ + if (use_env) { + int error = git__getenv(out, "GIT_CONFIG_GLOBAL"); + + if (error == 0 || error != GIT_ENOTFOUND) + return 0; + } + + git_config__find_global(out); + return 0; +} + int git_repository_config__weakptr(git_config **out, git_repository *repo) { int error = 0; if (repo->_config == NULL) { + git_str system_buf = GIT_STR_INIT; git_str global_buf = GIT_STR_INIT; git_str xdg_buf = GIT_STR_INIT; - git_str system_buf = GIT_STR_INIT; git_str programdata_buf = GIT_STR_INIT; + bool use_env = repo->use_env; git_config *config; - git_config__find_global(&global_buf); - git_config__find_xdg(&xdg_buf); - git_config__find_system(&system_buf); - git_config__find_programdata(&programdata_buf); + if (!(error = config_path_system(&system_buf, use_env)) && + !(error = config_path_global(&global_buf, use_env))) { + git_config__find_xdg(&xdg_buf); + git_config__find_programdata(&programdata_buf); + } - /* If there is no global file, open a backend for it anyway */ - if (git_str_len(&global_buf) == 0) - git_config__global_location(&global_buf); + if (!error) { + /* + * If there is no global file, open a backend + * for it anyway. + */ + if (git_str_len(&global_buf) == 0) + git_config__global_location(&global_buf); + + error = load_config( + &config, repo, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf), + path_unless_empty(&programdata_buf)); + } - error = load_config( - &config, repo, - path_unless_empty(&global_buf), - path_unless_empty(&xdg_buf), - path_unless_empty(&system_buf), - path_unless_empty(&programdata_buf)); if (!error) { GIT_REFCOUNT_OWN(config, repo); @@ -1966,7 +2019,7 @@ static bool is_filesystem_case_insensitive(const char *gitdir_path) * Return a configuration object with only the global and system * configurations; no repository-level configuration. */ -static int load_global_config(git_config **config) +static int load_global_config(git_config **config, bool use_env) { git_str global_buf = GIT_STR_INIT; git_str xdg_buf = GIT_STR_INIT; @@ -1974,16 +2027,17 @@ static int load_global_config(git_config **config) git_str programdata_buf = GIT_STR_INIT; int error; - git_config__find_global(&global_buf); - git_config__find_xdg(&xdg_buf); - git_config__find_system(&system_buf); - git_config__find_programdata(&programdata_buf); + if (!(error = config_path_system(&system_buf, use_env)) && + !(error = config_path_global(&global_buf, use_env))) { + git_config__find_xdg(&xdg_buf); + git_config__find_programdata(&programdata_buf); - error = load_config(config, NULL, - path_unless_empty(&global_buf), - path_unless_empty(&xdg_buf), - path_unless_empty(&system_buf), - path_unless_empty(&programdata_buf)); + error = load_config(config, NULL, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf), + path_unless_empty(&programdata_buf)); + } git_str_dispose(&global_buf); git_str_dispose(&xdg_buf); @@ -1993,7 +2047,7 @@ static int load_global_config(git_config **config) return error; } -static bool are_symlinks_supported(const char *wd_path) +static bool are_symlinks_supported(const char *wd_path, bool use_env) { git_config *config = NULL; int symlinks = 0; @@ -2006,10 +2060,12 @@ static bool are_symlinks_supported(const char *wd_path) * _not_ set, then we do not test or enable symlink support. */ #ifdef GIT_WIN32 - if (load_global_config(&config) < 0 || + if (load_global_config(&config, use_env) < 0 || git_config_get_bool(&symlinks, config, "core.symlinks") < 0 || !symlinks) goto done; +#else + GIT_UNUSED(use_env); #endif if (!(symlinks = git_fs_path_supports_symlinks(wd_path))) @@ -2082,7 +2138,8 @@ static int repo_init_fs_configs( const char *cfg_path, const char *repo_dir, const char *work_dir, - bool update_ignorecase) + bool update_ignorecase, + bool use_env) { int error = 0; @@ -2093,7 +2150,7 @@ static int repo_init_fs_configs( cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0) return error; - if (!are_symlinks_supported(work_dir)) { + if (!are_symlinks_supported(work_dir, use_env)) { if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0) return error; } else if (git_config_delete_entry(cfg, "core.symlinks") < 0) @@ -2130,6 +2187,7 @@ static int repo_init_config( git_config *config = NULL; bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0); bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0); + bool use_env = ((flags & GIT_REPOSITORY_OPEN_FROM_ENV) != 0); int version = GIT_REPO_VERSION_DEFAULT; if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0) @@ -2150,7 +2208,8 @@ static int repo_init_config( SET_REPO_CONFIG(int32, "core.repositoryformatversion", version); if ((error = repo_init_fs_configs( - config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0) + config, cfg_path.ptr, repo_dir, work_dir, + !is_reinit, use_env)) < 0) goto cleanup; if (!is_bare) { @@ -2214,8 +2273,8 @@ int git_repository_reinit_filesystem(git_repository *repo, int recurse) const char *repo_dir = git_repository_path(repo); if (!(error = repo_local_config(&config, &path, repo, repo_dir))) - error = repo_init_fs_configs( - config, path.ptr, repo_dir, git_repository_workdir(repo), true); + error = repo_init_fs_configs(config, path.ptr, repo_dir, + git_repository_workdir(repo), true, repo->use_env); git_config_free(config); git_str_dispose(&path); diff --git a/tests/libgit2/repo/env.c b/tests/libgit2/repo/env.c index 4a61581bd6b..0e6cc59d5e2 100644 --- a/tests/libgit2/repo/env.c +++ b/tests/libgit2/repo/env.c @@ -32,6 +32,8 @@ void test_repo_env__cleanup(void) git_futils_rmdir_r("peeled.git", NULL, GIT_RMDIR_REMOVE_FILES); cl_fixture_cleanup("test_workdir"); + cl_fixture_cleanup("test_global_conf"); + cl_fixture_cleanup("test_system_conf"); clear_git_env(); } @@ -315,3 +317,53 @@ void test_repo_env__commondir(void) git_repository_free(repo); cl_setenv("GIT_COMMON_DIR", NULL); } + +void test_repo_env__config(void) +{ + git_repository *repo; + git_config *config; + const char *system_path, *global_path; + int s, g; + + cl_fixture_sandbox("attr"); + cl_git_pass(p_rename("attr/.gitted", "attr/.git")); + + cl_git_rewritefile("test_system_conf", "[tttest]\n\tsys = true\n"); + cl_git_rewritefile("test_global_conf", "[tttest]\n\tglb = true\n"); + + system_path = cl_git_sandbox_path(0, "test_system_conf", NULL); + cl_setenv("GIT_CONFIG_SYSTEM", system_path); + + global_path = cl_git_sandbox_path(0, "test_global_conf", NULL); + cl_setenv("GIT_CONFIG_GLOBAL", global_path); + + /* Ensure we can override the system and global files */ + + cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); + cl_git_pass(git_repository_config(&config, repo)); + + cl_git_pass(git_config_get_bool(&s, config, "tttest.sys")); + cl_assert_equal_i(1, s); + cl_git_pass(git_config_get_bool(&g, config, "tttest.glb")); + cl_assert_equal_i(1, g); + + git_config_free(config); + git_repository_free(repo); + + /* Further ensure we can ignore the system file. */ + cl_setenv("GIT_CONFIG_NOSYSTEM", "TrUe"); + + cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); + cl_git_pass(git_repository_config(&config, repo)); + + cl_git_fail_with(GIT_ENOTFOUND, git_config_get_bool(&s, config, "tttest.sys")); + cl_git_pass(git_config_get_bool(&g, config, "tttest.glb")); + cl_assert_equal_i(1, g); + + git_config_free(config); + git_repository_free(repo); + + cl_setenv("GIT_CONFIG_NOSYSTEM", NULL); + cl_setenv("GIT_CONFIG_SYSTEM", NULL); + cl_setenv("GIT_CONFIG_GLOBAL", NULL); +} From c616ba2d1ebab52af0315235932659d81d238876 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 10:33:11 +0100 Subject: [PATCH 121/816] filebuf: configurable hash type `git_filebuf` hashes contents as its written; allow for SHA1 or SHA256 as that hash. Currently, most callers simply use SHA1 as they do not yet know about SHA256 themselves. --- src/libgit2/config_file.c | 16 ++++++++++++---- src/libgit2/index.c | 12 ++++++++---- src/libgit2/indexer.c | 5 +++-- src/util/filebuf.c | 7 ++++++- src/util/filebuf.h | 25 +++++++++++++++++++------ 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 932ca76014e..f3b87578d9c 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -1116,7 +1116,12 @@ static int write_on_eof( /* * This is pretty much the parsing, except we write out anything we don't have */ -static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value) +static int config_file_write( + config_file_backend *cfg, + const char *orig_key, + const char *key, + const git_regexp *preg, + const char *value) { char *orig_section = NULL, *section = NULL, *orig_name, *name, *ldot; @@ -1124,15 +1129,18 @@ static int config_file_write(config_file_backend *cfg, const char *orig_key, con git_config_parser parser = GIT_CONFIG_PARSER_INIT; git_filebuf file = GIT_FILEBUF_INIT; struct write_data write_data; - int error; + int filebuf_hash, error; + + filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(GIT_OID_SHA1)); + GIT_ASSERT(filebuf_hash); memset(&write_data, 0, sizeof(write_data)); if (cfg->locked) { error = git_str_puts(&contents, git_str_cstr(&cfg->locked_content) == NULL ? "" : git_str_cstr(&cfg->locked_content)); } else { - if ((error = git_filebuf_open(&file, cfg->file.path, GIT_FILEBUF_HASH_CONTENTS, - GIT_CONFIG_FILE_MODE)) < 0) + if ((error = git_filebuf_open(&file, cfg->file.path, + filebuf_hash, GIT_CONFIG_FILE_MODE)) < 0) goto done; /* We need to read in our own config file */ diff --git a/src/libgit2/index.c b/src/libgit2/index.c index d4532c005d0..6777f035812 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -3668,19 +3668,23 @@ int git_indexwriter_init( git_indexwriter *writer, git_index *index) { - int error; + int filebuf_hash, error; GIT_REFCOUNT_INC(index); writer->index = index; + filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(GIT_OID_SHA1)); + GIT_ASSERT(filebuf_hash); + if (!index->index_file_path) return create_index_error(-1, "failed to write index: The index is in-memory only"); - if ((error = git_filebuf_open( - &writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) { - + if ((error = git_filebuf_open(&writer->file, + index->index_file_path, + git_filebuf_hash_flags(filebuf_hash), + GIT_INDEX_FILE_MODE)) < 0) { if (error == GIT_ELOCKED) git_error_set(GIT_ERROR_INDEX, "the index is locked; this might be due to a concurrent or crashed process"); diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index fa55fb5eafe..7357a4aa56f 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -1232,6 +1232,7 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) git_filebuf index_file = {0}; void *packfile_trailer; size_t checksum_size; + int filebuf_hash; bool mismatch; if (!idx->parsed_header) { @@ -1240,6 +1241,7 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) } checksum_size = git_hash_size(indexer_hash_algorithm(idx)); + filebuf_hash = git_filebuf_hash_flags(indexer_hash_algorithm(idx)); GIT_ASSERT(checksum_size); /* Test for this before resolve_deltas(), as it plays with idx->off */ @@ -1314,8 +1316,7 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) return -1; if (git_filebuf_open(&index_file, filename.ptr, - GIT_FILEBUF_HASH_CONTENTS | - (idx->do_fsync ? GIT_FILEBUF_FSYNC : 0), + filebuf_hash | (idx->do_fsync ? GIT_FILEBUF_FSYNC : 0), idx->mode) < 0) goto on_error; diff --git a/src/util/filebuf.c b/src/util/filebuf.c index e014d43b25f..7afb76b88ec 100644 --- a/src/util/filebuf.c +++ b/src/util/filebuf.c @@ -302,11 +302,16 @@ int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mo } /* If we are hashing on-write, allocate a new hash context */ - if (flags & GIT_FILEBUF_HASH_CONTENTS) { + if (flags & GIT_FILEBUF_HASH_SHA1) { file->compute_digest = 1; if (git_hash_ctx_init(&file->digest, GIT_HASH_ALGORITHM_SHA1) < 0) goto cleanup; + } else if (flags & GIT_FILEBUF_HASH_SHA256) { + file->compute_digest = 1; + + if (git_hash_ctx_init(&file->digest, GIT_HASH_ALGORITHM_SHA256) < 0) + goto cleanup; } compression = flags >> GIT_FILEBUF_DEFLATE_SHIFT; diff --git a/src/util/filebuf.h b/src/util/filebuf.h index 4a61ae4e3bf..e23b9ed2adc 100644 --- a/src/util/filebuf.h +++ b/src/util/filebuf.h @@ -17,13 +17,14 @@ # define GIT_FILEBUF_THREADS #endif -#define GIT_FILEBUF_HASH_CONTENTS (1 << 0) -#define GIT_FILEBUF_APPEND (1 << 2) +#define GIT_FILEBUF_HASH_SHA1 (1 << 0) +#define GIT_FILEBUF_HASH_SHA256 (1 << 1) +#define GIT_FILEBUF_APPEND (1 << 2) #define GIT_FILEBUF_CREATE_LEADING_DIRS (1 << 3) -#define GIT_FILEBUF_TEMPORARY (1 << 4) -#define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5) -#define GIT_FILEBUF_FSYNC (1 << 6) -#define GIT_FILEBUF_DEFLATE_SHIFT (7) +#define GIT_FILEBUF_TEMPORARY (1 << 4) +#define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5) +#define GIT_FILEBUF_FSYNC (1 << 6) +#define GIT_FILEBUF_DEFLATE_SHIFT (7) #define GIT_FILELOCK_EXTENSION ".lock\0" #define GIT_FILELOCK_EXTLENGTH 6 @@ -91,4 +92,16 @@ int git_filebuf_hash(unsigned char *out, git_filebuf *file); int git_filebuf_flush(git_filebuf *file); int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file); +GIT_INLINE(int) git_filebuf_hash_flags(git_hash_algorithm_t algorithm) +{ + switch (algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + return GIT_FILEBUF_HASH_SHA1; + case GIT_HASH_ALGORITHM_SHA256: + return GIT_FILEBUF_HASH_SHA256; + default: + return 0; + } +} + #endif From 523f893f6fac92e301b090b141b449183947e3b3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 10:39:01 +0100 Subject: [PATCH 122/816] index: add sha256 support --- examples/show-index.c | 4 + include/git2/index.h | 9 + src/libgit2/apply.c | 7 +- src/libgit2/index.c | 433 ++++-- src/libgit2/index.h | 15 +- src/libgit2/merge.c | 15 +- src/libgit2/repository.c | 3 +- src/libgit2/stash.c | 17 +- src/libgit2/tree-cache.c | 42 +- src/libgit2/tree-cache.h | 8 +- src/libgit2/tree.c | 2 +- tests/libgit2/checkout/index.c | 3 +- tests/libgit2/clone/nonetwork.c | 3 +- tests/libgit2/diff/index.c | 3 +- tests/libgit2/index/cache.c | 10 +- tests/libgit2/index/inmemory.c | 5 +- tests/libgit2/index/racy.c | 4 +- tests/libgit2/index/read_index.c | 12 +- tests/libgit2/index/tests.c | 30 +- tests/libgit2/index/tests256.c | 1169 +++++++++++++++++ tests/libgit2/object/tree/update.c | 13 +- tests/libgit2/repo/setters.c | 3 +- tests/libgit2/reset/hard.c | 3 +- tests/libgit2/status/worktree_init.c | 13 +- tests/libgit2/submodule/lookup.c | 3 +- tests/resources/git-sha256.index | Bin 0 -> 458900 bytes tests/resources/testrepo_256/.gitted/HEAD | 1 + tests/resources/testrepo_256/.gitted/config | 15 + .../testrepo_256/.gitted/description | 1 + tests/resources/testrepo_256/.gitted/index | Bin 0 -> 361 bytes .../testrepo_256/.gitted/info/exclude | 6 + .../resources/testrepo_256/.gitted/logs/HEAD | 1 + .../.gitted/logs/refs/heads/master | 1 + .../.gitted/logs/refs/remotes/origin/HEAD | 1 + ...925bdc34ccdab778bd1d824f5562aaa319c6c8f045 | Bin 0 -> 267 bytes ...6d13866742a9070b56fd0ba9ab8dff828fc36c1f78 | 1 + ...16acdd727ea9364f7d48c55afed2f7dd889804065b | Bin 0 -> 103 bytes ...fcd19f12cc38faf337d10ec03ef4363d1a86f63750 | Bin 0 -> 21 bytes ...ba8801fe9bda46b66593291f5b9f7cd5f8888af12f | 1 + ...7e8ddfc9c8c47820fab5615cc04d904989ce800498 | Bin 0 -> 64 bytes ...4acca4ce4e1ea8508dfd77c24cefd461b65cead09e | Bin 0 -> 92 bytes ...da9be93f4afc2279623bb5b36c9194a660b7623c24 | Bin 0 -> 236 bytes ...50334e36a8015a546f0740bea4505e10d81a946f61 | Bin 0 -> 162 bytes ...08d88e14af624bb07fced6390997a0fa6abdad950a | Bin 0 -> 143 bytes ...e50a12b15f26aace3718749624f008bde68670352a | Bin 0 -> 202 bytes ...8644c307e17d0afe29b55f6488398cb59f13feb2f2 | Bin 0 -> 238 bytes ...0efa0433ac0cbd2d44679f68f2df3a9ae7014cf2a8 | Bin 0 -> 19 bytes ...830c2134815a31d9629e6aa9773338fedaab90976b | 1 + ...f2f30d79af178374166daeceefbf11e2f058d30d60 | Bin 0 -> 21 bytes ...eeca6bfffd9a0fe641784db85de2eb0f57b7553869 | Bin 0 -> 106 bytes ...89aa396d10f71c69e168d5c48ea23de59734ec3ab1 | Bin 0 -> 38 bytes ...917e3db8fde0045ee66305fd5e634b0c793c536a1b | 1 + ...e3b1e9a7dcda1185436fe141f7749120a303721813 | Bin 0 -> 15 bytes ...31b132e66ef18f564d41efb055804ec1dd28efb3f5 | Bin 0 -> 28 bytes ...2170996ce459d39e3a441e9759b635b0bc4ecc43fd | Bin 0 -> 57 bytes ...8c22b7898baaa0eda205a21cafdcb7e0f94b07bb9b | Bin 0 -> 64 bytes ...44523eb1ddeeef4bce03e35864640b452f84d26848 | 1 + ...635ab9fbee66d65fe5dda47dd0ac5f01dd69a84c6f | 3 + ...39b79f964c293db8620d679ea3596673c8a326446e | Bin 0 -> 157 bytes ...492f1bf1fcdf5dca09dab24cf331e05111b4cfc1a3 | Bin 0 -> 24 bytes ...b8f436e3ca0a82b25eddefd237bf5a26a0441c2aa7 | Bin 0 -> 107 bytes ...e660a4d510603c3f36e782a1a32ebd0388db6411ed | Bin 0 -> 181 bytes ...8aeb2c7811556538e7673e4b325307c71685fbf5b6 | Bin 0 -> 108 bytes ...417f9d5ccaf22b877c5a4522b6d1d2b16090ee2f6f | Bin 0 -> 141 bytes ...bccadee60065d8664a9af7648a1455100c4f772e1c | 2 + ...da9b3179f2419717275e3bfd2055b303489dbbfa47 | 1 + ...908dc44452ed38911cffa54ccc06076f30a1ffb1bf | Bin 0 -> 108 bytes ...c5d3f23bac1dded688b2bd314cc32b7f157e100724 | 1 + ...0b96786ebaa9ee6535fb698ec01b5f7a800fa27cbe | Bin 0 -> 137 bytes ...c294c441d08b89b455903c0c14e9b16587fec081f5 | Bin 0 -> 188 bytes ...cddea4259aea6b2961eb0822bd2c0c3f6029030045 | Bin 0 -> 18 bytes ...db7fc3a850e94f8c5ac1d71b9afa365a89005aff54 | Bin 0 -> 221 bytes ...8cc3cf4602c270a369beebc7d0b67238897bbc426b | 1 + ...24297e83e4a285f58bf5eabb1db270351388603c95 | Bin 0 -> 244 bytes ...ea61f40c14bdfc5b101b60fde4f44b58dd06667640 | Bin 0 -> 63 bytes ...3fdeed5502fd56b182af01b7740d297a24459333c5 | Bin 0 -> 26 bytes ...a3497ade7f62d2cd818bf388775cfa721de4068ebd | Bin 0 -> 54 bytes ...4ebf05e11d9c591b04cfdaff7cc860310356d71827 | 1 + ...82c5c09c22053675e2db24ea6b4b28cc75e9c10890 | Bin 0 -> 37 bytes ...a7ab8c68929bdc91b69ad54ef94979b93eba3f6022 | Bin 0 -> 190 bytes ...157ee4aad97814279fe500340eb3465797cbd3be23 | Bin 0 -> 23 bytes ...444b12c412210e9689c17e51bfc318ce4bb4360f19 | Bin 0 -> 57 bytes ...aaa96359f304c3dc97e95f336269ed474ea846ada5 | Bin 0 -> 198 bytes ...411d955520e0375fcbbcc14b7636a70f7536c32ef6 | 2 + ...787c5e94ba024ac9a4f763cb1d9bfd8e63aa7f7269 | Bin 0 -> 182 bytes ...621f5a228cb33dc84192980ca426cf9ab2a48cb9f0 | Bin 0 -> 187 bytes ...abfa899655d1b00e6529101a40d42f6acb059dff9f | Bin 0 -> 21 bytes ...3d137b654c602721c469c1b0a58e7e95647a9cf1c0 | 3 + ...8e201abb820a414de03eb63c065b06a2ab37d3f5ca | 1 + ...d3d4a80ced03101555e1fd8913b3544026c0717d4f | Bin 0 -> 181 bytes ...a5d92b78e54493fdaa78f72268d4cc69b61d5feee1 | Bin 0 -> 21 bytes ...55e9cb3cb46e348fca3b9dba3db64f7c9f64b8a736 | Bin 0 -> 157 bytes ...441f0b3f387faeddde1b37d0ad2f3f6a63f5327978 | Bin 0 -> 192 bytes ...24c75107423d5773066922ea5e55eaeb6490979562 | Bin 0 -> 157 bytes ...6e7643653c03e7f91faa27b767e3eb8225f0f6.idx | Bin 0 -> 1336 bytes ...e7643653c03e7f91faa27b767e3eb8225f0f6.pack | Bin 0 -> 569 bytes ...791b9b270067124b2609019b74f33f256f33fa.idx | Bin 0 -> 66216 bytes ...91b9b270067124b2609019b74f33f256f33fa.pack | Bin 0 -> 562646 bytes ...80b24ee981cf102db76764c383f9b87935d0d3.idx | Bin 0 -> 1336 bytes ...0b24ee981cf102db76764c383f9b87935d0d3.pack | Bin 0 -> 612 bytes .../testrepo_256/.gitted/packed-refs | 27 + .../testrepo_256/.gitted/refs/heads/master | 1 + .../.gitted/refs/remotes/origin/HEAD | 1 + tests/resources/testrepo_256/README | 1 + tests/resources/testrepo_256/branch_file.txt | 2 + tests/resources/testrepo_256/new.txt | 1 + 106 files changed, 1704 insertions(+), 204 deletions(-) create mode 100644 tests/libgit2/index/tests256.c create mode 100644 tests/resources/git-sha256.index create mode 100644 tests/resources/testrepo_256/.gitted/HEAD create mode 100644 tests/resources/testrepo_256/.gitted/config create mode 100644 tests/resources/testrepo_256/.gitted/description create mode 100644 tests/resources/testrepo_256/.gitted/index create mode 100644 tests/resources/testrepo_256/.gitted/info/exclude create mode 100644 tests/resources/testrepo_256/.gitted/logs/HEAD create mode 100644 tests/resources/testrepo_256/.gitted/logs/refs/heads/master create mode 100644 tests/resources/testrepo_256/.gitted/logs/refs/remotes/origin/HEAD create mode 100644 tests/resources/testrepo_256/.gitted/objects/00/404e6179d86039bbc01a925bdc34ccdab778bd1d824f5562aaa319c6c8f045 create mode 100644 tests/resources/testrepo_256/.gitted/objects/01/18010feb81fe41b9df646d13866742a9070b56fd0ba9ab8dff828fc36c1f78 create mode 100644 tests/resources/testrepo_256/.gitted/objects/02/df938cfb169b0b6ba0dd16acdd727ea9364f7d48c55afed2f7dd889804065b create mode 100644 tests/resources/testrepo_256/.gitted/objects/05/f7b70a01b0ade8afa5a5fcd19f12cc38faf337d10ec03ef4363d1a86f63750 create mode 100644 tests/resources/testrepo_256/.gitted/objects/14/bd335f9d7188c778d44eba8801fe9bda46b66593291f5b9f7cd5f8888af12f create mode 100644 tests/resources/testrepo_256/.gitted/objects/17/9496410f66032c03bd2b7e8ddfc9c8c47820fab5615cc04d904989ce800498 create mode 100644 tests/resources/testrepo_256/.gitted/objects/19/0a1349522cc11f8682e34acca4ce4e1ea8508dfd77c24cefd461b65cead09e create mode 100644 tests/resources/testrepo_256/.gitted/objects/1b/4b74772bd83ff28bf44cda9be93f4afc2279623bb5b36c9194a660b7623c24 create mode 100644 tests/resources/testrepo_256/.gitted/objects/21/e1e1ebe45b2c1ef79ab050334e36a8015a546f0740bea4505e10d81a946f61 create mode 100644 tests/resources/testrepo_256/.gitted/objects/23/8a501cf11a036f2f248008d88e14af624bb07fced6390997a0fa6abdad950a create mode 100644 tests/resources/testrepo_256/.gitted/objects/26/149bf1ac4612f24b532ae50a12b15f26aace3718749624f008bde68670352a create mode 100644 tests/resources/testrepo_256/.gitted/objects/2d/b6069c27ca4c08b784048644c307e17d0afe29b55f6488398cb59f13feb2f2 create mode 100644 tests/resources/testrepo_256/.gitted/objects/33/e415b835a670bb5c3c760efa0433ac0cbd2d44679f68f2df3a9ae7014cf2a8 create mode 100644 tests/resources/testrepo_256/.gitted/objects/34/f79ad1c813b93d2ee11c830c2134815a31d9629e6aa9773338fedaab90976b create mode 100644 tests/resources/testrepo_256/.gitted/objects/36/eac24505d4c4405864ccf2f30d79af178374166daeceefbf11e2f058d30d60 create mode 100644 tests/resources/testrepo_256/.gitted/objects/39/bf1ac28cc3f8432ba7cfeeca6bfffd9a0fe641784db85de2eb0f57b7553869 create mode 100644 tests/resources/testrepo_256/.gitted/objects/3b/58565ee067f13349cd4f89aa396d10f71c69e168d5c48ea23de59734ec3ab1 create mode 100644 tests/resources/testrepo_256/.gitted/objects/43/e084a4599ca42c476919917e3db8fde0045ee66305fd5e634b0c793c536a1b create mode 100644 tests/resources/testrepo_256/.gitted/objects/47/3a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 create mode 100644 tests/resources/testrepo_256/.gitted/objects/4b/c142808884e472ee6cc331b132e66ef18f564d41efb055804ec1dd28efb3f5 create mode 100644 tests/resources/testrepo_256/.gitted/objects/4d/f8ed86acaac5dc82b5652170996ce459d39e3a441e9759b635b0bc4ecc43fd create mode 100644 tests/resources/testrepo_256/.gitted/objects/5a/2d5699fea33657b42ba98c22b7898baaa0eda205a21cafdcb7e0f94b07bb9b create mode 100644 tests/resources/testrepo_256/.gitted/objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848 create mode 100644 tests/resources/testrepo_256/.gitted/objects/5d/bb1fff5c0094b31b25b4635ab9fbee66d65fe5dda47dd0ac5f01dd69a84c6f create mode 100644 tests/resources/testrepo_256/.gitted/objects/61/489e9e831f1d9001084d39b79f964c293db8620d679ea3596673c8a326446e create mode 100644 tests/resources/testrepo_256/.gitted/objects/6d/5fd291bb0f67444e99ab492f1bf1fcdf5dca09dab24cf331e05111b4cfc1a3 create mode 100644 tests/resources/testrepo_256/.gitted/objects/70/30f925768d9beb65654ab8f436e3ca0a82b25eddefd237bf5a26a0441c2aa7 create mode 100644 tests/resources/testrepo_256/.gitted/objects/73/8ff86401dbc5af692c83e660a4d510603c3f36e782a1a32ebd0388db6411ed create mode 100644 tests/resources/testrepo_256/.gitted/objects/73/b4f3c4f3182e6c8dd2c98aeb2c7811556538e7673e4b325307c71685fbf5b6 create mode 100644 tests/resources/testrepo_256/.gitted/objects/7e/4633ae1b0e83503dbea4417f9d5ccaf22b877c5a4522b6d1d2b16090ee2f6f create mode 100644 tests/resources/testrepo_256/.gitted/objects/7e/9424c06052ca33bfc599bccadee60065d8664a9af7648a1455100c4f772e1c create mode 100644 tests/resources/testrepo_256/.gitted/objects/80/91b686de8bf697ef632dda9b3179f2419717275e3bfd2055b303489dbbfa47 create mode 100644 tests/resources/testrepo_256/.gitted/objects/81/55958bbda08eed88c8ac908dc44452ed38911cffa54ccc06076f30a1ffb1bf create mode 100644 tests/resources/testrepo_256/.gitted/objects/90/1505c3355518bee35475c5d3f23bac1dded688b2bd314cc32b7f157e100724 create mode 100644 tests/resources/testrepo_256/.gitted/objects/93/1093620e5f050e2127fb0b96786ebaa9ee6535fb698ec01b5f7a800fa27cbe create mode 100644 tests/resources/testrepo_256/.gitted/objects/94/ed253efa9e86fc636805c294c441d08b89b455903c0c14e9b16587fec081f5 create mode 100644 tests/resources/testrepo_256/.gitted/objects/96/c18f0297e38d01f4b2dacddea4259aea6b2961eb0822bd2c0c3f6029030045 create mode 100644 tests/resources/testrepo_256/.gitted/objects/9c/cfa556cd7f73b426a7bedb7fc3a850e94f8c5ac1d71b9afa365a89005aff54 create mode 100644 tests/resources/testrepo_256/.gitted/objects/9d/aab17c25f647d652c72c8cc3cf4602c270a369beebc7d0b67238897bbc426b create mode 100644 tests/resources/testrepo_256/.gitted/objects/a4/813ef6708e6011e8187224297e83e4a285f58bf5eabb1db270351388603c95 create mode 100644 tests/resources/testrepo_256/.gitted/objects/ab/ee32b3339d1566d75613ea61f40c14bdfc5b101b60fde4f44b58dd06667640 create mode 100644 tests/resources/testrepo_256/.gitted/objects/ae/a29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5 create mode 100644 tests/resources/testrepo_256/.gitted/objects/b1/95873b48c824d995c974a3497ade7f62d2cd818bf388775cfa721de4068ebd create mode 100644 tests/resources/testrepo_256/.gitted/objects/b2/1c8c27a05a3f0bf9f0f44ebf05e11d9c591b04cfdaff7cc860310356d71827 create mode 100644 tests/resources/testrepo_256/.gitted/objects/b6/1b940a8cd979a32e005682c5c09c22053675e2db24ea6b4b28cc75e9c10890 create mode 100644 tests/resources/testrepo_256/.gitted/objects/b8/3624f6ac0995273c0034a7ab8c68929bdc91b69ad54ef94979b93eba3f6022 create mode 100644 tests/resources/testrepo_256/.gitted/objects/bd/f2066a28e11603a1af04157ee4aad97814279fe500340eb3465797cbd3be23 create mode 100644 tests/resources/testrepo_256/.gitted/objects/bf/a3b3b9a161d354e2254a444b12c412210e9689c17e51bfc318ce4bb4360f19 create mode 100644 tests/resources/testrepo_256/.gitted/objects/bf/cc4074ac517ed24d61b0aaa96359f304c3dc97e95f336269ed474ea846ada5 create mode 100644 tests/resources/testrepo_256/.gitted/objects/c2/58f010a08328a29cde33411d955520e0375fcbbcc14b7636a70f7536c32ef6 create mode 100644 tests/resources/testrepo_256/.gitted/objects/ca/31f7336e882a233a2943787c5e94ba024ac9a4f763cb1d9bfd8e63aa7f7269 create mode 100644 tests/resources/testrepo_256/.gitted/objects/cb/282e7c15fd8aeb2265cd621f5a228cb33dc84192980ca426cf9ab2a48cb9f0 create mode 100644 tests/resources/testrepo_256/.gitted/objects/cc/b5a03da85607c230d111abfa899655d1b00e6529101a40d42f6acb059dff9f create mode 100644 tests/resources/testrepo_256/.gitted/objects/cf/84e5be57f8d5d51f136d3d137b654c602721c469c1b0a58e7e95647a9cf1c0 create mode 100644 tests/resources/testrepo_256/.gitted/objects/d8/8b60d2641df3656381dc8e201abb820a414de03eb63c065b06a2ab37d3f5ca create mode 100644 tests/resources/testrepo_256/.gitted/objects/de/caff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f create mode 100644 tests/resources/testrepo_256/.gitted/objects/eb/ead5965196dfaeab52b1a5d92b78e54493fdaa78f72268d4cc69b61d5feee1 create mode 100644 tests/resources/testrepo_256/.gitted/objects/f2/a108f86a3b4fd9ad75ed55e9cb3cb46e348fca3b9dba3db64f7c9f64b8a736 create mode 100644 tests/resources/testrepo_256/.gitted/objects/f2/c8da1a7c2eb49ff25c47441f0b3f387faeddde1b37d0ad2f3f6a63f5327978 create mode 100644 tests/resources/testrepo_256/.gitted/objects/f3/1459efb9367c5a19c9dd24c75107423d5773066922ea5e55eaeb6490979562 create mode 100644 tests/resources/testrepo_256/.gitted/objects/pack/pack-b87f1f214098b19ce092afb9ef6e7643653c03e7f91faa27b767e3eb8225f0f6.idx create mode 100644 tests/resources/testrepo_256/.gitted/objects/pack/pack-b87f1f214098b19ce092afb9ef6e7643653c03e7f91faa27b767e3eb8225f0f6.pack create mode 100644 tests/resources/testrepo_256/.gitted/objects/pack/pack-e2f07f30db7e480ea84a0e64ee791b9b270067124b2609019b74f33f256f33fa.idx create mode 100644 tests/resources/testrepo_256/.gitted/objects/pack/pack-e2f07f30db7e480ea84a0e64ee791b9b270067124b2609019b74f33f256f33fa.pack create mode 100644 tests/resources/testrepo_256/.gitted/objects/pack/pack-f72bbfa35af982c2a60735152c80b24ee981cf102db76764c383f9b87935d0d3.idx create mode 100644 tests/resources/testrepo_256/.gitted/objects/pack/pack-f72bbfa35af982c2a60735152c80b24ee981cf102db76764c383f9b87935d0d3.pack create mode 100644 tests/resources/testrepo_256/.gitted/packed-refs create mode 100644 tests/resources/testrepo_256/.gitted/refs/heads/master create mode 100644 tests/resources/testrepo_256/.gitted/refs/remotes/origin/HEAD create mode 100644 tests/resources/testrepo_256/README create mode 100644 tests/resources/testrepo_256/branch_file.txt create mode 100644 tests/resources/testrepo_256/new.txt diff --git a/examples/show-index.c b/examples/show-index.c index fb797e04beb..0a5e7d1a2e4 100644 --- a/examples/show-index.c +++ b/examples/show-index.c @@ -30,7 +30,11 @@ int lg2_show_index(git_repository *repo, int argc, char **argv) dirlen = strlen(dir); if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) { +#ifdef GIT_EXPERIMENTAL_SHA256 + check_lg2(git_index_open(&index, dir, GIT_OID_SHA1), "could not open index", dir); +#else check_lg2(git_index_open(&index, dir), "could not open index", dir); +#endif } else { check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir); check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL); diff --git a/include/git2/index.h b/include/git2/index.h index 981535dadad..6e806371bf4 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -184,7 +184,12 @@ typedef enum { * @param index_path the path to the index file in disk * @return 0 or an error code */ + +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path, git_oid_t oid_type); +#else GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path); +#endif /** * Create an in-memory index object. @@ -197,7 +202,11 @@ GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path); * @param out the pointer for the new index * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_index_new(git_index **out, git_oid_t oid_type); +#else GIT_EXTERN(int) git_index_new(git_index **out); +#endif /** * Free an existing index object. diff --git a/src/libgit2/apply.c b/src/libgit2/apply.c index 18304da4df7..6b55b812fa4 100644 --- a/src/libgit2/apply.c +++ b/src/libgit2/apply.c @@ -19,6 +19,7 @@ #include "zstream.h" #include "reader.h" #include "index.h" +#include "repository.h" #include "apply.h" typedef struct { @@ -644,7 +645,7 @@ int git_apply_to_tree( * put the current tree into the postimage as-is - the diff will * replace any entries contained therein */ - if ((error = git_index_new(&postimage)) < 0 || + if ((error = git_index__new(&postimage, repo->oid_type)) < 0 || (error = git_index_read_tree(postimage, preimage)) < 0 || (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) goto done; @@ -851,8 +852,8 @@ int git_apply( * having the full repo index, so we will limit our checkout * to only write these files that were affected by the diff. */ - if ((error = git_index_new(&preimage)) < 0 || - (error = git_index_new(&postimage)) < 0 || + if ((error = git_index__new(&preimage, repo->oid_type)) < 0 || + (error = git_index__new(&postimage, repo->oid_type)) < 0 || (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) goto done; diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 6777f035812..9d919093be0 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -32,8 +32,6 @@ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarr unsigned int flags, git_index_matched_path_cb cb, void *payload); -#define minimal_entry_size (offsetof(struct entry_short, path)) - static const size_t INDEX_HEADER_SIZE = 12; static const unsigned int INDEX_VERSION_NUMBER_DEFAULT = 2; @@ -65,7 +63,7 @@ struct entry_time { uint32_t nanoseconds; }; -struct entry_short { +struct entry_common { struct entry_time ctime; struct entry_time mtime; uint32_t dev; @@ -74,25 +72,35 @@ struct entry_short { uint32_t uid; uint32_t gid; uint32_t file_size; - unsigned char oid[GIT_OID_SHA1_SIZE]; - uint16_t flags; - char path[1]; /* arbitrary length */ }; -struct entry_long { - struct entry_time ctime; - struct entry_time mtime; - uint32_t dev; - uint32_t ino; - uint32_t mode; - uint32_t uid; - uint32_t gid; - uint32_t file_size; - unsigned char oid[GIT_OID_SHA1_SIZE]; - uint16_t flags; - uint16_t flags_extended; - char path[1]; /* arbitrary length */ -}; +#define entry_short(oid_size) \ + struct { \ + struct entry_common common; \ + unsigned char oid[oid_size]; \ + uint16_t flags; \ + char path[1]; /* arbitrary length */ \ + } + +#define entry_long(oid_size) \ + struct { \ + struct entry_common common; \ + unsigned char oid[oid_size]; \ + uint16_t flags; \ + uint16_t flags_extended; \ + char path[1]; /* arbitrary length */ \ + } + +typedef entry_short(GIT_OID_SHA1_SIZE) index_entry_short_sha1; +typedef entry_long(GIT_OID_SHA1_SIZE) index_entry_long_sha1; + +#ifdef GIT_EXPERIMENTAL_SHA256 +typedef entry_short(GIT_OID_SHA256_SIZE) index_entry_short_sha256; +typedef entry_long(GIT_OID_SHA256_SIZE) index_entry_long_sha256; +#endif + +#undef entry_short +#undef entry_long struct entry_srch_key { const char *path; @@ -115,12 +123,12 @@ struct reuc_entry_internal { bool git_index__enforce_unsaved_safety = false; /* local declarations */ -static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size); +static int read_extension(size_t *read_len, git_index *index, size_t checksum_size, const char *buffer, size_t buffer_size); static int read_header(struct index_header *dest, const void *buffer); static int parse_index(git_index *index, const char *buffer, size_t buffer_size); static bool is_index_extended(git_index *index); -static int write_index(unsigned char checksum[GIT_HASH_SHA1_SIZE], size_t *checksum_size, git_index *index, git_filebuf *file); +static int write_index(unsigned char checksum[GIT_HASH_MAX_SIZE], size_t *checksum_size, git_index *index, git_filebuf *file); static void index_entry_free(git_index_entry *entry); static void index_entry_reuc_free(git_index_reuc_entry *reuc); @@ -401,7 +409,10 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case) git_vector_sort(&index->reuc); } -int git_index_open(git_index **index_out, const char *index_path) +int git_index__open( + git_index **index_out, + const char *index_path, + git_oid_t oid_type) { git_index *index; int error = -1; @@ -411,6 +422,8 @@ int git_index_open(git_index **index_out, const char *index_path) index = git__calloc(1, sizeof(git_index)); GIT_ERROR_CHECK_ALLOC(index); + index->oid_type = oid_type; + if (git_pool_init(&index->tree_pool, 1) < 0) goto fail; @@ -451,10 +464,34 @@ int git_index_open(git_index **index_out, const char *index_path) return error; } +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_index_open(git_index **index_out, const char *index_path, git_oid_t oid_type) +{ + return git_index__open(index_out, index_path, oid_type); +} +#else +int git_index_open(git_index **index_out, const char *index_path) +{ + return git_index__open(index_out, index_path, GIT_OID_SHA1); +} +#endif + +int git_index__new(git_index **out, git_oid_t oid_type) +{ + return git_index__open(out, NULL, oid_type); +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_index_new(git_index **out, git_oid_t oid_type) +{ + return git_index__new(out, oid_type); +} +#else int git_index_new(git_index **out) { - return git_index_open(out, NULL); + return git_index__new(out, GIT_OID_SHA1); } +#endif static void index_free(git_index *index) { @@ -620,8 +657,8 @@ static int compare_checksum(git_index *index) { int fd; ssize_t bytes_read; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size = GIT_HASH_SHA1_SIZE; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size = git_oid_size(index->oid_type); if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0) return fd; @@ -2306,6 +2343,7 @@ static int index_error_invalid(const char *message) static int read_reuc(git_index *index, const char *buffer, size_t size) { const char *endptr; + size_t oid_size = git_oid_size(index->oid_type); size_t len; int i; @@ -2354,16 +2392,16 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) for (i = 0; i < 3; i++) { if (!lost->mode[i]) continue; - if (size < GIT_OID_SHA1_SIZE) { + if (size < oid_size) { index_entry_reuc_free(lost); return index_error_invalid("reading reuc entry oid"); } - if (git_oid__fromraw(&lost->oid[i], (const unsigned char *) buffer, GIT_OID_SHA1) < 0) + if (git_oid__fromraw(&lost->oid[i], (const unsigned char *) buffer, index->oid_type) < 0) return -1; - size -= GIT_OID_SHA1_SIZE; - buffer += GIT_OID_SHA1_SIZE; + size -= oid_size; + buffer += oid_size; } /* entry was read successfully - insert into reuc vector */ @@ -2433,73 +2471,157 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size return 0; } -static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flags) +GIT_INLINE(size_t) index_entry_path_offset( + git_oid_t oid_type, + uint32_t flags) { + if (oid_type == GIT_OID_SHA1) + return (flags & GIT_INDEX_ENTRY_EXTENDED) ? + offsetof(index_entry_long_sha1, path) : + offsetof(index_entry_short_sha1, path); + +#ifdef GIT_EXPERIMENTAL_SHA256 + else if (oid_type == GIT_OID_SHA256) + return (flags & GIT_INDEX_ENTRY_EXTENDED) ? + offsetof(index_entry_long_sha256, path) : + offsetof(index_entry_short_sha256, path); +#endif + + git_error_set(GIT_ERROR_INTERNAL, "invalid oid type"); + return 0; +} + +GIT_INLINE(size_t) index_entry_flags_offset(git_oid_t oid_type) +{ + if (oid_type == GIT_OID_SHA1) + return offsetof(index_entry_long_sha1, flags_extended); + +#ifdef GIT_EXPERIMENTAL_SHA256 + else if (oid_type == GIT_OID_SHA256) + return offsetof(index_entry_long_sha256, flags_extended); +#endif + + git_error_set(GIT_ERROR_INTERNAL, "invalid oid type"); + return 0; +} + +static size_t index_entry_size( + size_t path_len, + size_t varint_len, + git_oid_t oid_type, + uint32_t flags) +{ + size_t offset, size; + + if (!(offset = index_entry_path_offset(oid_type, flags))) + return 0; + if (varint_len) { - if (flags & GIT_INDEX_ENTRY_EXTENDED) - return offsetof(struct entry_long, path) + path_len + 1 + varint_len; - else - return offsetof(struct entry_short, path) + path_len + 1 + varint_len; + if (GIT_ADD_SIZET_OVERFLOW(&size, offset, path_len) || + GIT_ADD_SIZET_OVERFLOW(&size, size, 1) || + GIT_ADD_SIZET_OVERFLOW(&size, size, varint_len)) + return 0; } else { -#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) - if (flags & GIT_INDEX_ENTRY_EXTENDED) - return entry_size(struct entry_long, path_len); - else - return entry_size(struct entry_short, path_len); -#undef entry_size + if (GIT_ADD_SIZET_OVERFLOW(&size, offset, path_len) || + GIT_ADD_SIZET_OVERFLOW(&size, size, 8)) + return 0; + + size &= ~7; } + + return size; } static int read_entry( git_index_entry **out, size_t *out_size, git_index *index, + size_t checksum_size, const void *buffer, size_t buffer_size, const char *last) { - size_t path_length, entry_size; + size_t path_length, path_offset, entry_size; const char *path_ptr; - struct entry_short source; + struct entry_common *source_common; + index_entry_short_sha1 source_sha1; +#ifdef GIT_EXPERIMENTAL_SHA256 + index_entry_short_sha256 source_sha256; +#endif git_index_entry entry = {{0}}; bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP; char *tmp_path = NULL; - size_t checksum_size = GIT_HASH_SHA1_SIZE; + + size_t minimal_entry_size = index_entry_path_offset(index->oid_type, 0); if (checksum_size + minimal_entry_size > buffer_size) return -1; /* buffer is not guaranteed to be aligned */ - memcpy(&source, buffer, sizeof(struct entry_short)); - - entry.ctime.seconds = (git_time_t)ntohl(source.ctime.seconds); - entry.ctime.nanoseconds = ntohl(source.ctime.nanoseconds); - entry.mtime.seconds = (git_time_t)ntohl(source.mtime.seconds); - entry.mtime.nanoseconds = ntohl(source.mtime.nanoseconds); - entry.dev = ntohl(source.dev); - entry.ino = ntohl(source.ino); - entry.mode = ntohl(source.mode); - entry.uid = ntohl(source.uid); - entry.gid = ntohl(source.gid); - entry.file_size = ntohl(source.file_size); - entry.flags = ntohs(source.flags); - - if (git_oid__fromraw(&entry.id, source.oid, GIT_OID_SHA1) < 0) + switch (index->oid_type) { + case GIT_OID_SHA1: + source_common = &source_sha1.common; + memcpy(&source_sha1, buffer, sizeof(source_sha1)); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + source_common = &source_sha256.common; + memcpy(&source_sha256, buffer, sizeof(source_sha256)); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + entry.ctime.seconds = (git_time_t)ntohl(source_common->ctime.seconds); + entry.ctime.nanoseconds = ntohl(source_common->ctime.nanoseconds); + entry.mtime.seconds = (git_time_t)ntohl(source_common->mtime.seconds); + entry.mtime.nanoseconds = ntohl(source_common->mtime.nanoseconds); + entry.dev = ntohl(source_common->dev); + entry.ino = ntohl(source_common->ino); + entry.mode = ntohl(source_common->mode); + entry.uid = ntohl(source_common->uid); + entry.gid = ntohl(source_common->gid); + entry.file_size = ntohl(source_common->file_size); + + switch (index->oid_type) { + case GIT_OID_SHA1: + if (git_oid__fromraw(&entry.id, source_sha1.oid, + GIT_OID_SHA1) < 0) + return -1; + entry.flags = ntohs(source_sha1.flags); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + if (git_oid__fromraw(&entry.id, source_sha256.oid, + GIT_OID_SHA256) < 0) + return -1; + entry.flags = ntohs(source_sha256.flags); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + if (!(path_offset = index_entry_path_offset(index->oid_type, entry.flags))) return -1; + if (entry.flags & GIT_INDEX_ENTRY_EXTENDED) { uint16_t flags_raw; size_t flags_offset; - flags_offset = offsetof(struct entry_long, flags_extended); - memcpy(&flags_raw, (const char *) buffer + flags_offset, - sizeof(flags_raw)); + if (!(flags_offset = index_entry_flags_offset(index->oid_type))) + return -1; + + memcpy(&flags_raw, (const char *)buffer + flags_offset, sizeof(flags_raw)); flags_raw = ntohs(flags_raw); memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw)); - path_ptr = (const char *) buffer + offsetof(struct entry_long, path); - } else - path_ptr = (const char *) buffer + offsetof(struct entry_short, path); + path_ptr = (const char *)buffer + path_offset; + } else { + path_ptr = (const char *)buffer + path_offset; + } if (!compressed) { path_length = entry.flags & GIT_INDEX_ENTRY_NAMEMASK; @@ -2511,12 +2633,12 @@ static int read_entry( path_end = memchr(path_ptr, '\0', buffer_size); if (path_end == NULL) - return -1; + return index_error_invalid("invalid path name"); path_length = path_end - path_ptr; } - entry_size = index_entry_size(path_length, 0, entry.flags); + entry_size = index_entry_size(path_length, 0, index->oid_type, entry.flags); entry.path = (char *)path_ptr; } else { size_t varint_len, last_len, prefix_len, suffix_len, path_len; @@ -2542,15 +2664,18 @@ static int read_entry( memcpy(tmp_path, last, prefix_len); memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1); - entry_size = index_entry_size(suffix_len, varint_len, entry.flags); + + entry_size = index_entry_size(suffix_len, varint_len, index->oid_type, entry.flags); entry.path = tmp_path; } if (entry_size == 0) return -1; - if (checksum_size + entry_size > buffer_size) + if (checksum_size + entry_size > buffer_size) { + git_error_set(GIT_ERROR_INTERNAL, "invalid index checksum"); return -1; + } if (index_entry_dup(out, index, &entry) < 0) { git__free(tmp_path); @@ -2579,11 +2704,10 @@ static int read_header(struct index_header *dest, const void *buffer) return 0; } -static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size) +static int read_extension(size_t *read_len, git_index *index, size_t checksum_size, const char *buffer, size_t buffer_size) { struct index_extension dest; size_t total_size; - size_t checksum_size = GIT_HASH_SHA1_SIZE; /* buffer is not guaranteed to be aligned */ memcpy(&dest, buffer, sizeof(struct index_extension)); @@ -2602,7 +2726,7 @@ static int read_extension(size_t *read_len, git_index *index, const char *buffer if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') { /* tree cache */ if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) { - if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, &index->tree_pool) < 0) + if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, index->oid_type, &index->tree_pool) < 0) return -1; } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { if (read_reuc(index, buffer + 8, dest.extension_size) < 0) @@ -2630,8 +2754,8 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) int error = 0; unsigned int i; struct index_header header = { 0 }; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size = GIT_HASH_SHA1_SIZE; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size = git_hash_size(git_oid_algorithm(index->oid_type)); const char *last = NULL; const char *empty = ""; @@ -2646,9 +2770,12 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) if (buffer_size < INDEX_HEADER_SIZE + checksum_size) return index_error_invalid("insufficient buffer space"); - /* Precalculate the SHA1 of the files's contents -- we'll match it to - * the provided SHA1 in the footer */ - git_hash_buf(checksum, buffer, buffer_size - checksum_size, GIT_HASH_ALGORITHM_SHA1); + /* + * Precalculate the hash of the files's contents -- we'll match + * it to the provided checksum in the footer. + */ + git_hash_buf(checksum, buffer, buffer_size - checksum_size, + git_oid_algorithm(index->oid_type)); /* Parse header */ if ((error = read_header(&header, buffer)) < 0) @@ -2670,7 +2797,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) git_index_entry *entry = NULL; size_t entry_size; - if ((error = read_entry(&entry, &entry_size, index, buffer, buffer_size, last)) < 0) { + if ((error = read_entry(&entry, &entry_size, index, checksum_size, buffer, buffer_size, last)) < 0) { error = index_error_invalid("invalid entry"); goto done; } @@ -2701,7 +2828,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) while (buffer_size > checksum_size) { size_t extension_size; - if ((error = read_extension(&extension_size, index, buffer, buffer_size)) < 0) { + if ((error = read_extension(&extension_size, index, checksum_size, buffer, buffer_size)) < 0) { goto done; } @@ -2714,7 +2841,10 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) goto done; } - /* 160-bit SHA-1 over the content of the index file before this checksum. */ + /* + * SHA-1 or SHA-256 (depending on the repository's object format) + * over the content of the index file before this checksum. + */ if (memcmp(checksum, buffer, checksum_size) != 0) { error = index_error_invalid( "calculated checksum does not match expected"); @@ -2754,16 +2884,40 @@ static bool is_index_extended(git_index *index) return (extended > 0); } -static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char *last) +static int write_disk_entry( + git_index *index, + git_filebuf *file, + git_index_entry *entry, + const char *last) { void *mem = NULL; - struct entry_short ondisk; - size_t path_len, disk_size; + struct entry_common *ondisk_common; + size_t path_len, path_offset, disk_size; int varint_len = 0; char *path; const char *path_start = entry->path; size_t same_len = 0; + index_entry_short_sha1 ondisk_sha1; + index_entry_long_sha1 ondisk_ext_sha1; +#ifdef GIT_EXPERIMENTAL_SHA256 + index_entry_short_sha256 ondisk_sha256; + index_entry_long_sha256 ondisk_ext_sha256; +#endif + + switch (index->oid_type) { + case GIT_OID_SHA1: + ondisk_common = &ondisk_sha1.common; + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + ondisk_common = &ondisk_sha256.common; + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + path_len = ((struct entry_internal *)entry)->pathlen; if (last) { @@ -2780,9 +2934,9 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha varint_len = git_encode_varint(NULL, 0, strlen(last) - same_len); } - disk_size = index_entry_size(path_len, varint_len, entry->flags); + disk_size = index_entry_size(path_len, varint_len, index->oid_type, entry->flags); - if (git_filebuf_reserve(file, &mem, disk_size) < 0) + if (!disk_size || git_filebuf_reserve(file, &mem, disk_size) < 0) return -1; memset(mem, 0x0, disk_size); @@ -2797,35 +2951,77 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha * * In 2038 I will be either too dead or too rich to care about this */ - ondisk.ctime.seconds = htonl((uint32_t)entry->ctime.seconds); - ondisk.mtime.seconds = htonl((uint32_t)entry->mtime.seconds); - ondisk.ctime.nanoseconds = htonl(entry->ctime.nanoseconds); - ondisk.mtime.nanoseconds = htonl(entry->mtime.nanoseconds); - ondisk.dev = htonl(entry->dev); - ondisk.ino = htonl(entry->ino); - ondisk.mode = htonl(entry->mode); - ondisk.uid = htonl(entry->uid); - ondisk.gid = htonl(entry->gid); - ondisk.file_size = htonl((uint32_t)entry->file_size); - git_oid_raw_cpy(ondisk.oid, entry->id.id, GIT_OID_SHA1_SIZE); - ondisk.flags = htons(entry->flags); + ondisk_common->ctime.seconds = htonl((uint32_t)entry->ctime.seconds); + ondisk_common->mtime.seconds = htonl((uint32_t)entry->mtime.seconds); + ondisk_common->ctime.nanoseconds = htonl(entry->ctime.nanoseconds); + ondisk_common->mtime.nanoseconds = htonl(entry->mtime.nanoseconds); + ondisk_common->dev = htonl(entry->dev); + ondisk_common->ino = htonl(entry->ino); + ondisk_common->mode = htonl(entry->mode); + ondisk_common->uid = htonl(entry->uid); + ondisk_common->gid = htonl(entry->gid); + ondisk_common->file_size = htonl((uint32_t)entry->file_size); + + switch (index->oid_type) { + case GIT_OID_SHA1: + git_oid_raw_cpy(ondisk_sha1.oid, entry->id.id, GIT_OID_SHA1_SIZE); + ondisk_sha1.flags = htons(entry->flags); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + git_oid_raw_cpy(ondisk_sha256.oid, entry->id.id, GIT_OID_SHA256_SIZE); + ondisk_sha256.flags = htons(entry->flags); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + path_offset = index_entry_path_offset(index->oid_type, entry->flags); if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) { - const size_t path_offset = offsetof(struct entry_long, path); - struct entry_long ondisk_ext; - memcpy(&ondisk_ext, &ondisk, sizeof(struct entry_short)); - ondisk_ext.flags_extended = htons(entry->flags_extended & + struct entry_common *ondisk_ext; + uint16_t flags_extended = htons(entry->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS); - memcpy(mem, &ondisk_ext, path_offset); - path = (char *)mem + path_offset; - disk_size -= path_offset; + + switch (index->oid_type) { + case GIT_OID_SHA1: + memcpy(&ondisk_ext_sha1, &ondisk_sha1, + sizeof(index_entry_short_sha1)); + ondisk_ext_sha1.flags_extended = flags_extended; + ondisk_ext = &ondisk_ext_sha1.common; + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + memcpy(&ondisk_ext_sha256, &ondisk_sha256, + sizeof(index_entry_short_sha256)); + ondisk_ext_sha256.flags_extended = flags_extended; + ondisk_ext = &ondisk_ext_sha256.common; + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + memcpy(mem, ondisk_ext, path_offset); } else { - const size_t path_offset = offsetof(struct entry_short, path); - memcpy(mem, &ondisk, path_offset); - path = (char *)mem + path_offset; - disk_size -= path_offset; + switch (index->oid_type) { + case GIT_OID_SHA1: + memcpy(mem, &ondisk_sha1, path_offset); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + memcpy(mem, &ondisk_sha256, path_offset); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } } + path = (char *)mem + path_offset; + disk_size -= path_offset; + if (last) { varint_len = git_encode_varint((unsigned char *) path, disk_size, strlen(last) - same_len); @@ -2877,7 +3073,7 @@ static int write_entries(git_index *index, git_filebuf *file) last = ""; git_vector_foreach(entries, i, entry) { - if ((error = write_disk_entry(file, entry, last)) < 0) + if ((error = write_disk_entry(index, file, entry, last)) < 0) break; if (index->version >= INDEX_VERSION_NUMBER_COMP) last = entry->path; @@ -2955,8 +3151,9 @@ static int write_name_extension(git_index *index, git_filebuf *file) return error; } -static int create_reuc_extension_data(git_str *reuc_buf, git_index_reuc_entry *reuc) +static int create_reuc_extension_data(git_str *reuc_buf, git_index *index, git_index_reuc_entry *reuc) { + size_t oid_size = git_oid_size(index->oid_type); int i; int error = 0; @@ -2970,7 +3167,7 @@ static int create_reuc_extension_data(git_str *reuc_buf, git_index_reuc_entry *r } for (i = 0; i < 3; i++) { - if (reuc->mode[i] && (error = git_str_put(reuc_buf, (char *)&reuc->oid[i].id, GIT_OID_SHA1_SIZE)) < 0) + if (reuc->mode[i] && (error = git_str_put(reuc_buf, (char *)&reuc->oid[i].id, oid_size)) < 0) return error; } @@ -2987,7 +3184,7 @@ static int write_reuc_extension(git_index *index, git_filebuf *file) int error = 0; git_vector_foreach(out, i, reuc) { - if ((error = create_reuc_extension_data(&reuc_buf, reuc)) < 0) + if ((error = create_reuc_extension_data(&reuc_buf, index, reuc)) < 0) goto done; } @@ -3036,7 +3233,7 @@ static void clear_uptodate(git_index *index) } static int write_index( - unsigned char checksum[GIT_HASH_SHA1_SIZE], + unsigned char checksum[GIT_HASH_MAX_SIZE], size_t *checksum_size, git_index *index, git_filebuf *file) @@ -3048,7 +3245,9 @@ static int write_index( GIT_ASSERT_ARG(index); GIT_ASSERT_ARG(file); - *checksum_size = GIT_HASH_SHA1_SIZE; + GIT_ASSERT(index->oid_type); + + *checksum_size = git_hash_size(git_oid_algorithm(index->oid_type)); if (index->version <= INDEX_VERSION_NUMBER_EXT) { is_extended = is_index_extended(index); @@ -3209,7 +3408,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree) if (error < 0) return error; - error = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool); + error = git_tree_cache_read_tree(&index->tree, tree, index->oid_type, &index->tree_pool); return error; } @@ -3674,7 +3873,7 @@ int git_indexwriter_init( writer->index = index; - filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(GIT_OID_SHA1)); + filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(index->oid_type)); GIT_ASSERT(filebuf_hash); if (!index->index_file_path) @@ -3716,7 +3915,7 @@ int git_indexwriter_init_for_operation( int git_indexwriter_commit(git_indexwriter *writer) { - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_MAX_SIZE]; size_t checksum_size; int error; diff --git a/src/libgit2/index.h b/src/libgit2/index.h index 71bb096f738..53c29977df7 100644 --- a/src/libgit2/index.h +++ b/src/libgit2/index.h @@ -27,7 +27,7 @@ struct git_index { char *index_file_path; git_futils_filestamp stamp; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_MAX_SIZE]; git_vector entries; git_idxmap *entries_map; @@ -35,6 +35,8 @@ struct git_index { git_vector deleted; /* deleted entries if readers > 0 */ git_atomic32 readers; /* number of active iterators */ + git_oid_t oid_type; + unsigned int on_disk:1; unsigned int ignore_case:1; unsigned int distrust_filemode:1; @@ -141,6 +143,17 @@ GIT_INLINE(unsigned char *) git_index__checksum(git_index *index) return index->checksum; } +/* SHA256-aware internal functions */ + +extern int git_index__new( + git_index **index_out, + git_oid_t oid_type); + +extern int git_index__open( + git_index **index_out, + const char *index_path, + git_oid_t oid_type); + /* Copy the current entries vector *and* increment the index refcount. * Call `git_index__release_snapshot` when done. */ diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index df2cefb2930..9a52b9f786b 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -1997,8 +1997,11 @@ static int index_update_reuc(git_index *index, git_merge_diff_list *diff_list) return 0; } -static int index_from_diff_list(git_index **out, - git_merge_diff_list *diff_list, bool skip_reuc) +static int index_from_diff_list( + git_index **out, + git_merge_diff_list *diff_list, + git_oid_t oid_type, + bool skip_reuc) { git_index *index; size_t i; @@ -2007,7 +2010,7 @@ static int index_from_diff_list(git_index **out, *out = NULL; - if ((error = git_index_new(&index)) < 0) + if ((error = git_index__new(&index, oid_type)) < 0) return error; if ((error = git_index__fill(index, &diff_list->staged)) < 0) @@ -2157,7 +2160,7 @@ int git_merge__iterators( } } - error = index_from_diff_list(out, diff_list, + error = index_from_diff_list(out, diff_list, repo->oid_type, (opts.flags & GIT_MERGE_SKIP_REUC)); done: @@ -2200,8 +2203,8 @@ int git_merge_trees( result = our_tree; if (result) { - if ((error = git_index_new(out)) == 0) - error = git_index_read_tree(*out, result); + if ((error = git_index__new(out, repo->oid_type)) == 0) + error = git_index_read_tree(*out, result); return error; } diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 3f57fb23cca..4bf92dcdca3 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1547,7 +1547,8 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) if ((error = repository_index_path(&index_path, repo)) < 0) return error; - error = git_index_open(&index, index_path.ptr); + error = git_index__open(&index, index_path.ptr, repo->oid_type); + if (!error) { GIT_REFCOUNT_OWN(index, repo); diff --git a/src/libgit2/stash.c b/src/libgit2/stash.c index 319ae3a3f0c..b49e95cdb21 100644 --- a/src/libgit2/stash.c +++ b/src/libgit2/stash.c @@ -284,7 +284,7 @@ static int build_untracked_tree( struct stash_update_rules data = {0}; int error; - if ((error = git_index_new(&i_index)) < 0) + if ((error = git_index__new(&i_index, repo->oid_type)) < 0) goto cleanup; if (flags & GIT_STASH_INCLUDE_UNTRACKED) { @@ -487,7 +487,7 @@ static int commit_worktree( int error = 0, ignorecase; if ((error = git_repository_index(&r_index, repo) < 0) || - (error = git_index_new(&i_index)) < 0 || + (error = git_index__new(&i_index, repo->oid_type)) < 0 || (error = git_index__fill(i_index, &r_index->entries) < 0) || (error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0) goto cleanup; @@ -732,7 +732,7 @@ int git_stash_save_with_opts( i_commit, b_commit, u_commit)) < 0) goto cleanup; } else { - if ((error = git_index_new(&paths_index)) < 0 || + if ((error = git_index__new(&paths_index, repo->oid_type)) < 0 || (error = retrieve_head(&head, repo)) < 0 || (error = git_reference_peel((git_object**)&tree, head, GIT_OBJECT_TREE)) < 0 || (error = git_index_read_tree(paths_index, tree)) < 0 || @@ -1003,6 +1003,7 @@ static int stage_new_file(const git_index_entry **entries, void *data) static int stage_new_files( git_index **out, + git_repository *repo, git_tree *parent_tree, git_tree *tree) { @@ -1011,7 +1012,7 @@ static int stage_new_files( git_index *index = NULL; int error; - if ((error = git_index_new(&index)) < 0 || + if ((error = git_index__new(&index, repo->oid_type)) < 0 || (error = git_iterator_for_tree( &iterators[0], parent_tree, &iterator_options)) < 0 || (error = git_iterator_for_tree( @@ -1095,10 +1096,10 @@ int git_stash_apply( * previously unstaged contents are staged, not the previously staged.) */ } else if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) == 0) { - if ((error = stage_new_files( - &stash_adds, stash_parent_tree, stash_tree)) < 0 || - (error = merge_indexes( - &unstashed_index, repo, stash_parent_tree, repo_index, stash_adds)) < 0) + if ((error = stage_new_files(&stash_adds, repo, + stash_parent_tree, stash_tree)) < 0 || + (error = merge_indexes(&unstashed_index, repo, + stash_parent_tree, repo_index, stash_adds)) < 0) goto cleanup; } diff --git a/src/libgit2/tree-cache.c b/src/libgit2/tree-cache.c index 19fad85aea3..95d879860f1 100644 --- a/src/libgit2/tree-cache.c +++ b/src/libgit2/tree-cache.c @@ -71,12 +71,16 @@ const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char } } -static int read_tree_internal(git_tree_cache **out, - const char **buffer_in, const char *buffer_end, - git_pool *pool) +static int read_tree_internal( + git_tree_cache **out, + const char **buffer_in, + const char *buffer_end, + git_oid_t oid_type, + git_pool *pool) { git_tree_cache *tree = NULL; const char *name_start, *buffer; + size_t oid_size = git_oid_size(oid_type); int count; buffer = name_start = *buffer_in; @@ -87,7 +91,7 @@ static int read_tree_internal(git_tree_cache **out, if (++buffer >= buffer_end) goto corrupted; - if (git_tree_cache_new(&tree, name_start, pool) < 0) + if (git_tree_cache_new(&tree, name_start, oid_type, pool) < 0) return -1; /* Blank-terminated ASCII decimal number of entries in this tree */ @@ -108,14 +112,14 @@ static int read_tree_internal(git_tree_cache **out, if (*buffer != '\n' || ++buffer > buffer_end) goto corrupted; - /* The SHA1 is only there if it's not invalidated */ + /* The OID is only there if it's not invalidated */ if (tree->entry_count >= 0) { /* 160-bit SHA-1 for this tree and it's children */ - if (buffer + GIT_OID_SHA1_SIZE > buffer_end) + if (buffer + oid_size > buffer_end) goto corrupted; - git_oid__fromraw(&tree->oid, (const unsigned char *)buffer, GIT_OID_SHA1); - buffer += GIT_OID_SHA1_SIZE; + git_oid__fromraw(&tree->oid, (const unsigned char *)buffer, oid_type); + buffer += oid_size; } /* Parse children: */ @@ -130,7 +134,7 @@ static int read_tree_internal(git_tree_cache **out, memset(tree->children, 0x0, bufsize); for (i = 0; i < tree->children_count; ++i) { - if (read_tree_internal(&tree->children[i], &buffer, buffer_end, pool) < 0) + if (read_tree_internal(&tree->children[i], &buffer, buffer_end, oid_type, pool) < 0) goto corrupted; } } @@ -144,11 +148,16 @@ static int read_tree_internal(git_tree_cache **out, return -1; } -int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size, git_pool *pool) +int git_tree_cache_read( + git_tree_cache **tree, + const char *buffer, + size_t buffer_size, + git_oid_t oid_type, + git_pool *pool) { const char *buffer_end = buffer + buffer_size; - if (read_tree_internal(tree, &buffer, buffer_end, pool) < 0) + if (read_tree_internal(tree, &buffer, buffer_end, oid_type, pool) < 0) return -1; if (buffer < buffer_end) { @@ -201,7 +210,7 @@ static int read_tree_recursive(git_tree_cache *cache, const git_tree *tree, git_ continue; } - if ((error = git_tree_cache_new(&cache->children[j], git_tree_entry_name(entry), pool)) < 0) + if ((error = git_tree_cache_new(&cache->children[j], git_tree_entry_name(entry), cache->oid_type, pool)) < 0) return error; if ((error = git_tree_lookup(&subtree, repo, git_tree_entry_id(entry))) < 0) @@ -219,12 +228,12 @@ static int read_tree_recursive(git_tree_cache *cache, const git_tree *tree, git_ return 0; } -int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_pool *pool) +int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_oid_t oid_type, git_pool *pool) { int error; git_tree_cache *cache; - if ((error = git_tree_cache_new(&cache, "", pool)) < 0) + if ((error = git_tree_cache_new(&cache, "", oid_type, pool)) < 0) return error; if ((error = read_tree_recursive(cache, tree, pool)) < 0) @@ -234,7 +243,7 @@ int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_poo return 0; } -int git_tree_cache_new(git_tree_cache **out, const char *name, git_pool *pool) +int git_tree_cache_new(git_tree_cache **out, const char *name, git_oid_t oid_type, git_pool *pool) { size_t name_len, alloc_size; git_tree_cache *tree; @@ -248,6 +257,7 @@ int git_tree_cache_new(git_tree_cache **out, const char *name, git_pool *pool) memset(tree, 0x0, sizeof(git_tree_cache)); /* NUL-terminated tree name */ + tree->oid_type = oid_type; tree->namelen = name_len; memcpy(tree->name, name, name_len); tree->name[name_len] = '\0'; @@ -263,7 +273,7 @@ static void write_tree(git_str *out, git_tree_cache *tree) git_str_printf(out, "%s%c%"PRIdZ" %"PRIuZ"\n", tree->name, 0, tree->entry_count, tree->children_count); if (tree->entry_count != -1) - git_str_put(out, (char *)&tree->oid.id, GIT_OID_SHA1_SIZE); + git_str_put(out, (char *)&tree->oid.id, git_oid_size(tree->oid_type)); for (i = 0; i < tree->children_count; i++) write_tree(out, tree->children[i]); diff --git a/src/libgit2/tree-cache.h b/src/libgit2/tree-cache.h index a27e3046614..e4a73f277e0 100644 --- a/src/libgit2/tree-cache.h +++ b/src/libgit2/tree-cache.h @@ -18,6 +18,8 @@ typedef struct git_tree_cache { struct git_tree_cache **children; size_t children_count; + git_oid_t oid_type; + ssize_t entry_count; git_oid oid; size_t namelen; @@ -25,14 +27,14 @@ typedef struct git_tree_cache { } git_tree_cache; int git_tree_cache_write(git_str *out, git_tree_cache *tree); -int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size, git_pool *pool); +int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size, git_oid_t oid_type, git_pool *pool); void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path); const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path); -int git_tree_cache_new(git_tree_cache **out, const char *name, git_pool *pool); +int git_tree_cache_new(git_tree_cache **out, const char *name, git_oid_t oid_type, git_pool *pool); /** * Read a tree as the root of the tree cache (like for `git read-tree`) */ -int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_pool *pool); +int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_oid_t oid_type, git_pool *pool); void git_tree_cache_free(git_tree_cache *tree); #endif diff --git a/src/libgit2/tree.c b/src/libgit2/tree.c index 9293d9422ba..236a87f7e3e 100644 --- a/src/libgit2/tree.c +++ b/src/libgit2/tree.c @@ -731,7 +731,7 @@ int git_tree__write_index( return ret; /* Read the tree cache into the index */ - ret = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool); + ret = git_tree_cache_read_tree(&index->tree, tree, index->oid_type, &index->tree_pool); git_tree_free(tree); return ret; diff --git a/tests/libgit2/checkout/index.c b/tests/libgit2/checkout/index.c index 6432cba841d..3dfdaa630ae 100644 --- a/tests/libgit2/checkout/index.c +++ b/tests/libgit2/checkout/index.c @@ -4,6 +4,7 @@ #include "git2/checkout.h" #include "futils.h" #include "repository.h" +#include "index.h" #include "remote.h" #include "repo/repo_helpers.h" @@ -834,7 +835,7 @@ void test_checkout_index__adding_conflict_removes_stage_0(void) git_index *new_index, *index; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; - cl_git_pass(git_index_new(&new_index)); + cl_git_pass(git_index__new(&new_index, GIT_OID_SHA1)); add_conflict(new_index, "new.txt"); cl_git_pass(git_checkout_index(g_repo, new_index, &opts)); diff --git a/tests/libgit2/clone/nonetwork.c b/tests/libgit2/clone/nonetwork.c index eab63363516..5316003f82a 100644 --- a/tests/libgit2/clone/nonetwork.c +++ b/tests/libgit2/clone/nonetwork.c @@ -5,6 +5,7 @@ #include "remote.h" #include "futils.h" #include "repository.h" +#include "index.h" #define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository" @@ -271,7 +272,7 @@ void test_clone_nonetwork__clone_tag_to_tree(void) stage = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_repository_odb(&odb, stage)); - cl_git_pass(git_index_new(&index)); + cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); memset(&entry, 0, sizeof(git_index_entry)); entry.path = file_path; diff --git a/tests/libgit2/diff/index.c b/tests/libgit2/diff/index.c index 5773b748e10..b7866750bb3 100644 --- a/tests/libgit2/diff/index.c +++ b/tests/libgit2/diff/index.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "diff_helpers.h" +#include "index.h" static git_repository *g_repo = NULL; @@ -278,7 +279,7 @@ void test_diff_index__to_index(void) git_diff *diff; diff_expects exp; - cl_git_pass(git_index_new(&old_index)); + cl_git_pass(git_index__new(&old_index, GIT_OID_SHA1)); old_tree = resolve_commit_oid_to_tree(g_repo, a_commit); cl_git_pass(git_index_read_tree(old_index, old_tree)); diff --git a/tests/libgit2/index/cache.c b/tests/libgit2/index/cache.c index 7576331b014..77f19a50b29 100644 --- a/tests/libgit2/index/cache.c +++ b/tests/libgit2/index/cache.c @@ -24,7 +24,7 @@ void test_index_cache__write_extension_at_root(void) const char *tree_id_str = "45dd856fdd4d89b884c340ba0e047752d9b085d6"; const char *index_file = "index-tree"; - cl_git_pass(git_index_open(&index, index_file)); + cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); cl_assert(index->tree == NULL); cl_git_pass(git_oid__fromstr(&id, tree_id_str, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); @@ -35,7 +35,7 @@ void test_index_cache__write_extension_at_root(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_index_open(&index, index_file)); + cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); cl_assert(index->tree); cl_assert_equal_i(git_index_entrycount(index), index->tree->entry_count); @@ -56,7 +56,7 @@ void test_index_cache__write_extension_invalidated_root(void) const char *index_file = "index-tree-invalidated"; git_index_entry entry; - cl_git_pass(git_index_open(&index, index_file)); + cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); cl_assert(index->tree == NULL); cl_git_pass(git_oid__fromstr(&id, tree_id_str, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); @@ -77,7 +77,7 @@ void test_index_cache__write_extension_invalidated_root(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_index_open(&index, index_file)); + cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); cl_assert(index->tree); cl_assert_equal_i(-1, index->tree->entry_count); @@ -96,7 +96,7 @@ void test_index_cache__read_tree_no_children(void) git_tree *tree; git_oid id; - cl_git_pass(git_index_new(&index)); + cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); cl_assert(index->tree == NULL); cl_git_pass(git_oid__fromstr(&id, "45dd856fdd4d89b884c340ba0e047752d9b085d6", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); diff --git a/tests/libgit2/index/inmemory.c b/tests/libgit2/index/inmemory.c index 38e91e0fd94..39374af67bc 100644 --- a/tests/libgit2/index/inmemory.c +++ b/tests/libgit2/index/inmemory.c @@ -1,10 +1,11 @@ #include "clar_libgit2.h" +#include "index.h" void test_index_inmemory__can_create_an_inmemory_index(void) { git_index *index; - cl_git_pass(git_index_new(&index)); + cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); cl_assert_equal_i(0, (int)git_index_entrycount(index)); git_index_free(index); @@ -14,7 +15,7 @@ void test_index_inmemory__cannot_add_bypath_to_an_inmemory_index(void) { git_index *index; - cl_git_pass(git_index_new(&index)); + cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); cl_assert_equal_i(GIT_ERROR, git_index_add_bypath(index, "test.txt")); diff --git a/tests/libgit2/index/racy.c b/tests/libgit2/index/racy.c index 07b3b73d429..a1d6f9c6ec0 100644 --- a/tests/libgit2/index/racy.c +++ b/tests/libgit2/index/racy.c @@ -287,7 +287,7 @@ void test_index_racy__read_index_smudges(void) setup_race(); cl_git_pass(git_repository_index(&index, g_repo)); - cl_git_pass(git_index_new(&newindex)); + cl_git_pass(git_index__new(&newindex, GIT_OID_SHA1)); cl_git_pass(git_index_read_index(newindex, index)); cl_assert(entry = git_index_get_bypath(newindex, "A", 0)); @@ -305,7 +305,7 @@ void test_index_racy__read_index_clears_uptodate_bit(void) setup_uptodate_files(); cl_git_pass(git_repository_index(&index, g_repo)); - cl_git_pass(git_index_new(&newindex)); + cl_git_pass(git_index__new(&newindex, GIT_OID_SHA1)); cl_git_pass(git_index_read_index(newindex, index)); /* ensure that files brought in from the other index are not uptodate */ diff --git a/tests/libgit2/index/read_index.c b/tests/libgit2/index/read_index.c index ac03cf1773e..9c80be299f1 100644 --- a/tests/libgit2/index/read_index.c +++ b/tests/libgit2/index/read_index.c @@ -42,7 +42,7 @@ void test_index_read_index__maintains_stat_cache(void) /* read-tree, then read index */ git_tree_lookup(&tree, _repo, &index_id); - cl_git_pass(git_index_new(&new_index)); + cl_git_pass(git_index__new(&new_index, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(new_index, tree)); git_tree_free(tree); @@ -81,7 +81,7 @@ static bool roundtrip_with_read_index(const char *tree_idstr) cl_git_pass(git_oid__fromstr(&tree_id, tree_idstr, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); - cl_git_pass(git_index_new(&tree_index)); + cl_git_pass(git_index__new(&tree_index, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(tree_index, tree)); cl_git_pass(git_index_read_index(_index, tree_index)); cl_git_pass(git_index_write_tree(&new_tree_id, _index)); @@ -113,12 +113,12 @@ void test_index_read_index__read_and_writes(void) cl_git_pass(git_oid__fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); - cl_git_pass(git_index_new(&tree_index)); + cl_git_pass(git_index__new(&tree_index, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(tree_index, tree)); cl_git_pass(git_index_read_index(_index, tree_index)); cl_git_pass(git_index_write(_index)); - cl_git_pass(git_index_open(&new_index, git_index_path(_index))); + cl_git_pass(git_index__open(&new_index, git_index_path(_index), GIT_OID_SHA1)); cl_git_pass(git_index_write_tree_to(&new_tree_id, new_index, _repo)); cl_assert_equal_oid(&tree_id, &new_tree_id); @@ -174,8 +174,8 @@ void test_index_read_index__handles_conflicts(void) cl_git_pass(git_oid__fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); - cl_git_pass(git_index_new(&index)); - cl_git_pass(git_index_new(&new_index)); + cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); + cl_git_pass(git_index__new(&new_index, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_read_tree(new_index, tree)); diff --git a/tests/libgit2/index/tests.c b/tests/libgit2/index/tests.c index da3ff6dd7b5..b48eb0fc170 100644 --- a/tests/libgit2/index/tests.c +++ b/tests/libgit2/index/tests.c @@ -81,7 +81,7 @@ void test_index_tests__empty_index(void) { git_index *index; - cl_git_pass(git_index_open(&index, "in-memory-index")); + cl_git_pass(git_index__open(&index, "in-memory-index", GIT_OID_SHA1)); cl_assert(index->on_disk == 0); cl_assert(git_index_entrycount(index) == 0); @@ -96,7 +96,7 @@ void test_index_tests__default_test_index(void) unsigned int i; git_index_entry **entries; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count); @@ -119,7 +119,7 @@ void test_index_tests__gitgit_index(void) { git_index *index; - cl_git_pass(git_index_open(&index, TEST_INDEX2_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX2_PATH, GIT_OID_SHA1)); cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count_2); @@ -134,7 +134,7 @@ void test_index_tests__find_in_existing(void) git_index *index; unsigned int i; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { size_t idx; @@ -151,7 +151,7 @@ void test_index_tests__find_in_empty(void) git_index *index; unsigned int i; - cl_git_pass(git_index_open(&index, "fake-index")); + cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA1)); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path)); @@ -166,7 +166,7 @@ void test_index_tests__find_prefix(void) const git_index_entry *entry; size_t pos; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); cl_git_pass(git_index_find_prefix(&pos, index, "src")); entry = git_index_get_byindex(index, pos); @@ -187,7 +187,7 @@ void test_index_tests__write(void) copy_file(TEST_INDEXBIG_PATH, "index_rewrite"); - cl_git_pass(git_index_open(&index, "index_rewrite")); + cl_git_pass(git_index__open(&index, "index_rewrite", GIT_OID_SHA1)); cl_assert(index->on_disk); cl_git_pass(git_index_write(index)); @@ -218,7 +218,7 @@ void test_index_tests__sort1(void) /* sort the entries in an empty index */ git_index *index; - cl_git_pass(git_index_open(&index, "fake-index")); + cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA1)); /* FIXME: this test is slightly dumb */ cl_assert(git_vector_is_sorted(&index->entries)); @@ -703,7 +703,7 @@ void test_index_tests__write_tree_invalid_unowned_index(void) git_index_entry entry = {{0}}; git_oid tree_id; - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); cl_git_pass(git_oid__fromstr(&entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318", GIT_OID_SHA1)); entry.path = "foo"; @@ -966,7 +966,7 @@ void test_index_tests__reload_from_disk(void) cl_git_pass(git_repository_index(&write_index, repo)); cl_assert_equal_i(false, write_index->on_disk); - cl_git_pass(git_index_open(&read_index, write_index->index_file_path)); + cl_git_pass(git_index__open(&read_index, write_index->index_file_path, GIT_OID_SHA1)); cl_assert_equal_i(false, read_index->on_disk); /* Stage two new files against the write_index */ @@ -1004,7 +1004,7 @@ void test_index_tests__corrupted_extension(void) { git_index *index; - cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR); + cl_git_fail_with(git_index__open(&index, TEST_INDEXBAD_PATH, GIT_OID_SHA1), GIT_ERROR); } void test_index_tests__reload_while_ignoring_case(void) @@ -1012,7 +1012,7 @@ void test_index_tests__reload_while_ignoring_case(void) git_index *index; unsigned int caps; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); cl_git_pass(git_vector_verify_sorted(&index->entries)); caps = git_index_caps(index); @@ -1037,7 +1037,7 @@ void test_index_tests__change_icase_on_instance(void) unsigned int caps; const git_index_entry *e; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); cl_git_pass(git_vector_verify_sorted(&index->entries)); caps = git_index_caps(index); @@ -1093,7 +1093,7 @@ void test_index_tests__can_iterate(void) size_t i, iterator_idx = 0, found = 0; int ret; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); cl_git_pass(git_index_iterator_new(&iterator, index)); cl_assert(git_vector_is_sorted(&iterator->snap)); @@ -1136,7 +1136,7 @@ void test_index_tests__can_modify_while_iterating(void) size_t expected = 0, seen = 0; int ret; - cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); cl_git_pass(git_index_iterator_new(&iterator, index)); expected = git_index_entrycount(index); diff --git a/tests/libgit2/index/tests256.c b/tests/libgit2/index/tests256.c new file mode 100644 index 00000000000..fed8bfb9358 --- /dev/null +++ b/tests/libgit2/index/tests256.c @@ -0,0 +1,1169 @@ +#include "clar_libgit2.h" +#include "index.h" + +#ifdef GIT_EXPERIMENTAL_SHA256 + +static const size_t index_entry_count = 4344; +#define TEST_INDEX_PATH cl_fixture("git-sha256.index") + +static git_repository_init_options repo_init_opts = + GIT_REPOSITORY_INIT_OPTIONS_INIT; + +/* Suite data */ +struct test_entry { + size_t index; + char path[128]; + off64_t file_size; + git_time_t mtime; +}; + +static struct test_entry test_entries[] = { + { 892, "Makefile", 120084, 0x642c3a6e }, + { 1542, "git.c", 27432, 0x642c3a6e }, + { 1737, "perl/Git.pm", 48084, 0x642c3a6e }, + { 1961, "t/Makefile", 4711, 0x642c3a6e }, + { 4343, "zlib.c", 6271, 0x642c3a6f } +}; + +/* Helpers */ +static void copy_file(const char *src, const char *dst) +{ + git_str source_buf = GIT_STR_INIT; + git_file dst_fd; + + cl_git_pass(git_futils_readbuffer(&source_buf, src)); + + dst_fd = git_futils_creat_withpath(dst, 0777, 0666); /* -V536 */ + if (dst_fd < 0) + goto cleanup; + + cl_git_pass(p_write(dst_fd, source_buf.ptr, source_buf.size)); + +cleanup: + git_str_dispose(&source_buf); + p_close(dst_fd); +} + +static void files_are_equal(const char *a, const char *b) +{ + git_str buf_a = GIT_STR_INIT; + git_str buf_b = GIT_STR_INIT; + + if (git_futils_readbuffer(&buf_a, a) < 0) + cl_assert(0); + + if (git_futils_readbuffer(&buf_b, b) < 0) { + git_str_dispose(&buf_a); + cl_assert(0); + } + + cl_assert_equal_sz(buf_a.size, buf_b.size); + cl_assert(!memcmp(buf_a.ptr, buf_b.ptr, buf_a.size)); + + git_str_dispose(&buf_a); + git_str_dispose(&buf_b); +} + +#endif + +/* Fixture setup and teardown */ +void test_index_tests256__initialize(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + repo_init_opts.flags |= GIT_REPOSITORY_INIT_MKPATH; + repo_init_opts.oid_type = GIT_OID_SHA256; +#endif +} + +void test_index_tests256__cleanup(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, 0)); +#endif +} + +void test_index_tests256__empty_index(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + + cl_git_pass(git_index__open(&index, "in-memory-index", GIT_OID_SHA256)); + cl_assert(index->on_disk == 0); + + cl_assert(git_index_entrycount(index) == 0); + cl_assert(git_vector_is_sorted(&index->entries)); + + git_index_free(index); +#endif +} + +void test_index_tests256__default_test_index(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + unsigned int i; + git_index_entry **entries; + + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_assert(index->on_disk); + + cl_assert_equal_sz(git_index_entrycount(index), index_entry_count); + cl_assert(git_vector_is_sorted(&index->entries)); + + entries = (git_index_entry **)index->entries.contents; + + for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { + git_index_entry *e = entries[test_entries[i].index]; + + cl_assert_equal_s(e->path, test_entries[i].path); + cl_assert_equal_i(e->mtime.seconds, test_entries[i].mtime); + cl_assert_equal_i(e->file_size, test_entries[i].file_size); + } + + git_index_free(index); +#endif +} + +void test_index_tests256__find_in_existing(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + unsigned int i; + + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + + for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { + size_t idx; + + cl_assert(!git_index_find(&idx, index, test_entries[i].path)); + cl_assert(idx == test_entries[i].index); + } + + git_index_free(index); +#endif +} + +void test_index_tests256__find_in_empty(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + unsigned int i; + + cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA256)); + + for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { + cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path)); + } + + git_index_free(index); +#endif +} + +void test_index_tests256__find_prefix(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + const git_index_entry *entry; + size_t pos; + + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + + cl_git_pass(git_index_find_prefix(&pos, index, "Documentation")); + entry = git_index_get_byindex(index, pos); + cl_assert(git__strcmp(entry->path, "Documentation/.gitattributes") == 0); + + cl_git_pass(git_index_find_prefix(&pos, index, "contrib/RE")); + entry = git_index_get_byindex(index, pos); + cl_assert(git__strcmp(entry->path, "contrib/README") == 0); + + cl_assert(GIT_ENOTFOUND == git_index_find_prefix(NULL, index, "blah")); + + git_index_free(index); +#endif +} + +void test_index_tests256__write(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + + copy_file(TEST_INDEX_PATH, "index_rewrite"); + + cl_git_pass(git_index__open(&index, "index_rewrite", GIT_OID_SHA256)); + cl_assert(index->on_disk); + + cl_git_pass(git_index_write(index)); + files_are_equal(TEST_INDEX_PATH, "index_rewrite"); + + git_index_free(index); + + p_unlink("index_rewrite"); +#endif +} + +void test_index_tests256__sort1(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + /* sort the entries in an empty index */ + git_index *index; + + cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA256)); + + /* FIXME: this test is slightly dumb */ + cl_assert(git_vector_is_sorted(&index->entries)); + + git_index_free(index); +#endif +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +static void cleanup_myrepo(void *opaque) +{ + GIT_UNUSED(opaque); + cl_fixture_cleanup("myrepo"); +} +#endif + +void test_index_tests256__add(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + git_filebuf file = GIT_FILEBUF_INIT; + git_repository *repo; + const git_index_entry *entry; + git_oid id1; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + /* Initialize a new repository */ + cl_git_pass(git_repository_init_ext(&repo, "./myrepo", &repo_init_opts)); + + /* Ensure we're the only guy in the room */ + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + /* Create a new file in the working directory */ + cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777)); + cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666)); + cl_git_pass(git_filebuf_write(&file, "hey there\n", 10)); + cl_git_pass(git_filebuf_commit(&file)); + + /* Store the expected hash of the file/blob + * This has been generated by executing the following + * $ echo "hey there" | git hash-object --stdin + */ + cl_git_pass(git_oid__fromstr(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + + /* Add the new file to the index */ + cl_git_pass(git_index_add_bypath(index, "test.txt")); + + /* Wow... it worked! */ + cl_assert(git_index_entrycount(index) == 1); + entry = git_index_get_byindex(index, 0); + + /* And the built-in hashing mechanism worked as expected */ + cl_assert_equal_oid(&id1, &entry->id); + + /* Test access by path instead of index */ + cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); + cl_assert_equal_oid(&id1, &entry->id); + + git_index_free(index); + git_repository_free(repo); +#endif +} + +void test_index_tests256__add_frombuffer(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + git_repository *repo; + git_index_entry entry; + const git_index_entry *returned_entry; + + git_oid id1; + git_blob *blob; + + const char *content = "hey there\n"; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + /* Initialize a new repository */ + cl_git_pass(git_repository_init_ext(&repo, "./myrepo", &repo_init_opts)); + + /* Ensure we're the only guy in the room */ + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + /* Store the expected hash of the file/blob + * This has been generated by executing the following + * $ echo "hey there" | git hash-object --stdin + */ + cl_git_pass(git_oid__fromstr(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + + /* Add the new file to the index */ + memset(&entry, 0x0, sizeof(git_index_entry)); + entry.mode = GIT_FILEMODE_BLOB; + entry.path = "test.txt"; + cl_git_pass(git_index_add_from_buffer(index, &entry, + content, strlen(content))); + + /* Wow... it worked! */ + cl_assert(git_index_entrycount(index) == 1); + returned_entry = git_index_get_byindex(index, 0); + + /* And the built-in hashing mechanism worked as expected */ + cl_assert_equal_oid(&id1, &returned_entry->id); + /* And mode is the one asked */ + cl_assert_equal_i(GIT_FILEMODE_BLOB, returned_entry->mode); + + /* Test access by path instead of index */ + cl_assert((returned_entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); + cl_assert_equal_oid(&id1, &returned_entry->id); + + /* Test the blob is in the repository */ + cl_git_pass(git_blob_lookup(&blob, repo, &id1)); + cl_assert_equal_s( + content, git_blob_rawcontent(blob)); + git_blob_free(blob); + + git_index_free(index); + git_repository_free(repo); +#endif +} + +void test_index_tests256__dirty_and_clean(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + git_index_entry entry = {{0}}; + + /* Index is not dirty after opening */ + cl_git_pass(git_repository_init_ext(&repo, "./myrepo", &repo_init_opts)); + cl_git_pass(git_repository_index(&index, repo)); + + cl_assert(git_index_entrycount(index) == 0); + cl_assert(!git_index_is_dirty(index)); + + /* Index is dirty after adding an entry */ + entry.mode = GIT_FILEMODE_BLOB; + entry.path = "test.txt"; + cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4)); + cl_assert(git_index_entrycount(index) == 1); + cl_assert(git_index_is_dirty(index)); + + /* Index is not dirty after write */ + cl_git_pass(git_index_write(index)); + cl_assert(!git_index_is_dirty(index)); + + /* Index is dirty after removing an entry */ + cl_git_pass(git_index_remove_bypath(index, "test.txt")); + cl_assert(git_index_entrycount(index) == 0); + cl_assert(git_index_is_dirty(index)); + + /* Index is not dirty after write */ + cl_git_pass(git_index_write(index)); + cl_assert(!git_index_is_dirty(index)); + + /* Index remains not dirty after read */ + cl_git_pass(git_index_read(index, 0)); + cl_assert(!git_index_is_dirty(index)); + + /* Index is dirty when we do an unforced read with dirty content */ + cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4)); + cl_assert(git_index_entrycount(index) == 1); + cl_assert(git_index_is_dirty(index)); + + cl_git_pass(git_index_read(index, 0)); + cl_assert(git_index_is_dirty(index)); + + /* Index is clean when we force a read with dirty content */ + cl_git_pass(git_index_read(index, 1)); + cl_assert(!git_index_is_dirty(index)); + + git_index_free(index); + git_repository_free(repo); +#endif +} + +void test_index_tests256__dirty_fails_optionally(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + git_index_entry entry = {{0}}; + + /* Index is not dirty after opening */ + repo = cl_git_sandbox_init("testrepo"); + cl_git_pass(git_repository_index(&index, repo)); + + /* Index is dirty after adding an entry */ + entry.mode = GIT_FILEMODE_BLOB; + entry.path = "test.txt"; + cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4)); + cl_assert(git_index_is_dirty(index)); + + cl_git_pass(git_checkout_head(repo, NULL)); + + /* Index is dirty (again) after adding an entry */ + entry.mode = GIT_FILEMODE_BLOB; + entry.path = "test.txt"; + cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4)); + cl_assert(git_index_is_dirty(index)); + + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, 1)); + cl_git_fail_with(GIT_EINDEXDIRTY, git_checkout_head(repo, NULL)); + + git_index_free(index); + cl_git_sandbox_cleanup(); +#endif +} + +void test_index_tests256__add_frombuffer_reset_entry(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + git_repository *repo; + git_index_entry entry; + const git_index_entry *returned_entry; + git_filebuf file = GIT_FILEBUF_INIT; + + git_oid id1; + git_blob *blob; + const char *old_content = "here\n"; + const char *content = "hey there\n"; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + /* Initialize a new repository */ + cl_git_pass(git_repository_init_ext(&repo, "./myrepo", &repo_init_opts)); + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777)); + cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666)); + cl_git_pass(git_filebuf_write(&file, old_content, strlen(old_content))); + cl_git_pass(git_filebuf_commit(&file)); + + /* Store the expected hash of the file/blob + * This has been generated by executing the following + * $ echo "hey there" | git hash-object --stdin + */ + cl_git_pass(git_oid__fromstr(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + + cl_git_pass(git_index_add_bypath(index, "test.txt")); + + /* Add the new file to the index */ + memset(&entry, 0x0, sizeof(git_index_entry)); + entry.mode = GIT_FILEMODE_BLOB; + entry.path = "test.txt"; + cl_git_pass(git_index_add_from_buffer(index, &entry, + content, strlen(content))); + + /* Wow... it worked! */ + cl_assert(git_index_entrycount(index) == 1); + returned_entry = git_index_get_byindex(index, 0); + + /* And the built-in hashing mechanism worked as expected */ + cl_assert_equal_oid(&id1, &returned_entry->id); + /* And mode is the one asked */ + cl_assert_equal_i(GIT_FILEMODE_BLOB, returned_entry->mode); + + /* Test access by path instead of index */ + cl_assert((returned_entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); + cl_assert_equal_oid(&id1, &returned_entry->id); + cl_assert_equal_i(0, returned_entry->dev); + cl_assert_equal_i(0, returned_entry->ino); + cl_assert_equal_i(0, returned_entry->uid); + cl_assert_equal_i(0, returned_entry->uid); + cl_assert_equal_i(10, returned_entry->file_size); + + /* Test the blob is in the repository */ + cl_git_pass(git_blob_lookup(&blob, repo, &id1)); + cl_assert_equal_s(content, git_blob_rawcontent(blob)); + git_blob_free(blob); + + git_index_free(index); + git_repository_free(repo); +#endif +} + +void test_index_tests256__add_bypath_to_a_bare_repository_returns_EBAREPO(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *bare_repo; + git_index *index; + + cl_git_pass(git_repository_open(&bare_repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_index(&index, bare_repo)); + + cl_assert_equal_i(GIT_EBAREREPO, git_index_add_bypath(index, "test.txt")); + + git_index_free(index); + git_repository_free(bare_repo); +#endif +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +static void assert_add_bypath_fails(git_repository *repo, const char *fn) +{ + git_index *index; + git_str path = GIT_STR_INIT; + + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + git_str_joinpath(&path, "./invalid", fn); + + cl_git_mkfile(path.ptr, NULL); + cl_git_fail(git_index_add_bypath(index, fn)); + cl_must_pass(p_unlink(path.ptr)); + + cl_assert(git_index_entrycount(index) == 0); + + git_str_dispose(&path); + git_index_free(index); +} +#endif + +/* Test that writing an invalid filename fails */ +void test_index_tests256__cannot_add_invalid_filename(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + + cl_must_pass(p_mkdir("invalid", 0700)); + cl_git_pass(git_repository_init_ext(&repo, "./invalid", &repo_init_opts)); + cl_must_pass(p_mkdir("./invalid/subdir", 0777)); + + /* cl_git_mkfile() needs the dir to exist */ + if (!git_fs_path_exists("./invalid/.GIT")) + cl_must_pass(p_mkdir("./invalid/.GIT", 0777)); + if (!git_fs_path_exists("./invalid/.GiT")) + cl_must_pass(p_mkdir("./invalid/.GiT", 0777)); + + assert_add_bypath_fails(repo, ".git/hello"); + assert_add_bypath_fails(repo, ".GIT/hello"); + assert_add_bypath_fails(repo, ".GiT/hello"); + assert_add_bypath_fails(repo, "./.git/hello"); + assert_add_bypath_fails(repo, "./foo"); + assert_add_bypath_fails(repo, "./bar"); + assert_add_bypath_fails(repo, "subdir/../bar"); + + git_repository_free(repo); + + cl_fixture_cleanup("invalid"); +#endif +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +static void assert_add_fails(git_repository *repo, const char *fn) +{ + git_index *index; + git_str path = GIT_STR_INIT; + git_index_entry entry = {{0}}; + + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + entry.path = fn; + entry.mode = GIT_FILEMODE_BLOB; + cl_git_pass(git_oid__fromstr(&entry.id, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + + cl_git_fail(git_index_add(index, &entry)); + + cl_assert(git_index_entrycount(index) == 0); + + git_str_dispose(&path); + git_index_free(index); +} +#endif + +/* + * Test that writing an invalid filename fails on filesystem + * specific protected names + */ +void test_index_tests256__cannot_add_protected_invalid_filename(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + + cl_must_pass(p_mkdir("invalid", 0700)); + + cl_git_pass(git_repository_init(&repo, "./invalid", 0)); + + /* add a file to the repository so we can reference it later */ + cl_git_pass(git_repository_index(&index, repo)); + cl_git_mkfile("invalid/dummy.txt", ""); + cl_git_pass(git_index_add_bypath(index, "dummy.txt")); + cl_must_pass(p_unlink("invalid/dummy.txt")); + cl_git_pass(git_index_remove_bypath(index, "dummy.txt")); + git_index_free(index); + + cl_repo_set_bool(repo, "core.protectHFS", true); + cl_repo_set_bool(repo, "core.protectNTFS", true); + + assert_add_fails(repo, ".git./hello"); + assert_add_fails(repo, ".git\xe2\x80\xad/hello"); + assert_add_fails(repo, "git~1/hello"); + assert_add_fails(repo, ".git\xe2\x81\xaf/hello"); + assert_add_fails(repo, ".git::$INDEX_ALLOCATION/dummy-file"); + + git_repository_free(repo); + + cl_fixture_cleanup("invalid"); +#endif +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +static void replace_char(char *str, char in, char out) +{ + char *c = str; + + while (*c++) + if (*c == in) + *c = out; +} + +static void assert_write_fails(git_repository *repo, const char *fn_orig) +{ + git_index *index; + git_oid expected; + const git_index_entry *entry; + git_str path = GIT_STR_INIT; + char *fn; + + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + /* + * Sneak a valid path into the index, we'll update it + * to an invalid path when we try to write the index. + */ + fn = git__strdup(fn_orig); + replace_char(fn, '/', '_'); + replace_char(fn, ':', '!'); + + git_str_joinpath(&path, "./invalid", fn); + + cl_git_mkfile(path.ptr, NULL); + + cl_git_pass(git_index_add_bypath(index, fn)); + + cl_assert(entry = git_index_get_bypath(index, fn, 0)); + + /* kids, don't try this at home */ + replace_char((char *)entry->path, '_', '/'); + replace_char((char *)entry->path, '!', ':'); + + /* write-tree */ + cl_git_fail(git_index_write_tree(&expected, index)); + + p_unlink(path.ptr); + + cl_git_pass(git_index_remove_all(index, NULL, NULL, NULL)); + git_str_dispose(&path); + git_index_free(index); + git__free(fn); +} +#endif + +void test_index_tests256__write_tree_invalid_unowned_index(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *idx; + git_repository *repo; + git_index_entry entry = {{0}}; + git_oid tree_id; + + cl_git_pass(git_index__new(&idx, GIT_OID_SHA256)); + + // TODO: this one is failing + cl_git_pass(git_oid__fromstr(&entry.id, "a8c2e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); + entry.path = "foo"; + entry.mode = GIT_FILEMODE_BLOB; + cl_git_pass(git_index_add(idx, &entry)); + + cl_git_pass(git_repository_init_ext(&repo, "./invalid-id", &repo_init_opts)); + + cl_git_fail(git_index_write_tree_to(&tree_id, idx, repo)); + + git_index_free(idx); + git_repository_free(repo); + + cl_fixture_cleanup("invalid-id"); +#endif +} + +/* Test that writing an invalid filename fails */ +void test_index_tests256__write_invalid_filename(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + + p_mkdir("invalid", 0700); + + cl_git_pass(git_repository_init(&repo, "./invalid", 0)); + + assert_write_fails(repo, ".git/hello"); + assert_write_fails(repo, ".GIT/hello"); + assert_write_fails(repo, ".GiT/hello"); + assert_write_fails(repo, "./.git/hello"); + assert_write_fails(repo, "./foo"); + assert_write_fails(repo, "./bar"); + assert_write_fails(repo, "foo/../bar"); + + git_repository_free(repo); + + cl_fixture_cleanup("invalid"); +#endif +} + +void test_index_tests256__honors_protect_filesystems(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + + p_mkdir("invalid", 0700); + + cl_git_pass(git_repository_init(&repo, "./invalid", 0)); + + cl_repo_set_bool(repo, "core.protectHFS", true); + cl_repo_set_bool(repo, "core.protectNTFS", true); + + assert_write_fails(repo, ".git./hello"); + assert_write_fails(repo, ".git\xe2\x80\xad/hello"); + assert_write_fails(repo, "git~1/hello"); + assert_write_fails(repo, ".git\xe2\x81\xaf/hello"); + assert_write_fails(repo, ".git::$INDEX_ALLOCATION/dummy-file"); + + git_repository_free(repo); + + cl_fixture_cleanup("invalid"); +#endif +} + +void test_index_tests256__protectntfs_on_by_default(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + + p_mkdir("invalid", 0700); + + cl_git_pass(git_repository_init(&repo, "./invalid", 0)); + assert_write_fails(repo, ".git./hello"); + assert_write_fails(repo, "git~1/hello"); + + git_repository_free(repo); + + cl_fixture_cleanup("invalid"); +#endif +} + +void test_index_tests256__can_disable_protectntfs(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + + cl_must_pass(p_mkdir("valid", 0700)); + cl_git_rewritefile("valid/git~1", "steal the shortname"); + + cl_git_pass(git_repository_init(&repo, "./valid", 0)); + cl_git_pass(git_repository_index(&index, repo)); + cl_repo_set_bool(repo, "core.protectNTFS", false); + + cl_git_pass(git_index_add_bypath(index, "git~1")); + + git_index_free(index); + git_repository_free(repo); + + cl_fixture_cleanup("valid"); +#endif +} + +void test_index_tests256__remove_entry(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + + p_mkdir("index_test", 0770); + + cl_git_pass(git_repository_init(&repo, "index_test", 0)); + cl_git_pass(git_repository_index(&index, repo)); + cl_assert(git_index_entrycount(index) == 0); + + cl_git_mkfile("index_test/hello", NULL); + cl_git_pass(git_index_add_bypath(index, "hello")); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert(git_index_entrycount(index) == 1); + cl_assert(git_index_get_bypath(index, "hello", 0) != NULL); + + cl_git_pass(git_index_remove(index, "hello", 0)); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert(git_index_entrycount(index) == 0); + cl_assert(git_index_get_bypath(index, "hello", 0) == NULL); + + git_index_free(index); + git_repository_free(repo); + cl_fixture_cleanup("index_test"); +#endif +} + +void test_index_tests256__remove_directory(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + + p_mkdir("index_test", 0770); + + cl_git_pass(git_repository_init(&repo, "index_test", 0)); + cl_git_pass(git_repository_index(&index, repo)); + cl_assert_equal_i(0, (int)git_index_entrycount(index)); + + p_mkdir("index_test/a", 0770); + cl_git_mkfile("index_test/a/1.txt", NULL); + cl_git_mkfile("index_test/a/2.txt", NULL); + cl_git_mkfile("index_test/a/3.txt", NULL); + cl_git_mkfile("index_test/b.txt", NULL); + + cl_git_pass(git_index_add_bypath(index, "a/1.txt")); + cl_git_pass(git_index_add_bypath(index, "a/2.txt")); + cl_git_pass(git_index_add_bypath(index, "a/3.txt")); + cl_git_pass(git_index_add_bypath(index, "b.txt")); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert_equal_i(4, (int)git_index_entrycount(index)); + cl_assert(git_index_get_bypath(index, "a/1.txt", 0) != NULL); + cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL); + cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); + + cl_git_pass(git_index_remove(index, "a/1.txt", 0)); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert_equal_i(3, (int)git_index_entrycount(index)); + cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL); + cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL); + cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); + + cl_git_pass(git_index_remove_directory(index, "a", 0)); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_index_read(index, true)); /* reload */ + cl_assert_equal_i(1, (int)git_index_entrycount(index)); + cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL); + cl_assert(git_index_get_bypath(index, "a/2.txt", 0) == NULL); + cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); + + git_index_free(index); + git_repository_free(repo); + cl_fixture_cleanup("index_test"); +#endif +} + +void test_index_tests256__preserves_case(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + const git_index_entry *entry; + int index_caps; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + cl_git_pass(git_repository_init_ext(&repo, "./myrepo", &repo_init_opts)); + cl_git_pass(git_repository_index(&index, repo)); + + index_caps = git_index_caps(index); + + cl_git_rewritefile("myrepo/test.txt", "hey there\n"); + cl_git_pass(git_index_add_bypath(index, "test.txt")); + + cl_git_pass(p_rename("myrepo/test.txt", "myrepo/TEST.txt")); + cl_git_rewritefile("myrepo/TEST.txt", "hello again\n"); + cl_git_pass(git_index_add_bypath(index, "TEST.txt")); + + if (index_caps & GIT_INDEX_CAPABILITY_IGNORE_CASE) + cl_assert_equal_i(1, (int)git_index_entrycount(index)); + else + cl_assert_equal_i(2, (int)git_index_entrycount(index)); + + /* Test access by path instead of index */ + cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); + /* The path should *not* have changed without an explicit remove */ + cl_assert(git__strcmp(entry->path, "test.txt") == 0); + + cl_assert((entry = git_index_get_bypath(index, "TEST.txt", 0)) != NULL); + if (index_caps & GIT_INDEX_CAPABILITY_IGNORE_CASE) + /* The path should *not* have changed without an explicit remove */ + cl_assert(git__strcmp(entry->path, "test.txt") == 0); + else + cl_assert(git__strcmp(entry->path, "TEST.txt") == 0); + + git_index_free(index); + git_repository_free(repo); +#endif +} + +void test_index_tests256__elocked(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + git_filebuf file = GIT_FILEBUF_INIT; + const git_error *err; + int error; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + cl_git_pass(git_repository_init_ext(&repo, "./myrepo", &repo_init_opts)); + cl_git_pass(git_repository_index(&index, repo)); + + /* Lock the index file so we fail to lock it */ + cl_git_pass(git_filebuf_open(&file, index->index_file_path, 0, 0666)); + error = git_index_write(index); + cl_assert_equal_i(GIT_ELOCKED, error); + + err = git_error_last(); + cl_assert_equal_i(err->klass, GIT_ERROR_INDEX); + + git_filebuf_cleanup(&file); + git_index_free(index); + git_repository_free(repo); +#endif +} + +void test_index_tests256__reload_from_disk(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *read_index; + git_index *write_index; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + cl_git_pass(git_futils_mkdir("./myrepo", 0777, GIT_MKDIR_PATH)); + cl_git_mkfile("./myrepo/a.txt", "a\n"); + cl_git_mkfile("./myrepo/b.txt", "b\n"); + + cl_git_pass(git_repository_init_ext(&repo, "./myrepo", &repo_init_opts)); + cl_git_pass(git_repository_index(&write_index, repo)); + cl_assert_equal_i(false, write_index->on_disk); + + cl_git_pass(git_index__open(&read_index, write_index->index_file_path, GIT_OID_SHA256)); + cl_assert_equal_i(false, read_index->on_disk); + + /* Stage two new files against the write_index */ + cl_git_pass(git_index_add_bypath(write_index, "a.txt")); + cl_git_pass(git_index_add_bypath(write_index, "b.txt")); + + cl_assert_equal_sz(2, git_index_entrycount(write_index)); + + /* Persist the index changes to disk */ + cl_git_pass(git_index_write(write_index)); + cl_assert_equal_i(true, write_index->on_disk); + + /* Sync the changes back into the read_index */ + cl_assert_equal_sz(0, git_index_entrycount(read_index)); + + cl_git_pass(git_index_read(read_index, true)); + cl_assert_equal_i(true, read_index->on_disk); + + cl_assert_equal_sz(2, git_index_entrycount(read_index)); + + /* Remove the index file from the filesystem */ + cl_git_pass(p_unlink(write_index->index_file_path)); + + /* Sync the changes back into the read_index */ + cl_git_pass(git_index_read(read_index, true)); + cl_assert_equal_i(false, read_index->on_disk); + cl_assert_equal_sz(0, git_index_entrycount(read_index)); + + git_index_free(read_index); + git_index_free(write_index); + git_repository_free(repo); +#endif +} + +void test_index_tests256__reload_while_ignoring_case(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + unsigned int caps; + + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_vector_verify_sorted(&index->entries)); + + caps = git_index_caps(index); + cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEX_CAPABILITY_IGNORE_CASE)); + cl_git_pass(git_index_read(index, true)); + cl_git_pass(git_vector_verify_sorted(&index->entries)); + cl_assert(git_index_get_bypath(index, "contrib/README", 0)); + cl_assert_equal_p(NULL, git_index_get_bypath(index, "CONTRIB/readme", 0)); + + cl_git_pass(git_index_set_caps(index, caps | GIT_INDEX_CAPABILITY_IGNORE_CASE)); + cl_git_pass(git_index_read(index, true)); + cl_git_pass(git_vector_verify_sorted(&index->entries)); + cl_assert(git_index_get_bypath(index, "contrib/README", 0)); + cl_assert(git_index_get_bypath(index, "CONTRIB/readme", 0)); + + git_index_free(index); +#endif +} + +void test_index_tests256__change_icase_on_instance(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + unsigned int caps; + const git_index_entry *e; + + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_vector_verify_sorted(&index->entries)); + + caps = git_index_caps(index); + cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEX_CAPABILITY_IGNORE_CASE)); + cl_assert_equal_i(false, index->ignore_case); + cl_git_pass(git_vector_verify_sorted(&index->entries)); + cl_assert(e = git_index_get_bypath(index, "contrib/README", 0)); + cl_assert_equal_p(NULL, e = git_index_get_bypath(index, "CONTRIB/readme", 0)); + cl_assert(e = git_index_get_bypath(index, "config.h", 0)); + cl_assert_equal_p(NULL, e = git_index_get_bypath(index, "CONFIG.H", 0)); + + cl_git_pass(git_index_set_caps(index, caps | GIT_INDEX_CAPABILITY_IGNORE_CASE)); + cl_assert_equal_i(true, index->ignore_case); + cl_git_pass(git_vector_verify_sorted(&index->entries)); + cl_assert(e = git_index_get_bypath(index, "config.h", 0)); + cl_assert_equal_s("config.h", e->path); + cl_assert(e = git_index_get_bypath(index, "CONFIG.H", 0)); + cl_assert_equal_s("config.h", e->path); + + git_index_free(index); +#endif +} + +void test_index_tests256__can_lock_index(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository *repo; + git_index *index; + git_indexwriter one = GIT_INDEXWRITER_INIT, + two = GIT_INDEXWRITER_INIT; + + repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_indexwriter_init(&one, index)); + + cl_git_fail_with(GIT_ELOCKED, git_indexwriter_init(&two, index)); + cl_git_fail_with(GIT_ELOCKED, git_index_write(index)); + + cl_git_pass(git_indexwriter_commit(&one)); + + cl_git_pass(git_index_write(index)); + + git_indexwriter_cleanup(&one); + git_indexwriter_cleanup(&two); + git_index_free(index); + cl_git_sandbox_cleanup(); +#endif +} + +void test_index_tests256__can_iterate(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + git_index_iterator *iterator; + const git_index_entry *entry; + size_t i, iterator_idx = 0, found = 0; + int ret; + + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_index_iterator_new(&iterator, index)); + + cl_assert(git_vector_is_sorted(&iterator->snap)); + + for (i = 0; i < ARRAY_SIZE(test_entries); i++) { + /* Advance iterator to next test entry index */ + do { + ret = git_index_iterator_next(&entry, iterator); + + if (ret == GIT_ITEROVER) + cl_fail("iterator did not contain all test entries"); + + cl_git_pass(ret); + } while (iterator_idx++ < test_entries[i].index); + + cl_assert_equal_s(entry->path, test_entries[i].path); + cl_assert_equal_i(entry->mtime.seconds, test_entries[i].mtime); + cl_assert_equal_i(entry->file_size, test_entries[i].file_size); + found++; + } + + while ((ret = git_index_iterator_next(&entry, iterator)) == 0) + ; + + if (ret != GIT_ITEROVER) + cl_git_fail(ret); + + cl_assert_equal_i(found, ARRAY_SIZE(test_entries)); + + git_index_iterator_free(iterator); + git_index_free(index); +#endif +} + +void test_index_tests256__can_modify_while_iterating(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_index *index; + git_index_iterator *iterator; + const git_index_entry *entry; + git_index_entry new_entry = {{0}}; + size_t expected = 0, seen = 0; + int ret; + + cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_index_iterator_new(&iterator, index)); + + expected = git_index_entrycount(index); + cl_assert(git_vector_is_sorted(&iterator->snap)); + + /* + * After we've counted the entries, add a new one and change another; + * ensure that our iterator is backed by a snapshot and thus returns + * the number of entries from when the iterator was created. + */ + cl_git_pass(git_oid__fromstr(&new_entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); + new_entry.path = "newfile"; + new_entry.mode = GIT_FILEMODE_BLOB; + cl_git_pass(git_index_add(index, &new_entry)); + + cl_git_pass(git_oid__fromstr(&new_entry.id, "4141414141414141414141414141414141414141414141414141414141414141", GIT_OID_SHA256)); + new_entry.path = "Makefile"; + new_entry.mode = GIT_FILEMODE_BLOB; + cl_git_pass(git_index_add(index, &new_entry)); + + while (true) { + ret = git_index_iterator_next(&entry, iterator); + + if (ret == GIT_ITEROVER) + break; + + seen++; + } + + cl_assert_equal_i(expected, seen); + + git_index_iterator_free(iterator); + git_index_free(index); +#endif +} diff --git a/tests/libgit2/object/tree/update.c b/tests/libgit2/object/tree/update.c index 1861ac838af..1e82bdcd621 100644 --- a/tests/libgit2/object/tree/update.c +++ b/tests/libgit2/object/tree/update.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "tree.h" +#include "index.h" static git_repository *g_repo; @@ -28,7 +29,7 @@ void test_object_tree_update__remove_blob(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(idx, base_tree)); cl_git_pass(git_index_remove(idx, path, 0)); cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo)); @@ -57,7 +58,7 @@ void test_object_tree_update__remove_blob_deeper(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(idx, base_tree)); cl_git_pass(git_index_remove(idx, path, 0)); cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo)); @@ -88,7 +89,7 @@ void test_object_tree_update__remove_all_entries(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(idx, base_tree)); cl_git_pass(git_index_remove(idx, path1, 0)); cl_git_pass(git_index_remove(idx, path2, 0)); @@ -119,7 +120,7 @@ void test_object_tree_update__replace_blob(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); cl_git_pass(git_index_read_tree(idx, base_tree)); entry.path = path; @@ -171,7 +172,7 @@ void test_object_tree_update__add_blobs(void) int j; /* Create it with an index */ - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); base_tree = NULL; if (i == 1) { @@ -228,7 +229,7 @@ void test_object_tree_update__add_blobs_unsorted(void) int j; /* Create it with an index */ - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); base_tree = NULL; if (i == 1) { diff --git a/tests/libgit2/repo/setters.c b/tests/libgit2/repo/setters.c index 66ec7706c2b..5c91ed39005 100644 --- a/tests/libgit2/repo/setters.c +++ b/tests/libgit2/repo/setters.c @@ -1,6 +1,7 @@ #include "clar_libgit2.h" #include "git2/sys/repository.h" +#include "index.h" #include "odb.h" #include "posix.h" #include "util.h" @@ -70,7 +71,7 @@ void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_o { git_index *new_index; - cl_git_pass(git_index_open(&new_index, "./my-index")); + cl_git_pass(git_index__open(&new_index, "./my-index", GIT_OID_SHA1)); cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_repository_set_index(repo, new_index); diff --git a/tests/libgit2/reset/hard.c b/tests/libgit2/reset/hard.c index 0b6342cb2f8..06a8a049afc 100644 --- a/tests/libgit2/reset/hard.c +++ b/tests/libgit2/reset/hard.c @@ -3,6 +3,7 @@ #include "reset_helpers.h" #include "path.h" #include "futils.h" +#include "index.h" static git_repository *repo; static git_object *target; @@ -252,7 +253,7 @@ void test_reset_hard__switch_file_to_dir(void) git_odb_free(odb); entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); cl_git_pass(git_signature_now(&sig, "foo", "bar")); /* Create the old tree */ diff --git a/tests/libgit2/status/worktree_init.c b/tests/libgit2/status/worktree_init.c index 40f1b2a3140..db6e71f1234 100644 --- a/tests/libgit2/status/worktree_init.c +++ b/tests/libgit2/status/worktree_init.c @@ -7,6 +7,7 @@ #include "posix.h" #include "util.h" #include "path.h" +#include "index.h" static void cleanup_new_repo(void *path) { @@ -65,7 +66,7 @@ void test_status_worktree_init__status_file_without_index_or_workdir(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_set_workdir(repo, "wd", false)); - cl_git_pass(git_index_open(&index, "empty-index")); + cl_git_pass(git_index__open(&index, "empty-index", GIT_OID_SHA1)); cl_assert_equal_i(0, (int)git_index_entrycount(index)); git_repository_set_index(repo, index); @@ -106,7 +107,7 @@ void test_status_worktree_init__status_file_with_clean_index_and_empty_workdir(v cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_set_workdir(repo, "wd", false)); - cl_git_pass(git_index_open(&index, "my-index")); + cl_git_pass(git_index__open(&index, "my-index", GIT_OID_SHA1)); fill_index_wth_head_entries(repo, index); git_repository_set_index(repo, index); @@ -283,7 +284,7 @@ void test_status_worktree_init__disable_pathspec_match(void) { git_repository *repo; git_status_options opts = GIT_STATUS_OPTIONS_INIT; - char *file_with_bracket = "LICENSE[1].md", + char *file_with_bracket = "LICENSE[1].md", *imaginary_file_with_bracket = "LICENSE[1-2].md"; cl_set_cleanup(&cleanup_new_repo, "pathspec"); @@ -291,18 +292,18 @@ void test_status_worktree_init__disable_pathspec_match(void) cl_git_mkfile("pathspec/LICENSE[1].md", "screaming bracket\n"); cl_git_mkfile("pathspec/LICENSE1.md", "no bracket\n"); - opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | + opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH; opts.pathspec.count = 1; opts.pathspec.strings = &file_with_bracket; cl_git_pass( - git_status_foreach_ext(repo, &opts, cb_status__expected_path, + git_status_foreach_ext(repo, &opts, cb_status__expected_path, file_with_bracket) ); /* Test passing a pathspec matching files in the workdir. */ - /* Must not match because pathspecs are disabled. */ + /* Must not match because pathspecs are disabled. */ opts.pathspec.strings = &imaginary_file_with_bracket; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__expected_path, NULL) diff --git a/tests/libgit2/submodule/lookup.c b/tests/libgit2/submodule/lookup.c index acfdc838c26..febb7dfad7d 100644 --- a/tests/libgit2/submodule/lookup.c +++ b/tests/libgit2/submodule/lookup.c @@ -3,6 +3,7 @@ #include "git2/sys/repository.h" #include "repository.h" #include "futils.h" +#include "index.h" static git_repository *g_repo = NULL; @@ -210,7 +211,7 @@ void test_submodule_lookup__lookup_even_with_missing_index(void) git_index *idx; /* give the repo an empty index */ - cl_git_pass(git_index_new(&idx)); + cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); git_repository_set_index(g_repo, idx); git_index_free(idx); diff --git a/tests/resources/git-sha256.index b/tests/resources/git-sha256.index new file mode 100644 index 0000000000000000000000000000000000000000..84b5cabd998bea56e0902dce6eee57d8d4107e7f GIT binary patch literal 458900 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ᢿXIjuVx@Q2{Yr+Fouj#+9F(bkSEFrayj| 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 z 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 BUqb)@ literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/HEAD b/tests/resources/testrepo_256/.gitted/HEAD new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/testrepo_256/.gitted/config b/tests/resources/testrepo_256/.gitted/config new file mode 100644 index 00000000000..ba975e1be69 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/config @@ -0,0 +1,15 @@ +[core] + repositoryformatversion = 1 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = /Users/ethomson/Personal/Projects/libgit2/libgit2/tests/resources/testrepo_256.git + fetch = +refs/heads/*:refs/remotes/origin/* +[extensions] + objectformat = sha256 +[branch "master"] + remote = origin + merge = refs/heads/master diff --git a/tests/resources/testrepo_256/.gitted/description b/tests/resources/testrepo_256/.gitted/description new file mode 100644 index 00000000000..498b267a8c7 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests/resources/testrepo_256/.gitted/index b/tests/resources/testrepo_256/.gitted/index new file mode 100644 index 0000000000000000000000000000000000000000..6b18426ca7e93c9d4bfdd927a9b30a5ef4effccc GIT binary patch literal 361 zcmZ?q402{*U|<4b<`nJQ0mAR>%wRMl1A`#5*o0~ZhQ=if42<7^YCwQ%-J-dNS+DS! z>3)i_zxOtj>2KJ^ruB^5OL#S_R9q(;A7x+*a&>g^b%iKrU;vx<;qPA<4K=q0&0LPX zpV+cA9*Qw9T+bp}_hi-03K8}BPZ>=3HoJvSKYe+hG6R27QDRMG4db zu(_WXIl*YC`L$@~^LQV0YUpTrQuHq8u;E6dXL%p{!+agzZwPJhJ9t;){pPO>?0Ko> zNaltFxq|$l%3!Qu!1ZY%$B!&)|C?(|--f{xF0IO&I{ h0-su>uU?+eE@`ej-^pw4Og_6p(IfoYum8(k5qel`FA literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/info/exclude b/tests/resources/testrepo_256/.gitted/info/exclude new file mode 100644 index 00000000000..a5196d1be8f --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/resources/testrepo_256/.gitted/logs/HEAD b/tests/resources/testrepo_256/.gitted/logs/HEAD new file mode 100644 index 00000000000..35923030200 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000000000000000000000000000 decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f Edward Thomson 1680595792 +0100 clone: from /Users/ethomson/Personal/Projects/libgit2/libgit2/tests/resources/testrepo_256.git diff --git a/tests/resources/testrepo_256/.gitted/logs/refs/heads/master b/tests/resources/testrepo_256/.gitted/logs/refs/heads/master new file mode 100644 index 00000000000..35923030200 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000000000000000000000000000 decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f Edward Thomson 1680595792 +0100 clone: from /Users/ethomson/Personal/Projects/libgit2/libgit2/tests/resources/testrepo_256.git diff --git a/tests/resources/testrepo_256/.gitted/logs/refs/remotes/origin/HEAD b/tests/resources/testrepo_256/.gitted/logs/refs/remotes/origin/HEAD new file mode 100644 index 00000000000..35923030200 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000000000000000000000000000 decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f Edward Thomson 1680595792 +0100 clone: from /Users/ethomson/Personal/Projects/libgit2/libgit2/tests/resources/testrepo_256.git diff --git a/tests/resources/testrepo_256/.gitted/objects/00/404e6179d86039bbc01a925bdc34ccdab778bd1d824f5562aaa319c6c8f045 b/tests/resources/testrepo_256/.gitted/objects/00/404e6179d86039bbc01a925bdc34ccdab778bd1d824f5562aaa319c6c8f045 new file mode 100644 index 0000000000000000000000000000000000000000..8d8d1d8e82826ef293e6194fd62fe58b610a64a9 GIT binary patch literal 267 zcmV+m0rdWO0iBRBP6ROwMXBc$>9zvdiQ_mDLNt_gTp&*D-IdrKG|YL6N#fP{&9f?`+(G`CnaXJ-;gRl4TtnA|jaTt3=n z*F6BD0K$ZVZiHIL+~Lp@3%g0orO)8SWCrd*Y5>rsv~%Ki%}9 zua~EQv7}g#D2Mx550*)%o!$O>zr5OZwD21f4wS62%-3_1h&jb+T9u{~z>%^>08ZHb R5YE?q4eR@e%QrEBc<=pegz5kQ literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/01/18010feb81fe41b9df646d13866742a9070b56fd0ba9ab8dff828fc36c1f78 b/tests/resources/testrepo_256/.gitted/objects/01/18010feb81fe41b9df646d13866742a9070b56fd0ba9ab8dff828fc36c1f78 new file mode 100644 index 00000000000..c7fbd7e9ec8 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/01/18010feb81fe41b9df646d13866742a9070b56fd0ba9ab8dff828fc36c1f78 @@ -0,0 +1 @@ +x[N0 *t8Bq iP~Gg42zo /k^rfKFO%BI"NdwVeb8vb<\LB6k< UtŖ%Y#SC\c<5~7:<Ξ:n3&Wl7S>KktkҦ_ \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/02/df938cfb169b0b6ba0dd16acdd727ea9364f7d48c55afed2f7dd889804065b b/tests/resources/testrepo_256/.gitted/objects/02/df938cfb169b0b6ba0dd16acdd727ea9364f7d48c55afed2f7dd889804065b new file mode 100644 index 0000000000000000000000000000000000000000..cdfafaca76c5125ec895dd2db23dacb7deb81805 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;xb4WH2-^Ff%bx2y%6F@pWY|ej>WVbXmdf7@IP_Uo6IJc=qbL zq|eXzbl+;$b4H&}E1;_Lb5a<#Nl)SGxmmebk0Gq-=z%#(tY)Q;ZmYb?_SQI4`tl&h J1OSNDCE&90Gx`7k literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/05/f7b70a01b0ade8afa5a5fcd19f12cc38faf337d10ec03ef4363d1a86f63750 b/tests/resources/testrepo_256/.gitted/objects/05/f7b70a01b0ade8afa5a5fcd19f12cc38faf337d10ec03ef4363d1a86f63750 new file mode 100644 index 0000000000000000000000000000000000000000..b135eccdafadfd5a8e548e5fd10adbb00a8af34f GIT binary patch literal 21 dcmb003G-2nPTF literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/14/bd335f9d7188c778d44eba8801fe9bda46b66593291f5b9f7cd5f8888af12f b/tests/resources/testrepo_256/.gitted/objects/14/bd335f9d7188c778d44eba8801fe9bda46b66593291f5b9f7cd5f8888af12f new file mode 100644 index 00000000000..58b2d0932a9 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/14/bd335f9d7188c778d44eba8801fe9bda46b66593291f5b9f7cd5f8888af12f @@ -0,0 +1 @@ +x ̱0 Ԟ#B k‘ j}(^rݫi3g _ܜ8H֍N] }P8Yo;o\Ww  \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/17/9496410f66032c03bd2b7e8ddfc9c8c47820fab5615cc04d904989ce800498 b/tests/resources/testrepo_256/.gitted/objects/17/9496410f66032c03bd2b7e8ddfc9c8c47820fab5615cc04d904989ce800498 new file mode 100644 index 0000000000000000000000000000000000000000..97157644b1b473df7cc6a9233900fe07123c0b02 GIT binary patch literal 64 zcmV-G0Kflu0Rc4t%Kvn7Wn~~VH2^U%Fg7$aATcgeZG}mfxK8yPV&{~SjE literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/19/0a1349522cc11f8682e34acca4ce4e1ea8508dfd77c24cefd461b65cead09e b/tests/resources/testrepo_256/.gitted/objects/19/0a1349522cc11f8682e34acca4ce4e1ea8508dfd77c24cefd461b65cead09e new file mode 100644 index 0000000000000000000000000000000000000000..554d191b3aca70ffde00fcf101d4e9a9875cc1a9 GIT binary patch literal 92 zcmV-i0HgnS0V^p=O;s>AV=y!@Ff%bxFfcbvHcT=xOSUjINisGxv@lIgv@|z2F-}S~ yOSAwoOw27AHcoA~_Bf$(bLz>G#hz97>XR;=ZS4NsQ6BTFNcIU^-(CO?b{=3|pCc*& literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/1b/4b74772bd83ff28bf44cda9be93f4afc2279623bb5b36c9194a660b7623c24 b/tests/resources/testrepo_256/.gitted/objects/1b/4b74772bd83ff28bf44cda9be93f4afc2279623bb5b36c9194a660b7623c24 new file mode 100644 index 0000000000000000000000000000000000000000..d5c518ecc8c721f8632f0bb8ea332f8a97a5497e GIT binary patch literal 236 zcmV_=Q@ zvc^JrmF}Qg=!O7r?zLNUX-aCt6-~5{l4I4ZRZTgp^D02}=TX1{#hFVf*erreuEopX zmDsxD7%`+ZBO8p_oyqEor3M02%1i&Am;Fd@zR#InF5UNQdi?U=@O<9-`^SUt+fzcS mxgjgmbPp9^xwW@vX8dQnyvA{kWJkaHC7tY`)A9qv31^C*IC|Ou literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/21/e1e1ebe45b2c1ef79ab050334e36a8015a546f0740bea4505e10d81a946f61 b/tests/resources/testrepo_256/.gitted/objects/21/e1e1ebe45b2c1ef79ab050334e36a8015a546f0740bea4505e10d81a946f61 new file mode 100644 index 0000000000000000000000000000000000000000..31aa9e5f53d3533a3a8776bb36eae93699a46384 GIT binary patch literal 162 zcmV;T0A2rh0Tqlv4uUWc06q5=dp9B5rPwwx#t(Qi-n(?cDg^@7gx`zF9Og1pLJ!*E zVd9sx1xz%j=&kl*sF99h#|?KJ(7T9yA|cJho+8>>J5M5=#mML^N^Ol%Wt#=sDd$vF z+27*PY2?56vcMy?G8VXnr6f3)Fi!8!wa+09)gE0ylhciLbz|X(gs9a0nO4{d@RenQ QHRX8_*msrs0f5OkO$&%m&j0`b literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/23/8a501cf11a036f2f248008d88e14af624bb07fced6390997a0fa6abdad950a b/tests/resources/testrepo_256/.gitted/objects/23/8a501cf11a036f2f248008d88e14af624bb07fced6390997a0fa6abdad950a new file mode 100644 index 0000000000000000000000000000000000000000..66dc15db4869b30415e10f5559c83bd21e1cc737 GIT binary patch literal 143 zcmV;A0C4|!0V^p=O;s>7GGj0_FfcPQQ83XfsVHGMvvq;(iZJ#=1{Vca|LU9;dT|3^ zs-}RH!xjCk)2ws<&o?mu0)=FTDBZA`{}!8tZ_!@aqqM!Vd)0!si&z)QtiQAU!B21Y x-LoO;Qc@W#_e&k>IsC&}d-?fyr?UV5oyGsmvBGyp?4#HG;oCzkG66E(I?6KoNm2j+ literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/26/149bf1ac4612f24b532ae50a12b15f26aace3718749624f008bde68670352a b/tests/resources/testrepo_256/.gitted/objects/26/149bf1ac4612f24b532ae50a12b15f26aace3718749624f008bde68670352a new file mode 100644 index 0000000000000000000000000000000000000000..bee6a42d79b08c80d27f1ff7f4f95189f55eb8fa GIT binary patch literal 202 zcmV;*05$)30d>z&N(3~>FKgs_E z!mZY07>DpMx`cxEQtzPe1=EZwDosY5K@}CF97|2nW9;RP@0Itze E*nhHQlK=n! literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/2d/b6069c27ca4c08b784048644c307e17d0afe29b55f6488398cb59f13feb2f2 b/tests/resources/testrepo_256/.gitted/objects/2d/b6069c27ca4c08b784048644c307e17d0afe29b55f6488398cb59f13feb2f2 new file mode 100644 index 0000000000000000000000000000000000000000..3dfd5463ba9d6f8014964d36504bcb9b30ea3e74 GIT binary patch literal 238 zcmV5HexU|FfcPQQ3!H%bn$g%Fn%Js!*p4}?iiagzF#cHYk2nR zx}?v~_;lZD)^kRmPb*9efIuNJi9xw5K<1+qbH2Vx1ILX%k@ZR58|u$pv*et<;8)h( zwNtsE#wHad<|Svur)B1(>XlTKFibnx&oupUFXNX@x6a;MqB`qUwr1jM4yC<1JoX8i z%nYtjZF#BXVCA{-mnQD!Pj~T~x!O}-`s1Jbv8On1ZSwhS_#jYl%lU(gp~~}fQW&;L oPvPphS-Dt`A*|`>fjLU7W~GmAtGvqg);Lr8@*u|q05@b{udX9}%>V!Z literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/33/e415b835a670bb5c3c760efa0433ac0cbd2d44679f68f2df3a9ae7014cf2a8 b/tests/resources/testrepo_256/.gitted/objects/33/e415b835a670bb5c3c760efa0433ac0cbd2d44679f68f2df3a9ae7014cf2a8 new file mode 100644 index 0000000000000000000000000000000000000000..cedb2a22e6914c3bbbed90bbedf8fd2095bf5a7d GIT binary patch literal 19 acmb-^#&K@VmFECanOevRMB$i#Rc`n6$Pz)g@z MiOzronCJc{NQdPt6aWAK literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/3b/58565ee067f13349cd4f89aa396d10f71c69e168d5c48ea23de59734ec3ab1 b/tests/resources/testrepo_256/.gitted/objects/3b/58565ee067f13349cd4f89aa396d10f71c69e168d5c48ea23de59734ec3ab1 new file mode 100644 index 0000000000000000000000000000000000000000..1b299dc257b712a486bb7ec5bd07720d88001374 GIT binary patch literal 38 ucmbxW_q!r`tZ֬t=?~V1fT \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/47/3a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 b/tests/resources/testrepo_256/.gitted/objects/47/3a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 new file mode 100644 index 0000000000000000000000000000000000000000..711223894375fe1186ac5bfffdc48fb1fa1e65cc GIT binary patch literal 15 WcmbBQQQ6W+Sv9;eTEK4oHX{LN+y0Ic;3tpET3 literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/4d/f8ed86acaac5dc82b5652170996ce459d39e3a441e9759b635b0bc4ecc43fd b/tests/resources/testrepo_256/.gitted/objects/4d/f8ed86acaac5dc82b5652170996ce459d39e3a441e9759b635b0bc4ecc43fd new file mode 100644 index 0000000000000000000000000000000000000000..8dc1932822c30e3289f0b6a74ce1d27f99fbca04 GIT binary patch literal 57 zcmV-90LK4#0V^p=O;s>4WH2!R0tHJm21zbq&mf(H@@-9zz0NE-=O?!!p!aY2A)ohG P61T;?x-bs_fTI)&EzuSA literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/5a/2d5699fea33657b42ba98c22b7898baaa0eda205a21cafdcb7e0f94b07bb9b b/tests/resources/testrepo_256/.gitted/objects/5a/2d5699fea33657b42ba98c22b7898baaa0eda205a21cafdcb7e0f94b07bb9b new file mode 100644 index 0000000000000000000000000000000000000000..dd993131694c0525737a02638048b52c66a7e051 GIT binary patch literal 64 zcmV-G0Kflu0Rc4t%Kvn7Wn~~VH2^U%Fg7$aATus>cys_Z>cT|@)WkqoWX$sO4SBB@ WgLD>cuFmhj5#sPz(+yzy7#1e#x*6;M literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848 b/tests/resources/testrepo_256/.gitted/objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848 new file mode 100644 index 00000000000..39e27c06a34 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848 @@ -0,0 +1 @@ +x1N1ERKPqx]#Sp'/}.ơj\1KRP8RDImP!D>p[ˡ0ൕD hSf !@-yZ S>\nS ]ɐClT[#GM|->~Sj־n^uGz?_zۛ.y,b0S ˤ/zQvYvɷ죛~/(jrS \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/5d/bb1fff5c0094b31b25b4635ab9fbee66d65fe5dda47dd0ac5f01dd69a84c6f b/tests/resources/testrepo_256/.gitted/objects/5d/bb1fff5c0094b31b25b4635ab9fbee66d65fe5dda47dd0ac5f01dd69a84c6f new file mode 100644 index 00000000000..17fae64f464 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/5d/bb1fff5c0094b31b25b4635ab9fbee66d65fe5dda47dd0ac5f01dd69a84c6f @@ -0,0 +1,3 @@ +xuKj1DS !'H.Og3 +96rݶ2> +d=-b5싓dŕĄP(De{+6;>4KĆrLf ,o} >rޖ/N-\W<[`1hǣ =KݮZN/{"?7bW \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/61/489e9e831f1d9001084d39b79f964c293db8620d679ea3596673c8a326446e b/tests/resources/testrepo_256/.gitted/objects/61/489e9e831f1d9001084d39b79f964c293db8620d679ea3596673c8a326446e new file mode 100644 index 0000000000000000000000000000000000000000..0bece845b96b3be7ca7f12ebd967e1764ce64fa8 GIT binary patch literal 157 zcmV;O0Al}m0V^p=O;s>7v0yMXFfcPQQ3!H%bn$g%Shr~IVb&{rX1bqZ?C-q|W%?Vo zv1vWy_7YyrDizns#zlZq1ak~8AdGILV(N-9birXB2On*O+#@yn)LXYVaho%JeP zGx0Tt(q0`N`vgs923M%Iywq~Aa_@sq4IM2{ir(cMHr#0REbn7~n6Kme4WSKw2k&aU L-~1H-4}m~Ae2hy! literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/6d/5fd291bb0f67444e99ab492f1bf1fcdf5dca09dab24cf331e05111b4cfc1a3 b/tests/resources/testrepo_256/.gitted/objects/6d/5fd291bb0f67444e99ab492f1bf1fcdf5dca09dab24cf331e05111b4cfc1a3 new file mode 100644 index 0000000000000000000000000000000000000000..112998d425717bb922ce74e8f6f0f831d8dc4510 GIT binary patch literal 24 gcmbBwx}Rd~@4XFW`Wv>f zX+7ii5?;+J71zneN1>|oQp@#9DoPl<4>~n;v^*(#mvh)~qtUaxkNsi3j_)^wHuxR9 NtMPvGR{&K(Dn}t?GcEuC literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/73/8ff86401dbc5af692c83e660a4d510603c3f36e782a1a32ebd0388db6411ed b/tests/resources/testrepo_256/.gitted/objects/73/8ff86401dbc5af692c83e660a4d510603c3f36e782a1a32ebd0388db6411ed new file mode 100644 index 0000000000000000000000000000000000000000..4c973ea83afb1efa8040be2204a65922df718df6 GIT binary patch literal 181 zcmV;m080OO0iBOAP6ROwMX7U&^hn5d;v|+3+6z!|g4l61Be4t`viIMGBhY-k;=SVA zalP&>8mP{?jXCQ!Je}|U;BMlVp*fLKANE=x! literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/73/b4f3c4f3182e6c8dd2c98aeb2c7811556538e7673e4b325307c71685fbf5b6 b/tests/resources/testrepo_256/.gitted/objects/73/b4f3c4f3182e6c8dd2c98aeb2c7811556538e7673e4b325307c71685fbf5b6 new file mode 100644 index 0000000000000000000000000000000000000000..67b84c462af40737559130399874eeb4b77a3873 GIT binary patch literal 108 zcmV-y0F(cC0V^p=O;xZoW-v4`Ff%bx2y%6F@pWZbw`lHR)+>Bwx}Rd~@4XFW`Wv>f zX+7ii5?;+J71zneN1>|oQp@#9DoPk~<1bCz&7bb#H*>Y8zVydG_hV0S-rD5z+3-Q2 O;Fj|T7Xtu2R4DnfG&Y$4 literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/7e/4633ae1b0e83503dbea4417f9d5ccaf22b877c5a4522b6d1d2b16090ee2f6f b/tests/resources/testrepo_256/.gitted/objects/7e/4633ae1b0e83503dbea4417f9d5ccaf22b877c5a4522b6d1d2b16090ee2f6f new file mode 100644 index 0000000000000000000000000000000000000000..993a62b1637039118d63bec43013bdb924745aa8 GIT binary patch literal 141 zcmV;80CN9$0iBLp3c@fD0R7G>asg$xn`|nG2p+)`sd4(!0hkIsFwuiRDb vbB?*M_O|CAJf;?x_a*msw>ShM1{&F(Apn@e9w#dQv_@suWu43yI6^)tb_75M literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/7e/9424c06052ca33bfc599bccadee60065d8664a9af7648a1455100c4f772e1c b/tests/resources/testrepo_256/.gitted/objects/7e/9424c06052ca33bfc599bccadee60065d8664a9af7648a1455100c4f772e1c new file mode 100644 index 00000000000..70bf64e16bf --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/7e/9424c06052ca33bfc599bccadee60065d8664a9af7648a1455100c4f772e1c @@ -0,0 +1,2 @@ +xAj1 -i,B(](ti2 =~]znxe_ץf]b$a9)yI '2iYTU[fWVa5su,Q +:POCp*)?~'x]6x˹\^žz٩WVbXmdf7@IP_Uo6IJc=qbL zq|eXzbl+;$b4H&}E1;_LQp@#9DoPk~<1bCz&7bb#H*>Y8zVydG_hV0S-rD5z+3-Q2 O;Fj|T7Xtt@NhwLRz&0BI literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/90/1505c3355518bee35475c5d3f23bac1dded688b2bd314cc32b7f157e100724 b/tests/resources/testrepo_256/.gitted/objects/90/1505c3355518bee35475c5d3f23bac1dded688b2bd314cc32b7f157e100724 new file mode 100644 index 00000000000..09d0abfa7b4 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/90/1505c3355518bee35475c5d3f23bac1dded688b2bd314cc32b7f157e100724 @@ -0,0 +1 @@ +xQJ1 })zM<'HZ7mf`t}yN3?R6BYwJeHR(LḾӎA#8z āPԵ5d(:XH2t_7yۗ]O:grrBp{=Zk ?s?TU \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/93/1093620e5f050e2127fb0b96786ebaa9ee6535fb698ec01b5f7a800fa27cbe b/tests/resources/testrepo_256/.gitted/objects/93/1093620e5f050e2127fb0b96786ebaa9ee6535fb698ec01b5f7a800fa27cbe new file mode 100644 index 0000000000000000000000000000000000000000..70431af8128d71fe97407bd3333bfd6953435891 GIT binary patch literal 137 zcmV;40CxX)0iBLb3c@fDMqTF=vlk?jO#VQ`3%K$GnaPv}EQOlh-|7+Ee7wbb@X5L? zeE{Zs8k;Iaov<*Wb3uZSWkNwqjY7*U2c2qR8xjZ4NK9O~_|jUUrgHcWP2I=5Zt&ks34~NnJYDK-@s& literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/94/ed253efa9e86fc636805c294c441d08b89b455903c0c14e9b16587fec081f5 b/tests/resources/testrepo_256/.gitted/objects/94/ed253efa9e86fc636805c294c441d08b89b455903c0c14e9b16587fec081f5 new file mode 100644 index 0000000000000000000000000000000000000000..41bcd18afbb47ff313b90874fa27decf3a34b5cb GIT binary patch literal 188 zcmV;t07L(H0iBQ0O$0FvMETw-(g4VD5<8I)x*s~A0Vj6Ylh_Mda=P{jE%5i|Nu$xU zaU9p_knw4rW)4t$3Ay#^sZ^*`1ynsrQ)Oh65-4`om|IHHO>qUyxnzhysczqL+HE?v zNFj*%3YJ5Hpw%Qs&%J1BO*&%D%q>Yw3rW4=nuG#o*r{)FpZhr7yFTPp_py)TXWZPY qE&E58&+FXp^`(vD&3WX2M8%VP1_s!cU9YD7x4(@q-F^W(?^Up9reI0hYPWM?<@LE8o(K`PkZiyW2X8cRHOfV>{BnkIcb` X82t2c`iq#_jy^W?S6Y4mjhI&pAZBds literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/9d/aab17c25f647d652c72c8cc3cf4602c270a369beebc7d0b67238897bbc426b b/tests/resources/testrepo_256/.gitted/objects/9d/aab17c25f647d652c72c8cc3cf4602c270a369beebc7d0b67238897bbc426b new file mode 100644 index 00000000000..74b8385edc1 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/9d/aab17c25f647d652c72c8cc3cf4602c270a369beebc7d0b67238897bbc426b @@ -0,0 +1 @@ +x+)JMU0d040031Qrutue0~"tY2_,kx꺤tjsFO+L @!1A+@sJǍ>I]䜾W޵S&%%għeT0L;4q/M[:Ufk:< Pmy`&OwS_8oml PpTO \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/a4/813ef6708e6011e8187224297e83e4a285f58bf5eabb1db270351388603c95 b/tests/resources/testrepo_256/.gitted/objects/a4/813ef6708e6011e8187224297e83e4a285f58bf5eabb1db270351388603c95 new file mode 100644 index 0000000000000000000000000000000000000000..2419974cbc27d6c1afe3e38ab5a7b41ee67782a9 GIT binary patch literal 244 zcmVj1=F9WRbosttAR+ya|(cx z7H!qI3QFrHv9V~+$!AGYqzQRbni&u${T|DHgb&-t2yctpzJ=$z{f5`;s<+Q4+t-&6 uv7{OkAcaRL0Mkj&XNLc$JH7jH_0SI8YzdcD@2BSyZrj*Th|>?YL2LiRRDL}G literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/ab/ee32b3339d1566d75613ea61f40c14bdfc5b101b60fde4f44b58dd06667640 b/tests/resources/testrepo_256/.gitted/objects/ab/ee32b3339d1566d75613ea61f40c14bdfc5b101b60fde4f44b58dd06667640 new file mode 100644 index 0000000000000000000000000000000000000000..b390250e308a62f1afc44c5f8e99e8196c1949ae GIT binary patch literal 63 zcmV-F0Korv0V^p=O;s>4V=y!@Ff%bx2y%6F@pWY|ej>WVbXmdf7@IP_Uo6IJc=qbL Vq|eXzbl+;$b4H&}D*(}y6gC9)8?68U literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/ae/a29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5 b/tests/resources/testrepo_256/.gitted/objects/ae/a29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5 new file mode 100644 index 0000000000000000000000000000000000000000..18a7f61c29ea8c5c9a48e3b30bead7f058d06293 GIT binary patch literal 26 icmb4W(dj1ELH%b#5{%koD_wmqQt!93`H&goVE$TEmshD literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/b8/3624f6ac0995273c0034a7ab8c68929bdc91b69ad54ef94979b93eba3f6022 b/tests/resources/testrepo_256/.gitted/objects/b8/3624f6ac0995273c0034a7ab8c68929bdc91b69ad54ef94979b93eba3f6022 new file mode 100644 index 0000000000000000000000000000000000000000..3e36331ea660f96ddc6389c51c0b5b04bae31f94 GIT binary patch literal 190 zcmV;v073tF0iBOqN(3j0%EkJD$BPXewzWa z!-|SjiYX>T;Sx)U;<=r*<^V|U%o(URa?V)6q-3Ma8tbC>xs4-y*qAfCZ))QfUVrR& sTt0Wbe!bY(-$G1+k|I$F&maKHNzX^q|Klzi`nVr+3xAd60TLfo5g`3pC;$Ke literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/bd/f2066a28e11603a1af04157ee4aad97814279fe500340eb3465797cbd3be23 b/tests/resources/testrepo_256/.gitted/objects/bd/f2066a28e11603a1af04157ee4aad97814279fe500340eb3465797cbd3be23 new file mode 100644 index 0000000000000000000000000000000000000000..9bb5b623bdbc11a70db482867b5b26d0d7b3215c GIT binary patch literal 23 fcmb4WH2!R0tE{b2HziV+t#c)dZ%e?s$#*+oF|c&=UKVPO^@7W Px?zvs8Rx$M(km5$Qz#fi literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/bf/cc4074ac517ed24d61b0aaa96359f304c3dc97e95f336269ed474ea846ada5 b/tests/resources/testrepo_256/.gitted/objects/bf/cc4074ac517ed24d61b0aaa96359f304c3dc97e95f336269ed474ea846ada5 new file mode 100644 index 0000000000000000000000000000000000000000..be8b99bba80435c6152a727a07b56daeefda6569 GIT binary patch literal 198 zcmV;%06G770V^p=O;s?ouw*baFfcPQQ3!H%bn$g%Fn%Js!*p4}?iiagzF#cHYk2nR zx}?v~_;lZD)^kRmPb*9efIuNJi9xw5K<1+qbH2Vx1ILX%k@ZR58|u$pv*et<;8)h( zwNtsE#wHad<|Svur)B1(>XlTKFibnx&oupUFXNX@x6a;MqB`qUwr1jM4yC<1JoX8i z%nYtjZF#BXVCB{kVQ~-AKN@?U_3vC|nJe&JCi7v&)gyh2Y@bdyd1JK^0G=>TfAl9| Ae*gdg literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/c2/58f010a08328a29cde33411d955520e0375fcbbcc14b7636a70f7536c32ef6 b/tests/resources/testrepo_256/.gitted/objects/c2/58f010a08328a29cde33411d955520e0375fcbbcc14b7636a70f7536c32ef6 new file mode 100644 index 00000000000..9d2ceb1fff9 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/objects/c2/58f010a08328a29cde33411d955520e0375fcbbcc14b7636a70f7536c32ef6 @@ -0,0 +1,2 @@ +x0D=+nbvK[Jb?x֥փ/I^ P1=%+X5IO6u =V*pD]hvG/H,o r1@eLp +0s>?H!"s}t3,ͳIm3 \ No newline at end of file diff --git a/tests/resources/testrepo_256/.gitted/objects/ca/31f7336e882a233a2943787c5e94ba024ac9a4f763cb1d9bfd8e63aa7f7269 b/tests/resources/testrepo_256/.gitted/objects/ca/31f7336e882a233a2943787c5e94ba024ac9a4f763cb1d9bfd8e63aa7f7269 new file mode 100644 index 0000000000000000000000000000000000000000..cfcdac3069711e3c0e4779477c932e2e4dea8d59 GIT binary patch literal 182 zcmV;n07?IN0iBOAP6ROwMX7U&^hn5#9Vd|x+6z!|f;e_GBe4t`viIMGBhY-k;=SUJ z<9gj!Oaf2qbdTZ_n=+=9MLKjX*PZtCZX kuRjmE{LagMyhS9gML1QC&yWDZ_&c=xA8DX)2hjgc&6D$5qyPW_ literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/cb/282e7c15fd8aeb2265cd621f5a228cb33dc84192980ca426cf9ab2a48cb9f0 b/tests/resources/testrepo_256/.gitted/objects/cb/282e7c15fd8aeb2265cd621f5a228cb33dc84192980ca426cf9ab2a48cb9f0 new file mode 100644 index 0000000000000000000000000000000000000000..77d9ec27d546841923f4d7688b1675af7e8e4d09 GIT binary patch literal 187 zcmV;s07U014!Q&1J`S7%pUi!~ zFHa>stW(ujOsS>X`(UW5qgJUb4eF2>VWG)N3h{_=-}`0|#}?&_IpZ=o@DON9;t+k5QzLE6aaV8>(SExxQ>sxwoCnsxF4}jRtl?nS=|5t literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/cc/b5a03da85607c230d111abfa899655d1b00e6529101a40d42f6acb059dff9f b/tests/resources/testrepo_256/.gitted/objects/cc/b5a03da85607c230d111abfa899655d1b00e6529101a40d42f6acb059dff9f new file mode 100644 index 0000000000000000000000000000000000000000..a67d6e647ccc1f3faad53aa928441dcf66808c42 GIT binary patch literal 21 dcmbtwae_U^_9p60<==wtq&H!0qWh{lmAp z@3$2T<)?Lw5xq!G%^L|QdS~f%8-3dbn}R9Q0Bmk&<*ou<3B4LSp*E>N;aiSzUok6c z#afH@2JWS)BU%^M!Qd!vrBtQ@s+$5CXGS4PT2E&MgFM!C9`VEGTJilVHt+HE$Nu2* jxy$YA#peDNGvvYuR46{Dno>CJ`Dl&*Y(w}3o8?f{IrmoS literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/eb/ead5965196dfaeab52b1a5d92b78e54493fdaa78f72268d4cc69b61d5feee1 b/tests/resources/testrepo_256/.gitted/objects/eb/ead5965196dfaeab52b1a5d92b78e54493fdaa78f72268d4cc69b61d5feee1 new file mode 100644 index 0000000000000000000000000000000000000000..225c45734e0bc525ec231bcba0d6ffd2e335a5d0 GIT binary patch literal 21 dcmb7v0yMXFfcPQQ3!H%bn$g%Shr~IVb&{rX1bqZ?C-q|W%?Vo zv1vWy_7YyrDizns#zlZq1ak~8AdGILV(N-9bi_I_f^(s(Gwyl_2>Xx)=lH!DQc z=RajI;oIyMKK=CNeacX6d8y@K<=zLK8ai5@6urwiY`D?rS>DI~Fki>_8$uiW4&K#x LzxgWw+t)xa*56Lu literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/f2/c8da1a7c2eb49ff25c47441f0b3f387faeddde1b37d0ad2f3f6a63f5327978 b/tests/resources/testrepo_256/.gitted/objects/f2/c8da1a7c2eb49ff25c47441f0b3f387faeddde1b37d0ad2f3f6a63f5327978 new file mode 100644 index 0000000000000000000000000000000000000000..04bf5eb0621c5e6a453ac232bf04198f7a6a04ce GIT binary patch literal 192 zcmV;x06+hD0iBP*ZNo4O0Q>e7TA&4KQIrG}ML*e~3s52%=V3c=6=eOmEA)3b;2zia zb-j%+=lV7dv(UVEf=tpAX49FJv4MzGj;VSC>QQ^mR+GobGgni}WKxJlB~5oZY#RX( z3m~|)f^LMZsxz@-EX7v0yMXFfcPQQ3!H%bn$g%Fn%Js!*p4}?iiagzF#cHYk2nR zx}?v~_;lZD)^kRmPb;9RlZq1ak~8AdGILV(N-9birXB2On*O+#@yn)LXYVaho%JeP zGx0Tt(q0`N`vgs923M%Iywq~A^4$1K6L<5cyZFsq?Wr&Q@z4F(Q=GRp`Fu8f5Gc6i L{K3Tl{;EGa8DLRL literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/pack/pack-b87f1f214098b19ce092afb9ef6e7643653c03e7f91faa27b767e3eb8225f0f6.idx b/tests/resources/testrepo_256/.gitted/objects/pack/pack-b87f1f214098b19ce092afb9ef6e7643653c03e7f91faa27b767e3eb8225f0f6.idx new file mode 100644 index 0000000000000000000000000000000000000000..897e8a478fcd5da84a4faf07f1d47e873809c40c GIT binary patch literal 1336 zcmexg;-AdGz`z8=LlH0n9gPix{4*FaGtgb6ViusDfyAsp`$sY9VZa6qw;_XdTSbe? zt)5tGZM8A@8Pr~PYgJ!anh zD`si9^@YFJi=Vu@&DZ9b?P0GIaKf^6-s!gAVT%eEF>R}PI?XA-h^~1Nyk|gsYf%8$~m*)2`Jr>GVb$z9txX6d+H=mR&5mLJN9RQC) BmmmND literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/pack/pack-b87f1f214098b19ce092afb9ef6e7643653c03e7f91faa27b767e3eb8225f0f6.pack b/tests/resources/testrepo_256/.gitted/objects/pack/pack-b87f1f214098b19ce092afb9ef6e7643653c03e7f91faa27b767e3eb8225f0f6.pack new file mode 100644 index 0000000000000000000000000000000000000000..9c8557886c820187eb37b4d68a70c42aeaccc895 GIT binary patch literal 569 zcmV-90>=GNK|@Ob00062000J-5qO-Pj$uj!F$_lk&nbEVB~6od3bF`$1W%Bpsk`WG zWwzq=9rXtO`*`pk-`w2;wv{6nEG3CkQdEV?l)4M`l%YmOG|C22jVfvL#-^!3PkD}hK!yfe5D3>oHH~qFf%bxNX*MG$w)2I zE2$`9h_qJIzJA~cZ{jp9v!5?#m@w_{_Kt{3a$Qm_CS@pT!EOlAQkp9Tt4u9XNX*MG$w)0y zNXyJgZmc$_QGNGwrE%gjl&=K=s2`2)UmErk_wcRJ)dE3lPA{-pC@ky0#1 zz^TNPz3p7H(DMS}c$`Z$o?r|B1B3xwxPKoZK$x+d;F7Po?{0QOWjq7t`5&q$w`b$) Hf+g_whLjGt literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/pack/pack-e2f07f30db7e480ea84a0e64ee791b9b270067124b2609019b74f33f256f33fa.idx b/tests/resources/testrepo_256/.gitted/objects/pack/pack-e2f07f30db7e480ea84a0e64ee791b9b270067124b2609019b74f33f256f33fa.idx new file mode 100644 index 0000000000000000000000000000000000000000..9e2ec99c546e6de5f8279f1abfc0f254565d625b GIT binary patch literal 66216 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%0D&XxF~7)M z*H%hjf}fLy z<~-~i14x(Ml`z z5(tr80vA%km--8R2?2(dEfz&NU%{Ch{)P`h0U6@HT_l?8-DwJ4^mG>6Geowo3u5FQ zv=nr(px99=UQJi0pEI?y(|%-Hen~AnwTYP8j^(aIaQACj+6NSwFwsA*3iKNuwSK2V z4g`K_{r*h%(iZUs({(wX^vAj|q77lr#mcY(s?2DS3UbWaw+G)m6HU3F+tb5vuzY-b zpmANv3ATw3dNqwEqn`11)l{tUCn0N&?X}Mg(+Tw0njNU?R+-1#vx%xC$7a1Ws|{3Y z>pXVt$s3J6j7mK;k**z*i+s`?wEc-T-I90Y+NP!{lnrC*FLtf#5d|`8+9VvANu`@n z_G+8kKTom+aVI~O0{8p?E3}V|fQ>GfUIP4@f5lAG=+cH+z^6>#89ymCNwmWz#hpoF z$88GBgbVl0e)i91y7cpn6^&UM2tk_JB!**7wQ{WvEGg2WJ>g)|0NwU|^NW z1ar-PorQ_+>lZ&Mc=ni0x4u|}o#RPhr~FL1uT9lf7*SE1U>kc=Pa)FKoB+MHc1!Kxj8r! zPHMLaGwlrP>lJ%Xz0?Wd%%>X(35C}K7RYc{TK_o9Nf{T1P(PSU46urD*hC)+PdT5p z5zVkmGFnm)=S*PftUC_R{`lBKAmQMLc|i`fj)tM1O1{n8TBIQ}_L9IuM?(iaVG)7B z-eZc!_Iug5hf0bKj08T!;Y8#Y3*x^GM8eaU(uMOwO=B$Z8ePy(oG%Qcc8DhDr^x=Y zsdxLCLOgjh z@3CCkY8i-nf)4)Xwb$G=591PHKA%O{&2`m#MD^*`?JsDm(}0Q-aq$MFz4g0X{hp~c zjSWeFuAv1c3h@E5%hCwK7RftnvY_4GEcFWm{hIM#`!{_^pj8w z$icGW1X1JgCLeaGLwZ5%-ez^Gr4uWDf zg?=s+)A6u5^oObIL^(;%Hbc13kUaorC?l*t_lOCabgo|l=4>m@nIK!<%%}5~Z0ys(5m+zqmWmNl@)>smm2@X&=4g0^4W2p7{qFe z9_9pf%>fq9I9WA=>eF-h4|BxFUj)%Yy~u)W@a-$9qViDeZxu0GDe%gwe-Cc2yMgV` zf&*$T8abr@_4R(ap&uxrK)&HEHDfp7eEMptlvf?8+np{T94f|TD8K~{eF^cG#heN@vVGy?3 znH}dvLb~{)rndOQ32=iWQl;(XbuAsuc+r(`#m%-AGn$2p<4RcM4zj{o`-7YCSD1jK zeP+XO{c~r*0zo1hg4{fXXu2Y{kU-w@B8(Ted+M9sLRnS4!h;Z)6xWP{tiEF>Vyv0{ zIq+Cz9^sMc9PDt=g+5Q2_iSa9X9zNL{XkvdB7oyrq#$#X5TWhYD8Y~1bfP}WzC-4m z6k6lT@ZTa&((p3#VbkQIzchZf?0CYXm+XT8UvM2KGMQnC8(zb)Pg;f=HueYZoy}s- z6B-bsa8_*UlW(S6P!6V_{#X)cZ@L5Cdi~_zL8QFecygJ(K~0dgUt;WwYNvAYqhEb?Of*);WR)8-wv(M+mSd9icT2@r=bI+lLu>(h3;BFyd#Vo_JfeL>18&M7iBT+Gi zw(@7Jn^K^)+lW+qzd=@nBY~@Xdhl%wa-zDB#pMM?6G2nL3i@~-H=D_$BXf4b1$V{FnU#ubGJn*^}aZ%6VpLnGv&5U zu!pC_tqp<*Db>t=r=ik(&#cWPedV@P<$MXy`jk4eI2rmlcbZq ztKGz$HN(1xiQ6}g7HP5Iy{x>AGdUXSzy~4a{B)5~gu8wvt1hez{Mj^SUu**PEh|(o z>?n7c_`-26Y=f=)YM33G?M=8mjAn-hphk1k6y&U>#r(t!Z><)t7U3Kuy{%|@59NtU zXwp7^2j-KJQ-p*5RF;5zY}oivy`!a9nR8M~gKbDC{sc8eGtaQnb+1}~`D=3mB`|+a z35yCAE;*@sptx3w7JT5-wH2HXJ1aHKOz5$h8P~xJ7FHvihn_6TK{)vl+j5LBoh;&*hm15GwLab&vg04xUNg>|_hi)-eeOdj z8yL^OVYnY0A$85EoxP7g1p^wh&~M>%<)EXsBn=vTypV$(##d8oNYVsgfFrsHccwwk z-Z=aoS%{OJh=WWBAoByVaipvs5Rrlrhv7d}q5kX(pch@M)vzd3l(ip#y3?=T3Or7^ zE`k0lgY-;`t3Xel(wj<@8f2#97>k+vDMp$w^&^wx9|f?s2XLn$Dp>_)$M6e$4s43A zsK{=he>uNQjOqB)jQ<+-$Js!&S_a@{T$^20Z0_#q1H3z$K_;8!zk4MeyU2thQ0qUu z1tz4+?Y6lDsp_x>4$Yw8SpAN}iDjv?K6CZB%PI##zX5)PLb2-;n_e$11YzxJeq?97 zrS*>;dxNVTHCth;d7~qG_bN&>NpE7s0$8<0O+U5K986=lrb6bQU|MNDBO-)rH^rOlXjw`JGdL{6gE1NLkE|s=D)`5e+N-=2RuUI7s}faV4-zK%P*Hq zIxyQ;yy5cM2!8WwP3P2i_PRUqczX4Ec2dIg#-E~w;j199@jWiVX0w)ScYNrw zNmYgIZkikE%95dVhZbkco|qDQ{RPf3TO_O4EpA(`#zqV@KT>p)mUMze`+iSjH<2d+ zY&8+oG@&$mgQYl`Hfxz4?Ib#U*O74e^-MLoM*@aWdSK*`YD#BtkO^*gVHju?ciW?N$A3*;RirdYrFPEl!E#xCeC+q3e z4KDb*<}DT5z`Xzh`du_Hf-kSx#9fFl3D8k)B>CY(=?`a-y}N6}!7|Dee zeF&W<+~G zi_VM^`u2gjNO+nwrUwj*M(H>R7Wq>HGB381?r0Rh7QZT;;6G~<02U09&7K4B)L(CA z0_T=BTngTB8yY-{5*PjXBT+~w%Yvm}PNv^|B-rnMY7Kvo>%NfC#rZKrIi%dSTlh+g z5_h=dOKn2-Aa7zgc8N=P0vq*+HTCdPuQF1r$U6UW7jB$$>Rr1~kUq(gTM{o3 zMqt?2XyXWlWASpjH>c(WsdS;aHub-0A$~gMdw2^5dPc73K?R!~4Mh-=1#|U7%KfOJ z{c19=lD!zax|r$Wms{JPAkwXP?bwjTMQy`}1nMyIKPBK&L>*L!=JU`dqY|cqqmR%Q zvsv>Jq}kGQUgj-Pz0D&{7qE(ftu`<4*l}57a`qe&zWSM{ISIVxw9DaNgy7pudM(C+ z^N`gknW(1M^~}@iDuwR$+qDt%C_!_ay&g-|#_HPZO@Egek7l_#tv_D3q4q3wN`{CjRXD`}&-%zu*ikDS%_&F7Pjd z0ScK()*>s2nCq%i zOcGBnl`Q#K55$m(&Zn>q93!tk6s3@NE|sDMnRAx`VfLvir=VAd(u8qO>gCHW-D;80 zfrL<;fl|$ufP4@e)+Wr=H9n2 zt<5^boW_j56}J1n@1|!6BCo6?q>y~`6DMfD$%HcO?iabq0|8r>D57YKVgeUOqWtGV z{MLe)E*?s9^rp4erpThzty2*AakZ~y7#eYZlpQm~zYw(}M%pls!h53Ena+FZaKwP% zm`2G4YAbSaxHk}fSQewg#qNOq$RU=4+w49D#mm1wuf>08fM`|8ys;L&bLy8B_Up)# zsihHL&`Zh1>P=@)_Z{;|tQeM$L+ZuBYp0rgGHCW3-GysI!h8qUVsybyCp(91cP8eim5jHj;&+iHCjc23I$UWe=VoNggIA=&ryR;AK<>f z*mf_a7ENOuNO9Bpiv5_P@ge5}ZVOP?b8hFOdQf(Y81#*~+0pI!I+y;3ojg-(nXL8= zs)}^tA=~#;?kBp-qHLn%_C7@?%1pUehoLH?xTQp2j`_El!k8L=s&+Ren-2XEgqz&0 z>hsmxg;!1_FQcPE+NPea+(PjL*R*|HOViYKoh_`S+(pgQcAdtCR`bN19d3onZR98jgL@Z(a(bhR`WUPQX@-}W#i6d;QtgGBwGt+maAYu9U z9=Drc;BJ+a1F=ISR!{Wl`{>X*f^Qq zi#s?WRGbJBRBd&A(Jmu9*$5KYAd}8Nk+Kd*cPx&8yE$)nBSbGZE{zahL2!T1W|HpX z7!owAI!APa3&nUSAP6pMp=!WlaN{+UmlLI3)60J8>LDXztss$L*L%-;zxAkWAmNCB zA{;!~(uP>3f`*j=G#b18P{H9(&rudeA_CnsaPNycXlFMXOsJLD2(@~Ik)(vWG%dt5 zFi)%l-COhDd_?Nb#6-EZ9MC7dV7quTC?5mSxh%;p)I0RVr?%nRa^!2h=(7)V855*L zRr{s>IhP`@HRouggyO_XfQJ~0UDxKn$z;@S;-JL3QK$z1UN>t-hAT#{QbQOvQMKqB z{Va7c;JQPp1*#)5OO~+7Ce~tY&3amq^y>l3XziMj+O+B>=MTNl-!x#E7lgzeMjls9 zx(PmqgDIf6Sua$gBs#w6sWVTUPuKr;z%S)GH*Y3QQVk8nHbP_d4GxApXNz3Q1QKCCOe@3-(K5N_9$nC2qHPz8sLwGa}i;*v8K8 zu^6(Cmu~^e?ssgWEFOl|Fe1Xd#z z|Fmp|pv3W5lIpA1IOSNm$D`e=%lW(qX9|#Pr&UALjH9(eVv1dhffQENZFZY#dmN05 zFthW-7eo$Is5Puemd)L|_c*KS0uP)DIU$fJq#&-@j)g) zE^5F_<@(i~ZuEAmb!vH>bi)KMZy1Wq%N?Y4QDrjDpic^kJBv9kM?HALO#-9KHfB$0j%BxpzwjvqHInGuCl73^Ewff+&$`)3Y$+rHAtG| z0-v|g0l_de3Bs36=&rl$)%c+$6$-0mGK>o6`9w0q&0>}HiQUawZob;=9l{aGl@OV# z19AEL1qTbboEH5ra~dqkU2d+*4_*peu;a4E#pu!KL3=f#^dgnq>76ajGSx3Q=
    zYre|V-p@&@;qvFHgGKMp1_$@J6;CA@#)K!2y(Qg3s@5ms^7gi&nQ8DDPl2D0P_*k!J|7fMEDz zh4s_+JpWG#U|*kk{m7gAFb1d|f84 zjs%D0QHD!gN_tu|H+mfIGl(oV<$`E6>?Pbtax zgQ2Sl@IA?v2UqGGn%662&`SoM)TCEVTfIa&G z{K4k3%$q&$u#7ZDIL; zR5nW2L^uN_xgl`oK?BP})^Cx2UI~3mb>jHr-64%y)?5F?Tfs{ti9d$_;)tr)Vv&1! z;!CLdswe@=uE?&;0|8X)ll>Sx3C5L{ydw4z)Tl8(&dFS zj|oyI+To1v?&m}1Gw5AxqDUgvcdbX)%YieaKzjQRKT=uPch9_{2uUodNZea{XKP4a z6*MYeKS4wgZIq^a8nc3~XT0#oB*6F&zX|eRTqP zEsd@?v|Anhb4&U3zG+w*wD*-}=QF-dgGQ#UD;?7M^8UIV_AqNUIT=PCS=A~)`|p+Y zW9xeki$+|b7R+FyhEWs=c{McNpxM(t9!gz_Tg$$zy66SyxUWN@Z<7~EB-i%11Go8e zm&4=8J%<(=CJs!J#3i%HQHd#z!@*n?RW$!VG9EZ`#nj6zWF(6chL|dfpw12^8P^%& z6^F19-;v^vie{LiR?_N~&>0?Y-IXyclK%C~ND1wFse zvV5kYfp#Bh!n~egDfe?DR-;Fswk+OwLK!~fLmZV%8OUTp8Vo3?uEWYr)*6z;DY+3~ zPjf0}B`BPIi)>j2UA7ijGV z@Mbf$j{u^sV7S;f>7URn-TM#gpbe@Q=)ZnUU$C?IN00_9FK^7D@chvzGVVcaYVOIG zY&m@W=F?L_={$`VTNZ3Ht~T~V>QIkzCAIeb<(!D!n1^(QRtD}P|9(%GtNnij|w8A%u2X$RAFY#^y~BYoL~aHvf*;(nVVdFw^d! zqGzV;*X^GpCw%^#?3!KAM5O-Nx6+tKA``%pmc9a!@c45Y+z>r z4tENck04~;VbuM=61d&&;_;E}af+Rm{w&AvB<@e!hDK{Os<8Y}*Og7Mk=1V><%wtg zf47%uITI2Tu_r#!%V?;!R6*mYM9t2O2yNwG^U-dDh;w+mdR|$>QTW@a6*KNiyA~n_ zio@hhqQ z7Rwz{ma9cU2S%y_;mP-;z6(k;v_+Cq&_O0LNpiSkI5{Id93Er)1n#l6CT+MH|L)H0 z+=qPH;2u2S(U;Y@_to0=5}Y~wV?7aGvHlgg%v|?Uy`hrbFSaam{E&U&;#B%T51A*y zwzyC5u7PaPLe8$w_17Vk@(mHND&!tB?cj}qGnRk(ilTjd+Z|$k)Y@b<2$O5%B7o@R zBPs>hc)V+v+(q)S_>O>MT|%O+0*J>F7i!5s4Qz*ZCn__>>5)(offYt{bqEl+IWSulPj>{R$(boyBb-FOKN{Lba z?WwI(G!UH%dNRhG&)AtFFh<8FdT~vuF35G>y%4Bl@fOfhT(UTVN023I<;uFYlac5~ z$*IAbp?tawNoyL~Gv8g*?^%w&8Q;9W)Dle=Wqc7QQ&=Bce;Ivb%!wl{`>RlRbA62~ zL_J431W0Y;qF?6}h#b}a-sYDvla^vk1&E!)!DXmD+t15hk*WX;$$UW)M&X9;^l95d zR0zzbQAR490g983m*Iv5l?@E;;X$!AYEz}l5j1=cA|G1ZtE6Nja^3b8ktUBJ&2&Kj z*kcD`h|1$7THp`k8K$|ndA*yTZBg$%4351bXeb?UFmhmdv{HS6o5p_$sz28K6-W*B#C%ic+gPYLw!(Nte)hYYr ztxC|Hys)Q)TA44&k?(o)&0qKT2UwTQd}tiaH}diQcK9SHp|ktcV%#F-O6qhTnky9r zkDy)^OV;dt28(qDmkkwLrHnh#^sT8!Y521 zj-A!$#S^S_s%yb0QY-ov*-$(4yI@zrf@Tp3&c1yOgDqZwAzCL>0jIOKy-OeT+Ep(| zxo!_&B0UCcOhq|HH1X$0roPGK5SH2KRm$sPOmN5*Q7Ya7kpr$F=3v2#!#vTQW6a-; zFr0l*qnh-XxW(vx|0xOOXJuG-DK3b=%sB@9+G*-H8GsC6!f6$ZYpRA-lXI8$-?NN; z8c%}j5Q7ZySM2Kbi$6chu2R`mW`TyeW3~-X_|6;M5Be93TBjSpOp5=Imyi9f`C;G- zMvtS$G>zuW0s#t%viV|E+OuO1Eqouv~DhC|WLW2q)fEdHDsGbfR2S#6g3|&Qwwo1E( zd}vWfqaBa}Htb)hV6Uq*dD6F83t?^qWl!TVv51Q19L>aNT4LI^^_S7P%WDa}|8NvL zoWh1oK9U{#k(w!4>izEn5JwFDm`@So(#v^WB8;@01e=K#i76W&&2iCkmNjMs?eHVlyaot! zfuauEfHuiyN)qcBbKL%dm<`Xe#*AuZr<}*KC}Gp167PJ=NWL2apkW%_hrD;K`#=Sa z50l{T>3spnglL`XK060v9DNzQUw07dthTI66Y}||A)1jDX%P2-MU=mP`4Xg*J{p@n zntx9=)OQBl*dCowIR`nJRy**bXH2~)4x?ZcjvqD{T^F@okhX7v$d_YYucB z3=MJ2Leo1?|14N!xsX5%j2K$zu9nxR|9;8Cvt>G6fr#k7%{l8dRkfBOTIfG z!0v&u9m>%4{_;z=ZPQP7iHps{Tjd})tu*n#ZAm2wQKRO01L z7!s;7mRV+>T6uC1sJ^BFm@7E?v<_Y*W@>#?-7{R2c0qS?>Oy=U7(Dg2M=|HUVt*M` z-LiaAa6Gb-V>;yqf1!xJeMFuqR;`D1@4%42(MVC1nY)>z{q?|Jms9x6fq4cgi?MT_ z*~UV}5&v5rix#S*k`%&ZD5b`daHnXB@H<|(#7HzrN$Fx4uvg`EVf146g8% z`J^8c5H8C96ca%P(C$kB&yzlCo@dKG_7xSgo*_R3RpZxs|dO!@4yi^jgzmFU}DJ9H|Aqsej zM8LGFxYh*S?9@xZN!?@VBI+ ztn^_QI7Nx<;zAiu^?lIz-~YL6A^*#Vz~FJ$C$hnisOg}TVs<`R*~H>oqw_WpZoGSE z1)^-A>)2>|?RwvhaHIAAXtFSkO=x4u@Y=?wFIG`H@7Y(1x4_6xT9US#b4qIFDEPgD zsFvSg(=QwwVp{wy8F*+W5*St6uH|B z=Enht3Hv(`PGz$0XTJPU=&yP?Fzyp6Pg0eu}y^A0dx{RD? z)MoAyKX92r$Eb~t8KVdV(^&rMV4NVRS-jcz`RTYZ7u{z$Fpd1135997BPN6%0JYCy zp8|z!B1a|W#-2&~XHFf20T8BGR7|1D!Jqb@d9 z-cu4=Zl+O3r;Bpn&gX2!v@)wRkswd|`@lKV!|t{&C;V($+@Rx^-309mNO6C(vLWDb zrudTf5-EJs@wnPm!&vT@4s%VMxnuVs$m|xz*FYEWi}6<#=P}uD$|2?V#I&nhzTKC} z*xE0JE|9O*Uip-7_bfYp+G>jlWfbTYNm3eY7EM3-3PXY6C6(XA2I0h-z&8`QmOwi$ zowDFwdoc~()GcxMlG!W9O$v5wr4oIlq!1zX!`KL=%D94q9d1P;N!S>nRgBavNTi>e z126fC$CQiWZ_FvHix~Vyv$3VUYP3Xkolq>*=x@tmZF;ujKwQ>SP+8b{uzytrQLXH) zQK#(0!okE|a<2&bfuj(_hgZHGIH`TLGt+qy7{+uJq0g9RpUVDqh1hcc3T0+%ED`K; zcfH3dr@eO?8M@i+M<$Hg-d1k0q6Juj-X4H01x|G`!U#fl=o4$KAZI& zs@2(+l;50j4(M^OKJxXaKHH6)*4#}Dx1^?XA2{<-?pGeLRp8zop8*D?hKEr={iROc zKGeQZrjaLy%>ML;#3YHm8a{M@IrLxxboPFs-a@;guXW`9@9mKO7RgXVo&-dJ^HCR% zls7OWD7@qx4uN)^{86Dp@rQJ6{QJ%z8p%=>>Z;ulAj}Eak2~oH)Wssq;@F7T_RV4( zD|PNce>uW}?PR>CAP97ExbaY%6%yMA4WN-wQNw{TUC;6Srj%) zxn?kQPYO!=G=W0D(<{!pBs+PgqVpXgKxA)d^4!CjrxzaJ66m(L`o?GN-~Ct*6C(ONCL?&{b^fVok+h-MF20FrZ>H~* zg|;O(uv=KqG#75*S0|O>-?o&55;7~(?G^n?BG(CONS=^L;xAp%j-7DbFk+M-i?77r zerRwzZD)~t?$Nf2+%K1*9yI5h@(4wyUO-^Hb@O)R7CAnRGcr|nef>lesoqFgtzK~$ zgak~L43Z=XeZik))}-8W26rP0g7jyJ!JtlvFom)d?S&?UwjZI4R$5<|T1ZR8*E6CI z_X>Cp;Kp#x9&uznP3ky5OV*9@F?7h_taomP?O#1UTz^ilzS(mgtgl=n6U2BoN&7rp zT!Dqk#}fC;rGdh0!^?BiUolS`Myu4t^g-KKEQm=MiEnRzZa9(?*D|w;5To$Co0O?FG5i& z39Nb+Q2yhA3)DHM;>;sa5o zcrFX0@`4<8&}KQTiNfxV zmb&Hjr3rY3=Cihu-Kzsg5~Cfb^^3^n?MY^bLnDa5^GhM`M;70PIVLo1hRm5KO^W&+ zgRBY5N!d~%OLga+kj>98RsSIWW&9ox{WX8&#QzV1Nc!L5lQq5qn~K4K0ikF)ede_! zfsJIF)VGgmxshOs(=koE7A2Tw4xoy8FfqqyV-+C?@)LD2QWhf-MF}fha5P$gB5WxQ zmbF+<7Sd}6mk{M3oB|xAu**cwbJ_M8gqqZ)F&wI*RN5!W4AQXv4Q z*17@Z@ht=W-i>`;6>+}Qt>T659N@19yE{h<#4Q_hr6QKu#Ri9vH<@JNpfH}|6{%3) zJ>hnv)#os0CF@SdkCBMcGjOn}O%L7ufqjHal^xb0%$do%YWbAPfop(GQBIIfz$}u>~5e=3?Q5 zL>+%$^&V-7jFu%F6HQiL-pl=;cSgl{%@Z39$*QUigzgq#F6lOvbm-X_ZAyIV6`ISg6r%kUwMtd-t)A+|%?g@7 z6~|brBQaM@7u`%Xo1^6OTakKh=I{7@TA=u|Iy~L|G#W$>EM!S-SU$Ld=5PujPZ2N$cj(ntiUBzHt!EbthiHh8)2I@*x zsBaHr5QC#V#p4Crd{X3koT6t_* zH|)DVBlaT;?As zHQkxxtfR!4y6yMz_4MF=(0fJo1{ui_865xr$Ic7&HsEZ>!W!MwFlnH<93YDH+PEG) zR&9;MTL!=5VC0VnMLOR&KpQ!uOP`ve~oRFl$@ zJ((Z!2kSqbQ{hDdKl47~K-FhtkmnXm&DC{8@cX3`_#zqKlWe>!sY<39@Sh_&C<}bD zsEd$iR^T5(wlb4u^$8tmEDmtyMyLEx-^@rG+G>+~8u;tO0)I z>h<{gwftH8xmVIa5H!U1<0bQdTDSCnGfmH%`cyUFMpgDuZJE$92pR!38g@}KaiY!A zkls4%=EoD4G<7Vv5mJj8-|paRN-&HXhuoZ6o}E@@G{#u9n~vmYQh9l@n8mQQXgYSw zzKqr)*|HkVEI~&Kf$TtCfJ(KRR;!GXEgyT6ee|z0Hq5TlNXPyz^Ggn;>U~7c=!S`9 zwKFlxqM@oulAq5eCpI(J%urJfnGD<8v42&G05~+*l@I%fby~Ni>a>ux)P+fHT(gG_ z27#^plx(;=#q-Am;9GcIf5r7oeFh{q*b4Uk1(E?r#hLaF4?X)pC=&;8po9bGGK8NJ-`a!5cl|*9HH)dEAM=!}v|1^eK?%ImC))3K?0L%+V8ftULFNR282=;F@t?Y zg<86TP#Mj%Xl9G6-m2_+6FWy53E{X4rH5uw1=S{ocJi`kjT47s*iVqzg^IGf>;qD= zf-&n2MRrv(l~!w&^@xs&$QoHs-DV*y+f~zsDp8*w$|Ha|ZD{?M(-$!Ps^7?~cD|k5 zwwk1lO+QgN(*3(aq9Pd@e=_2EWSdz|1QUuAg7J9R7YSeO2Q3bGTkmBYMrT(H9j31q zi7KKpQWCwD5%(z*6YY;>&!5Zy_mlNUW{?bQKq8FtI84D>yR)HTd47fMfg@{mc@M9d zgAbLaraNScGhcql=mr!0UN@{0SMqZ*K(O$n+~MkK-FC+yL4E7mHb4GEZ4PtB#3u9S zLP(heha{-#{1F^xUn!#FUwbRsO6t9SDHjI5|I<25cyBu(OnBD!i@1gv@0=WwLgV_5 zjr-o3yf?V}4;kt`7vf~0j!0A=Kku1B(MI^gIoJ&skACF(a3?37`kn#_KYWq_V6R!E zE^=>!wHR7vh3DW0#MAkFBOfPi%1@}oMnc!FfVv_%>V8V^A#WG_79p{Y?D=f3qowHV ztP>KXwSIf0&aREQd49Z=P2;FA6$Ikdv5WP!+y-G;_KvbkhfX6So29K^$tVv4tj5z= z#HT6v0#($rNyO=Q&Mp|(x*kDPzDFZ0#e8RR9Nrmz$o#ilY0ke|UuW{Rw2E7{8@`^1 zZ@6#d1&QBa5wU$glm8R-`tQIvEZxKH0 z9koq`haMWwon-~eOp630uo}-(Gc+HGS@1gVDH2 zzXhdh1bw9~Z$#Q&3yj5R>-n=FOxPDk?1V??My{qCT#42$FRH3RS`-7AB*V}gl z>yE9X&YCv@lH+pzWe8L4Rhi;n{K2>4%|YmYY_=jWWf$uh1nq(J_B7Lwhy7_~TJV3P^L$&rqY1VABOFbN76UCI^)8_h z@6+WCLsvj(Nmr;ay59dg#Un!P$XnRSfUQJYplXxATs7Z$6=(5 z+$h&cRKhf}m#42|+GqNWjZ-8c%k>gR^8woBK_He|L(Elgo3GbMN(0$*LqTC2r$y+1z@*eqg}<*bcc*u(0F_ z$Yh>xA`<#zzU9!+@4w}WjN6#oD3oqW>hRz3V_eorP{AB{iy1NJ@>GX0^HqNb z4i1$#-~aGtYpcz6ZMHXWcAIUx&2@8|yV;(g<2e!6~vT77vs*?P@S8(d$KYq9n5LIRcY7P#rd|4f<{pc%dEh`2e z2s%=EE4ZCsBqGcCO8GHeT9@bt;}p9s!(BLcvUx?lAb#~(e0D!+;4|zq_kPix)Xt{(*Rnfh$e~QS zq34sR6ACJXaj3d{)(N*V9G>of%M_klzE{}!E3>rY8n~e1x2TWW))L|lqA#X44fb(& z>P^5H=jBc%d1M11%)U)7)RWUqOv0`$9{Df6GNji<7#s&*x}9HV*{rnfgPuM{-c%oF zKnXeZFP!Zu;D@&3{~p?dALDi+wqp7UTor&w^zV+FpMDftZ%4I-_Q%*-{2r^Z$UIB_ zLf?;I@L91lMKEnMJOJ8WX%1yhGtnBMt!WL!R%5pA9@(mEN~Phul2kw35M^{$Je95+ z&SV0Vp>{Qe1fiHqtS7m}+GSbD*wL@2)H9}2Gt)~n(sFA_5adPLCRVhTboOZgvn=ad ze;`a6SrGXQPVZm{X^Rmvt<|^j30{Lrrqk7yUEkmFuk$g~^?!?Y|B5Q0nu#eu4J2%5 z?Vz~5oU}UX;B<^|HKU35YTe<~(vsBgX*a#~ZV7pK{?bl_plLA!HAeUc&(7W_!H1>$ z09ktys+BW%4GMVgw_jOTe9E#2rFverLJ6V2K9Ul1-}EBMR(P#7EfjW!2klV7hN+`z zRS+~N^0B!c*#*Z<5Fv5{(aFT-L}wwT2{u&1YKzp?Cd@y6vaZF|P;8BOuG3LgKfR~d zX7Ny*l=>y{m@-ANG+@D{zkz!!l2NPOXWFqq2np*4QIR_op!j^C{_+9YudlV>Vv@Rj zVCB54xW@Ycjk?-Flun>My2Ybx8vE0GLjSE%6t7Y?)vtArlgE@4iS3B&W|i5WZEQxn zlr#58gq+6Wd++`Y`ne$aFZ-15KE@vhWdR@Bu$LW9dHhWHhZKfUs^&D?U+15&gqF}% z4Vz^V{45RvrJ-?ue?6n+lORSFyZ!@r&(oiCpX+(JU%P6UPHFI^J4F3BpWpt&_lrNx zyWM+2PJX`oRmMLPVw|ud6f5$;gAd}b2*kVZOe1>$dNo*FT!;u>|4c4`Z22zY*>4(a z3@9k$y0@=y*>?gs;<>b-{B@h2Iovo^{_n-pVftP;0DPciHI;gY@k||YST~$iQg?2M zVZy0g4@b}rau%`MVNk+wOVcv_*x@DtHYEvManfC{HW!OX5MI19y^hmi+K>Lz13RWm z(_-tG%T!Da&7?%_9D)-81ztBMkC)#%h8+n2lpWg5NH&>>v01DGJfu}BgFkA`%+qt} zn3c%YHwy09UAz*!DbXhcQpDR3*4gMx)~l4a3oow3xmry=by~Wa`;Yefi?2fR(yVs$ zWXw91j|F*xP{vg+gUb|)0uDwygt|-yS1dRUpArS+?sh=izhdGJW{b>FjjUq1Kc+qi zUK!Y*AaxKjs+0bGG~z}6!51MH&)6=uRtv-RUu|S*wL}r=iUMs9-SDJ$8p9bG6Ee@< zU&^gqEYXTcafux|J!eWO$qzws9m+A5y9EXMch-d3CD`^^>-iem3^XB&)(MfTq)&es z@^oyT4D04jgCj&C?4s3zY_nL!by#olquq9~w6L5(y~xhMHPYs}jzjf@y#4yUo#8UC zen&=Cxyu0AK_s7;KsMbX9JjX$P;>!R=-{Ba?=!p|N_^FfZa4qB^Q5ir7Xw79MVJ(L z_El;Jml%lZxayrU2e!9;*mXDGJ@LIonhzrMWIh4C?m^(Z>Q$1A4XqzpF3{NcROnk8 zeDbSpPo%#>(6K z<=OfB*!k7@`^gF{F-=Y$@h=deW5gd{jCGtw6pc_KQFU~a!?hJ1r7PSRsFT2ty zL#N7kDFf7qY(>_|Fn~F=qb9nubOobLerR2XFsyS1PYi*})8&Wo6}VG5YamG~n1IT_ z2k*<&KYSG#?ov?E$W20U?JnOEyE|gNNJd3`BRhzVm6Up{-tT^+<1<78 zyEb(ZBL;O9k<)<-ssMeT6oJ|3DD*Ef8bvHOVk+fYUGW_#?!c_tnHjPIIUw+I)h3J0 zJkXpn-w8Rp&;v;RfI3YlKceYiy1%R)&q$rvX!P^Erl=Ql5{3Cv^NV$D&Bof6c7L2D z(-``gqhA{gS=F>LXr>1REVa?x_dL#`Uu7)&%+*|@YFqWSR*Daph=>2iGnT|wkyv5k z;vLKXGgau5Q6epIopFvv=#!1k$)c5h&T6;UHV09SSb3w`V0KAL$V}62J4(vh$IVBm zznOUsKs`Jy6U=Ue#MCK3lVM4CcLLT=VR1JDmr@&RYirr+{JTw3nxP0nS)U(brbk6r zGQ1}{3NWuWeZ()m?Gbk5bI9}VMih>HG2vP=;a~!M`_nsu@W(t)J>dI@RbrrCohlJw zhb!tZZITj<4IRSS=KyvEOFUmW5xad-fWopuPtdIjJwiC9H3)gZ$v&$K_*mrKD}*SF z492+yv(3Mz_}bnOr65M3FEb1{1b+tD9qA6{PF~m?2P63(QZdO^yau@1{%9~b%$WTW z1t5tLoLpF6r*%5^B@i-^Pf=0yfpYR?PMN9mzigl9k*OHVt~+op2f8yJ=sh;ST^wIL z8$2x1FfI6;Wq|?b5U@M|jJf|O4aBd$Z~Rl9``fYo>*`F zyo6E{oy!cJX?W%E+BM0G*TrwxZAx0+=N|Wof!Gg!fjNr}!rU5cGZ8(<~a( zop5R3$7nRa#dJjkI4Id_lg}(Y{S7K2ul4j^xBp@MC*U2!z%}u^ad2c8x>2;9A2607$ZNr-n z_=}jUb?>h!M`{isKl$ftIg(84vm7yzW!QI+zP0DYq`cr$)B!Lhur38;+N&4g#O=TS zA@%(7%FK5Ub3o@goeEY@{40xpq@TBch_`D=Bhe5S7=O<#goyC-=xAvmy&7R9ea|K> zrOhRpX!q=hutW&#k0)~lO4%UueqYC66DH}dvS;c1HLAL$T-7_si&F4b>WFXIfqo-HUY0TE3V+jS*ZGY$~@##M@r zELoEzNITCxrb0tX%!}~dah$fN`l|gM%PaIz)5p`YWGGVcR#-fpP z8Der;LNPbBPY%O^-w0kLF=3_iO58p`)}K+mowBvl8?c*5Rid2_cLI>6a7F zj4@7JXDqdA{)JAxmDVHqTXH_b6|_DVKC_rMwkiJC_P3fdhu50WKAinWzk=-l?gCb@ ztqH6tevKp$DIIn{)sLe8iy9^O{nTQkMN@v8)?MV)Tf4vi(@DvLU`JDAz}BG(rHr68 z_1I)uKWkw?Ho}Nx1Z+n{&`|+erGV!^0<95=ZR`vqXmqu^-XkKO!$=q!d9h>{5IM>#2wqzi6qev_04^J=sMa%v#TRO8~hLi&exsalD_cd9e$=-~F8EPM)SDX)m4~FI! zNP6!e_(X6A7!t=1?f}7ro$=5yT<%4xN8dg~0D)*V}#Z`^gl%bx3tr8Yd z*mCSL+$wvePBZu+9gYAVMQqh|?wDdfP)Fh*DTb+Of-+OEsV*v1W0uf@*yttUDcrg8 z0lwi6H@Tr3KfWUt2RptsNVEKuOj@R`bQaOpCczMG);>K~Jh#9XLR&hzUWFYY#=fS_ z5{E-6R+g)?6XIS5zEUe`mvq1!yH8$jVKNa-b0oq(7R@*+Tc;t@;e2kv3&y--?|HsH zqdW*e6|z`Ohfe+%s+VxPZf`tK%~HJwW?8cA#BM<_gf4%D@`8K+Y`+WEZ|vi_)f>*N zGTklfzgiNOg=WR-fANXD-Hz{K*5cj$3TpU#nwXNpxvF1p>XN&$u3q^Ss~CTun;rbH zO5>U+7Z)nyGBSFdd}@yey1`2GQFnjs*7>aMon*|i9H<<}u^45Gl6AbvhY1Z_-W0bM zH6h;<%oGRCNGn>GL{nf2@=(eFl@MlNNsC7myL;W*8z&8r{N@D1!0&2|(#n%pI&zweewCTtEwU?v6o3b>3L}dE`R$~^l3f^3GrBcd@&9lli=;)7)>kd+Q{+-Y501s ze)JK|8d#D>U}zy;COVlXe)DhX8uXAO58ewMhG40o%fIeLy*j8VtvHp8eXUz+_azhV z{XUwZY(fEXl3H6>9*#p)2bGFLtN7|aGmWV-x61Zerpy4GGsT2=&c!vE8Vm(RPa|~) zuOb+&@0lfxJ`3N*C?*_d-CaXHj&t<5FI^$_HLMTnAc#?a{Eq6_KNELSR?&XEdGp`y zy6Q4rqA5TOsEG%+o+1B_+6VL6wDD8-&u|j7@X9J=)811jV|2Xy*SwsAQyQQzWQUj@+D%J(Z zH|}b>;jkoQWL1}(QC+S%PK*%MNQ1X$SLWI*<7cVKXx$;_u;yMATa1`doQBAv#LJ=LQEe!qRr>At3G;-?a7!aPc)%I!h}=2AJA;Y< z`=jH)$}I1U`$F)sSRLb#^-0_cXc#}tCS^lGakm(I`k5edRO$}ZJ{n+4NEZ>iME*Uo4(R!190X%q@OIy$z|bfUT>o>qej%7j z81c=8A7pHq-Z>B|TQ%4NPvt#J%d~=OQ#~k2ud`yL)>;R}os~R@D0ExD6Iz8kVo_Tj zzDKHUX1lOc+9<&w$L=n=Fu)qAY@gng0wda_jPj+Zv7@vMhoa9#CXcaGoV>#43|4;59>oz_8;>7?-%kv9n?Ps3~l_G&PU$=nvQ2dZ{NCv#px`H z%`;wddc;L@P(j*S&D8iNWI0A-Q_oLwn}V_M(@NF^Ojw|hw~f3^kb*uM@3JK%CY@}- zl*%up30-~`lS_KkC2F}Il)`#hBch9Gi@|B$DQW%+E2Vf`J5;t|)&h!zN@%^8yopPV z?S~eebnigDlI56%H`ik46y;vIWl5+^1 zsoFEm;}bLPEEbZ5yli`s?RB*HP^mZIJu`!FEcyKB4 zoCZc)#_G(v)8v%a0Tvct3`yc$Z_V>?rOJuYN{x&pwBbMyJAjG;yjRN0`3>152fEdb z4#P8PVlaH-#GlPAm*PvilK6KsI?L!f(MKs4h() z;OlpHDZM$p{#JesB@LPufsXhhm~g}hw^bztEDjl^3yH~WGFA6*N?SmjuRoc{{X49I zzavGpq<|Sc<6Q-VR5Q%Kf+a7*a_`(9iUP>Q!!|moz5}wg_a9Z9kL=+a8LXx2*MxaG zUA1S;IHQTCLsS8Idi9uJI&F?V+w36^C9$EFvBfO^;tzYL?A%sF%BtztD>{HwG zMqOyZDQ6s$FJSY{Yhoke{WBY28m*ltu{U%2|}GQv2UD*R+Vp}Wo5 zy7G(gW@cWreb0BRIbB8j>1M~@-|xiV7u`S|CgSK{jA=-M$iF!Ekc-#I7Q1|VjlqCG z`tr|ZRe#0i#ESF_>IC&yA@!Hce>^=94bz9wS~CZPdfs#%IK_zPKG&-xRk~W~MC(as ziLB6-Ri4ooD5ti%+R-2z>&?}>0`O^UsO(nqoXUBO3VER-^dnWI=?FN?Xd2^MlQbWE znZ<3stGgNSnFQNq+Pi8Y%;srWmTENRb#_ysk@Ye=%sXwcnxj479b8&?@+ce*1tHAR z(3Z&!mHao1tpQgy>zVAF8e0qA#s(w z)^P*WnCMsY)a>&4+G`d{vLWOWStGlvk||pF_T`{s^~6&gpEVKY_c%4X3jktD%`zYF zk9Pe_1>=yJ=}-p8>cGob+?zNHto|;7J*-?*9cm{dU`1dkK;Tn#bq!59t5Z^}MNlW? z$L&zssh;Dxg0TPVhMniidkulgE6n6FoO3$SztaB?Ckg>yc`JOm8cmo(sO3r+#-^gi zRg*0))|?RxD|pWr(t!|U&?g=jz9m0Cv*+4)0Ykm1BE0%~d5_v1bb2Tm-9!&tmGMUi z>hbF|@~2UBR0}|phsS`31IUhh+CQ>?iHz)`r5Gy7849@?DSpck#-AS--${C8&8|By zxQBWjg;+7@j?z*8M0%5d0F*&5;$-f4@*-n~IxP$xK@_r`d=%SYts+o~H_p%jdl85& zWTNo0RS#Wa*iYlpuJS$7guPm=qBYKb)Ohi239$5-!|y#>@y3v)pgdyHe8cVY(ZAq^ zrK%3t-X1);C)jv1Us|1!HFwMlKod|2WjW~mjxP9!5!PN&zQ8grw{rM4uXpi5@Xr3e zuy{-ap_1bAPs$uJDfsW-0lO*GMZSjZJhaarFZK^l7QwPLOOU$<{2qy)Kz#T9F)%1v z5ook-vA&K@_p4V1GYfhI_&vAXG}LM&@y{{}7w!Z!DGrkswORsf@LjFK7>`G$Zm!Xh zt6A{v*Gu?$W7EU0sp_njiJN@lRNY{30xi_WW+9~qZJbOpTF4PnR(MV_$K`SNJnv5K z0qm{UL*0RXYDaQw&5I%^gJxHltq4Se()z7>PDCJ>yohe@wc?z5pnXVusl;r}z4Jps z+79buBwi}>m_V`>&&B^qLq9oTOlE7<1&^Dfk#E{h)JyA?7tYJ4c?IJdI0SIgQC)t1 zIQhW;5c;T~dio^fde# z->~ zl2BYPJr7874(b^_ENrw_a#s>0Ah(dI6@n*`sMS~A?X^nKcM7Y=5oI`2rpVI}Do2gA z)1eoj{?PXbYoyZT9yjx7Uq5AyW-z$_(d|u1I2agXS=WU}K?l(w8A0W}@DY{uqg^pW z&PdBxw{>>UzwH(D(J1i%JBL{ikOB^!3IT^sL4mmm@GZ(~4MM5ywvT3=JDmP$xji@D zs}!MU8Blz+A*&-;8nM1P(SBj3KOvq=DBVYdfk45F7^C3bcvz)6s$?eh>} z@VEBmG`?*5!zfbIfLtA*HVfYgUE_hrF=DVeMpjHzOV&Cs3mnw37B0vHyX2<9Xd2r= zUIcA?fOmdu^AC)KcnEKSZLY?hU9oS;X0hGplIJEht-(qWb^4e2F#nehEbg)|7z>6W zcCIZdgkShR2AaDOmCDg5UYPNDUbJpQz@E?R%tU9-_*>tEZY-}9Ho#_a zx^TY4+Yf?UF=oK#nIKIpnU5&yz0V_Rtf-Yf6x9{;Ekf{7nB9U=eDK&PV{A|g@`Jd- zxxNmkue8D?B1C~%zJPPZo{wMs>M2aHQS)wdckpZ=Uyr6U)N%ym052wZ!U#BhpyP%? zvV}vM;FlirSc0UwZdn*Hy@bqM1ABkM`If+$uZF7X&oBJ$T-ujliOsHI-{WFgzZ zl{pP4JjZ(r+5We-E2>}9vV3D`F+2xc(2kv zR-pdSn`ATirscOk_CF~1zC*hcCY{RYStp=yifYqWv~odCYpDP5a6VmW zy^yd_b676sTGX+X0?o5T3}AwzWoUO``6WRGcyxP%7U!MDJQ180r%k z%2lqv&o1OEt8FG9pl|gY-85hPA7EkcF&k;mdsyoiTyIP;$0d(IB2FdVQ&KUOMo!of z5e(kHf9iDm`14*>m+v5#XwzyHoN69?s0)^cH+?^*j;#i21m{{I$`}ytNwlAKKsck1v$?#}|Sa zhGLxn8kTgq1)}*RQ*vLB5-M$LpuzDkYFK~tv%JskB*bYxv#Zp@B0I_8o_*>kCng1C z5lz#^;E6h#09oMJwW9p6OvBl0`Ap&)t%BS+*zs{_VOfaWX2lcw!?9yWyuaXl_D0=> zfTNTVa_3zJK4Le6A2OIkD+}s5 z+o;^0jY`xWwJHsg5C66E{w*qrW*AN@4x%YJ{0~n z5vuBKv&;54dVB8j21D9RWoWL`p5{4VwPA>=yu%zgi{Rx)r57Yw?^xJQp<3zQ&L1d9 zg#Je7Q@3pOp%~k)+A?&mzo_m7eUlgIqgx4; z)bp|0su@szFxCXKO5#sal_5~0d6Izd5bOAtuO>~7@kMCA!^WHv=CSGJE^;Y_i4No! z`YQAqS6IEWY$tKIMo+@odP*$S!Jt`4{}{^+`PS%;Jj2g9dja<%PGmMMnEg%lrXE>~ z8w}(Yo(KRE$k$H{Bk_*HWa9z;G0`0ZtGZMF!@PIN@@68!t)cr0`QFs*+wHfvVFb>x zEsRr2KiHWQ;YH68#w>n7mU$SaTOj_q-Fky->H+%A@f1wi$n-wD$f)wNlVTq(^|0y9 z*w6!vu0^`$LASJ9#^Uum4}%up(kH69Y%W1~?XGh1_6#w{iXlSHeymj@(PR_tW`b58 zP7{F3mS3IO+x&E2lQ=@egKNLbU^uk@oJ;wYIS+2om4q@D^M(+_h$~? zp=D2)H(N8VmXRw;SbH(?vc}Avav0ew1Pw6_;CTk`)h{RL(@-Gw#)o_3 z#gqMUk^T`P?9p?I)1M{gkow=zACmz?A)ya9SQgBTEf(ZpBm{sYg1(xQNoi+ELzkv@ zw!$CDfYbW&u%oBP%GSgm^=}yMTx! z&0Ot0HY0yGHT{onag4)3$pXP_rv{3o=ci3o0WM!gTbVjkLtJ8#YI|JtL~W@0 zFpku?*g2l>unu~)Js)=0Ob&4K&Q>(6!}J5#o*6{C&~el_1J22WEfCo<~`zZ|p zpo2dt2?QoL*J*UbGBR-f-mf2U_b8ANKYjnfx6xCA|0Fdqo9iX1s0jU|AL|krGKl!# zK5~&gRK5Owbe(kXK6n>WO|j-N`?hHic|KNX2dElTScKeTP9n%Jh4nW$6c5EHHENo^ z@Ea{}Vm-GpXwGA2Y4(a+eeR_d4u!GnBE6z38&)N%*Yc^iZ>QFnPv~2=BC;mD zhJ8yDjF%oR`8{tBTDEzwFn#~Qt9oj-&E(Y8_4NnyHcp$eFIGGlBa5Dt|0g_y+4NP| zqJnn=nqL2+|I4&k8;r>l0Yx!v3X}`+@>Xg7#Bic@(a_FK9zK|$N}1GS8pj4}UmpkT z*paceH&vo`3>j3S-YZPuq7q)o4dT>lKq08&KkP3`1rMbf-aEX);#8hzGgRU6z5wj| zaFClH?ejF5wmWhg#%-B>l%nX@xwiMp>Xr4?y%o=HpsVJqEYQs#T|YsK;`7&fpb`)2 zO&T+rEqPcw>Z?+mUalrDdh2b4yOw8U^Q~njNsdFI(S(^C0CN{am8>b68E|zv!rFZ> z{zl`UkMUfsITGZt-#4|_08u#)#F~ZPKTPhSgv*>ofd5WJoUA=KxHR;^1@S^tE$Z4; zG=#p@5=XCzX1Fg9V;q`F#Mpl08}px}JDvB+Df!eqIgq`GBf%YAZikrQOgc0x@mFQ zh~Ok43{~3p$n2q>wPiY-M|T%D2A{nU`qMFXqIX0RiV06VF=B@U?#*5n@u1IJMQ!zD zyPnzF1&|lAUw7$!fOLP;aTfXcb}NV(1Y7Kv1Wgab4??GoP|w6!9`4LSkXqQGJu0wz zYT{O1(~>Db$VXRoL%Y-^YGpkj@m7b>Eek#-tlu4NcPA$wvABK^iR>N?KrkVf6e9wj z0*3_-76|bO$c;baiO?g1{%nh`B#su)d3G^hZX%@s0IsNNqkgKGwlvQ+rw_;CFKhOI zEvzT~Q}9<*YljlVIh4LoZ)C~21FPN#Vp&I|Q=^~~J!mI`!ji)@8)W#)2wxP;MvME< z_=U9H8Rb9$e?KO|KI`b`iMCayB$YNy^j$gq0hX7A*e1(St$+~Qxh+cVP)p7V<=mS+z~^}<|~>ES2PWF^NcQE73D>KH*8Y>W|9;$ zwnNngN8?{F8Rg86=gZWsx6;VMngrWoIcjGlZIzv+QJrRudud0Vueuzl~Akxxw*)? zFl5wXj>7e5$4YdUKxUT1c9v1+W*&aCSNo|*f2vIX=j^qB%AZKpIHCsY-SL|&({xs{ zNmjEsXhV!j@<4%N>XmKIjFI)5b*gz4=- z4sc{4n2>fS?PnlW-HPftm6(~_AE7!zxzr+^3#Uue=}5VpGHBLui#F3_G`qxb+k-L; z=tW!|?3PvHdr>!`eCMG}+`1k?s^7s>BNnE>l1&ryCF3M;%VfED>US7-Otq6e3)k2a zrsFgcuOpfF&yDLQGu)a5CB!#}aD3pGYvSI{74|2`Jh-2(sLr~dKR?Q7C_wLgW-=o& z=kfF0joVh~)mA2N_w@GRdlhImIUS-i{SHi#9Z@Q(a7Z~xXFKbjM0LmYSFTqj`X!HP z$JYLpX?(WaJWRMTiQ=Q6J+Ovd^FS2ANnd(CSchmc;_@}`{Z*c0S{IK?@s@kgyxg#@ z3Rsm%pr()Qp_r$O<{MTMIK`S2T4$1K?)-B2=I7)2^X+=cp<8P@G7UVyGYLE?32ZfO ze__yeS;kK6aav~x{ze!V*L+$Hg6q$F>z${(A9ga=?984Vzx<5D(@6B=hx!j18k6qP z>g0|syOkf>K=~@T5R{tHNseOc=NVwSO;G+9<3F7F=L|M2xZ0|Bjlk1@kznMia?_CX z1sU8mX|3cYJm9hRgwtV*O8Z5jHC0OftXM@wo`?>CE}E|6q~iz^b@Pzbpv5D4P}-I{ z-^RMGOv|i!q*2MX{Zdz`ifcZ7M(5TgAf-Qdo8u{S;v?a&@0x30QgD_}X+O~_=CS1_ zhg4$?^dc6`@MQPl0rIp;5<())JK@pi`=}276S0EErYu0lZ|xw$vaVF3+GgM@K@QzzufbB*@wju!2K; zp0Qk9iFZGD!2QTI3Pc(>RZ$;TDQY-1FGveET~LJeB*k zO1myIk56Y!74liFRwjw6Ds?OLNAxaL5(?4nAKdEWJPaZdcqS`kb{{dED;OcT8j95k znv=dKI;0}K%Mj#&>l;B}r5QFh(B-F;tV{&*24Wv=h|LF}Q!mZ6s(ReBNgKDe z#~ZlJXw*c)nr$5~qMSh9^{?-0dkm7W{(oG?zohc=Jc@iWbjuSG)XKr{1Yo@@m27%c zpqz?Dxu?1|nFJetGwMBg-TRnQ>C6`2PjJ#+M`Qq;et+uFIW!I(1|Ow7AU;t}zh@UA zqgIv+vW=s|n@U43XOhr}P?@V7jO6sxFqLOC)d#vICPINzDGH-EImgOd#Wk=cC}yc; zscLNKu~VWAt)$1A3MHiD8`}3#3d)9c;&D*y=p`O;`A#+oNCa}W8aNNP8u{Nk1pUFO z6o&s&Db~9JqvnAs^H_N8G7TJ5y{JK`5FaUph7xICVkvh|&K^z}9&gUwT1@-i9@zNNweYKD0XqRga%@KL1u{5wox$~73*VY8@m*H{)eZC6rT z*NSKw|Eu4TuuqF&dS4w}TD5C11KK23NhB%>QR9aK!IM)LKlup|RwB_%NL71h(wyuj zF3zC%dpSt0NqKM$&IqQt9_oXb$aWL6F2m2SD}N6Q$hOxW8{ICSDvr0UJ;e)HJ*=Ke zbxL)I1q@34jJkpfd|+xa35_ASQhRdp{=Ks9v$WoBP&LvW(r}d?27h`6`u^3ApAiRi zZ}D41%0ini3W<>=uqv=LBIfJ#wvd2DM=(Oq$=08#_#?$Svv#D*-yuHa<9j1CHR`- zHVwj(+d!GlwO?5zbjs5uJ9H1Xl#lXKiVTh^e-PC&DRPn=hG>kcVw>UT*lj=dHdC|o z=C9TE_<>f}GgghFk&7La08vCFM`&vSaG#F*-OFGzl837Ok_()bL5FiB{N2+Sa|7wY z`!yIwhvVbGd!4mtId=BJ<)xzbRG{y{&y zvtIIg2Zsr9ztOn?)wPAetHM|41&C+4bg}IHF>n4a)7X!jv8oU z`}U=JqLpyAZz4E$0U2zOG|%RFAZ)5E%5J)s)oST?=+r|?PQn7iVdElTHx2ryZvL9h zeWM0g%UnE@ar-FdMI2YL9fk4k;GUqag&+&xZ*zp?%dE9DiX$ZnkQTqcDk0~6ViynG zW{g(H__t1tx?C_6+$;8lfh97myt)Kw$b$(UQ0J*5RFWV$;(o0j7%V-xW zId=z*LO+9IM`V-s7Gvw`!$cvr$-!wEDa(j5j}Ccl>ugIL2wB>66e zC}?2Fzm5JX$1rPQu9IBlYSd_<=R7XPz)lj~vNzbR|C-^Ob&=k_B)t@_*DxkAQDNKt zjY)*ANuBP#(Y`EB)LyyCEe$81mO*bf+SW`xJh?GK=@dyXQnI|g($Ro^&2|NO=RidLLFhXjPKmF69n%O)+^lv@ksG>8xPb}&s{C8lLq_s{8b{_H8CfP zTVJArz9{-3Z|Zy}61nilx4{6ABsyU=oc8cY)L1NUdh?`$w&3`hVhWA}vaz)IG4W_Y zLbt;v3_PmEe;}3*x4t0&rg0dA<93X^!6jGy)LsZ5?^z}!k zzhqhpm1{vwQoE&bo?EU$$VE{|IKGeHG~)`AnAi1$1<%ZUt@A=L^yP}z&_bkudk#9p zmfyQGUUc3+2wk^h`m1Vz3-^Z0OV1r@Igw`)?%M0u>^4by@ zBFK`SH8#yo4XiK7)>#7sI9?BLH*IKWI4o6Z5ls1bCPFTzlQ)ag24z$2XFrmBcg^QF z48;Wj(Y6l6lSi(t47Bla-|~qq2DN^H{mKU#FBfUwqyojadf9ITZOmcqMl`30qJuR& zeh`NGv6R}zYHP6J9W&l+$>z za{j>(EI>OoZ)MZIFd7}2NmcZ$75gJU5MSV!(d_3hARdy>q!AN1mqF4`-h1PVAB3Hx zU1-@Xl#d!XabIEOi}l{e0H=d^K+)y?JRFd~8h)konp(LQHqiU3{=#MU)i4)JSd9l! ztn_m88DUkKteAfl&;Ie^d5nG@LAi8jqE0!itXaVR_@2?7~YwT*~g-fME8!mctDa(6p;40UP{4 z#Yq2SFFsxPgz2BW)d!nAjvn}q|-Of67vyssfC&(+KM(#sbRU{pT;5~T~L z4HdAKZ|u$G!Jr(biW#K0Y$R=n5t|1fatuVB>!;g?kx)bJkaI1L^v3ZbK{=6chpRzh zN|OGNJS2obl!7%J)JP%w$g6>ux5Ygba?MLJn$=7s3swHgqEWdyJUtC zb8N3U@gaORn9`GYmFE_;G5}AEIIAoD?UH+2ZKIdHzAw?{vT80<=ez(2G%iDJ@icHG0nQgUS%1CI!3nOqs0%Zi}3r!SM4 z`*Dz|AMx#R$*W-a*MPNDCg2Y(NQ~@9Xvg&tJSYN4%T1sZ-34ZqI7<*9esCGQK^xF;K3 z-I%ZiHB;g|jTS8gh--)&95)X9t?N9g%Nw)E|8_z25;_I#F;vwmo_eu~&kUXV8S6#7 zS}Z&QzaP1(b%;AQ%6Fm)(~A~@jhNNpj|aeAo8*LtmNUlp*-3hOAX|TP&MnrSWVNUA z@8n;&=qwb`GJ-olid;sEumrf0C~YIkILAlNH`Hpe-jcuo~ZQE&VHMVWrXl&cIlO3B)lbqf6JLfw;VP@8zy=Fc4eO)t-S&Rt7*T3Mm z*we{*{xackXUln=$;4hln3!mDxU$w{yZ#D2u6tXRxk3!Q^}aO ziC5P3!Dk9RYiVyenJb=^F!8MvTSXVQSH!m|ys9mipo3|*27CbHF< z398XT8!oH%g{qnjRxA=$HOZD_G-r_o)?WV7o=B*_b~z7lyJ6&6yd&N=QYQ*|weSLe zWZ3KI@e6AGq3eU6@3LX>$5iee zOVIC;GTSDNRH(qsFce!X!Ytw0X zlx!`5Fz#e&MjF{ugDYQbv!LniN!4S9yf08ws6YI1TRfw zLkLItCu2>hAh-A@K#5g0qh|Wsg&eHFDyc7cIV9h}{MqlyXfW`>-^nW z*3tRIvYzx2k8$fWh8O9aqOTOrTRsSawEbfpr!O6*HD7{vCX%X@YFkt#vTF&!IMG|Y zd;ANlW~M6?cUG5tlLSEg)D`$!EmmrkEB0Is?Ij`-*tr;M@J zapQ$l+<=X`Yt5q9$JuCd@v~n&uU6OZI(t%91-*jrfX366@uei-QzEJNAedio1e4)5SG{>fYjSRk+UNh)H_w~```n6g6PGz9)6k}1tp?l4OOyQ-ISx$(orag z*>b}uxkZSQmAA!hF`lgm#8y0DTKM#;OG*B zuVot6spoa_=D0=q?}~&R6O$A6mXV740rWIEdu=9Kdo>?(G|%{Th#E zj}vgc#(i`)2%1Tk36l_D&#}O(t=D5x-wC}@4)4H{*VXQaiqGpm20TML>AHbEtC*i+ z`GP}8R^~U)yH+pL4p5f-zbK?>n*8fmJaVbFoxKlcT6}%M-oOj6%f{kB@w#L=!GD9c z4j`tJcy)qgh9ruR{Shof+IRGJ>P(dms)8PKRrfD1M%pQKv7(T1v%lS(1+b=x&sB6q z2AJT9Q%I7?;Gmpw8c3Cu;e#V3CHlzhmeR2;Ap)8btmm;<{+MWV=wu-~$Kg~{JPjA( z2xSMNI*6HbS*VwJnxRoeFdVF6yB~QR(R4nL)9})AJU6={H&o=c3 z>U8I+cGcp>!*dGp*LzT^m@?$0zD<5zSF-Gx2!i`tT!YX2SwW$0W^=NjXxvbPN3D9L-r% zz8I*S^6XQ1`NDhLtCZ`98)K{7w&-qoV_&YVKq2euJ7UV#_)HPJ>Lr&W-xSWvY~(*J zBD}{4kkwD?^oY}siNu6l*}Lzfgu|0vPY?>B96{;qdS1uKl#j{5?&YD=9vo6@L+6(} zzF`bDbUsTt|1LWA|0V}tF`QCU{%%MriC`cH%tk`-$tQ#(y8brh5dCwhyNH~}5;_vN z_rCp*j{BYB09KkAWXL#;=*NIV9O}blU`aHl32fLdDT5h~npTu4noFe|N;k75>_j@Z zq-IAHBNj&o|9!vA1jt!MS}{b_I~5ch4{XJP?8q9qHY#vVktvv zcw@PkKt%=5J6@kh904bMM{Gf6iqMWyFtHqL5pUy|q)6*<)F$j$Yyq@s43|x^z(}Mg zH8&P-BtHpLS%sPp3h@!7C36=SlYEeo8tls5fWLNF-$&Hjn8fF;**SkLU5xXvx{q70 z)6WsGw7%Su#&?ecaY{?dpQb;9I1jQpUI3_exBbO>udobU1I-N5+B``eTI(&_~;#~5;pXYtTMOY`r^d=XO_p_7R3Z7u75kCUm$tbc}-J~@!@L&Ph$ zpYIPz?PoMfK|x*+`fA5{EG$~#YWye&1Psy3S{N^O9UZMHq^Ka|kO96@q!fnNi^aZ6 zstK6~x$Yls!HX$|7``ebh`>#ZaU0K}7b-K3jtQ6+uZ=+D)|ifuXKuHe?%U3|Pn4<{ z&#NysDmZf_<9}B>^yzGtN?`q?k-p3xfJsBo>LIu*?! zn@!V4c725c!ihzm0jRO}r584a;nByB)Nh>In$um^o5AkswKNOGOP*9Cmph{SfV_7{ zo49|2@tFF5*@-W1zC#<*QQyxc)nJM9ovBPL^WG94lF|lK;(tngbm!~xID;(Dt;LMO z6w0vq(rH21QA+q5k4RnQ@+8orWnGVwR&--dUmG8?uc$c9AqtqLWP(efs&4u?3)_*Z z=enNR>qJdg%U6F$qm6Spj=OFbm;D(`BM=qI_o`-MZKPk(*$o_)LUx})S6@y3%JWyK zIevt^cUNsL!$>qy;P4jIhFq zM^sRNM1D+vWr8f04q2g)B$P5EwRz||_g+<)kRnP*SFoTB6uu98S&&->MbcU#ZT~H; z%`y&@L&CJw(c{&=s1|~v<%kV6?|2#+V8iniB1cHKACt(d5XyF>rTvpQi+O3gWU=(} z2uT5lN>Q?KFXY;we1*G~=AA{v!CCKa2SqLQ**PHe6+J}{4oMqd#o{xKQuwqmM1A!~ zsFc?N7=OQo6Awca-waUfbyb>c`26%5e--=n({m{6zcpPi2L&pI|HIC7B0>y+GYo5J zYFHWaF%CExfBD@Z@8esm_(QmtrM6LO$3=n(Qy8oW90$Me)c`S37|bN|`*;0^@z;HZGA3j4TV~O=W-eZb9&?G+OKdtG-} z4T7foUOq#n8wO6bL@5|T63HZ{N=3^Do-4E|0d&7Re7^#3!Nynz80|wW0W6dxM-9t! zW>H*{O7S`ZrLvP|0&STs!sASHX-O(X;Xcfi$&v6LC|?ct=6k)2Lw1FTx}3Rulb5N7 zGL%{SZp*sD*GbXh9o7=Q#-)=$n=~GZtge^S-{2jyZSEFh>FpW5%E|u_^Eqxy;a~d2 z^8SLJ(=)rsJkPh)*e8murvKk zanNt;<;XhIt-)S)8!28w%(AR8-eRyPdIM|D^*&{RyLBLKvB7CR{qyonz7NyI{0r?r zyHYHV9E2c>$UT?n1XTmuCvpP{Dj0EAo_YI--d?s~hjn@vAI$(*UV@V9jY^ZuWSmR^ zEt|5Eg$xrnt}Y`6RV7tTMH*ndU~E;R2sl3dhG#;a$W|_~k4|9=a2I7ZCDlco%fAI9 ztxPCnVOL;^r*$N0o6}Es_vql7?CQH( zKi*qR+l6(6;mBH_l@sdRneeG~$z2)gVL;hg1M>p>i?=1m{NHE&hS647gJ$;&RVa(A zA3_BrzAkh{Z0zUaBmoq`Qrjl8SR_g*eeghsIx26F&Ybt9YW4S- zr#xHlX*%Y#)iui6xkxP&1*%f8dOOD)!y`Bz5F5OU&8T!<+5B? ze`7GdHr~3AoEW*hdiQv>h?h&)Dh_-TQ_JC* z0b^gj4EL;`Co))P>Igb`c7#=UYz1#kCahMPxAn3%rds~C^B7KDqIIsmkaYFFy@8ve zcaZ2jLmwHo4K|3wZkOw+^$zEmmE*>;6mqA|@p%uSF7+>|C-)l6J6lXtVDQ0B&!k;2 zRNAhinQW70jyzu785)Z^ax{wme%9!ZV-%v&jfEZt*}vez-ECMYpgmx++&{?<#s(0> zE|yzLFCo<=2*o<(8&cd1Kt(uFF%$LdvfK~Ck0XU{;z=XD5Bn)54Fj_Q$)zTwfP<2+ zep%0|qB}@~QaLZKz&V|%Bw;pRIew6>W)oVYKTfDY1}(g*i9YnAL5;15^g2#adwMBj zk{Tzwi78mKfM!ganPhv|OMj1xUVC$|oMU_U*SlKmk0QC?)NQ%8T-#I_1qr;^P`UnW z-fxcjDIN$P=Hc<hro?*3EyJeVom7{= z9)<{p3q8ll|D0@c|Fr}z-Z8J{M9-TJV1!_)zkkQ0EVH@(Lmx1xxR3GttkDYt+RNic zo0Zs1Cdg3j!f|FWY2IZ;(bUJy^;!hTN*VXVsMpY&%)YoA8KF za$>sk&II_ZY!gdQB|RebbO-hdqP{#0w^L*zM?=2b*Ha1K@!AZ z^+F`VTUSptP)~WcoU1(}1Yf@-tEei-FIB)I;LIvu~y-Zor>SQ=n?j-8$Zxy3EtZJFh2x`E-EU1U#-~?Cwh0oc&>zHMYK! z4^!q|!|)~Ex+n3g6SVxP5VF@K$g|RrGi~}F0e(%YT7})4o;#wY z;lzn|3i7#|*B`i5Y(24^g;l%jSTxpvXlibXYYa*<3tH*S#Lw`&rtSP!(LpCF#~cl! z4c;gI0Zn85; zAeX{D4f(m~0liY5Ks1vln+L<$SISF_j9^!riJG@-LW5`7&eLGmb@QCqe5!9kYi_do z$=R&YDHWJ9Wi_f~*9zF#N}}eC>=k9y7l0)yaxGP-WqVeaA!+i4NQ4u#hk^kq;|ctw zq)sa8smkF-mo<(8jwrZk7v1m@qmqk^l;nb+h}d*1kYZ-cZAEi1FZ4jl>zgT_s2i%E zOQ}AFZNqCFI*)`x!RRsRWr>;$;_Z|2}(vG^FdmSYSeGBjjcgY{ErU zo@v6!;~?J}siv!<# zpu2Ehc=P!c+-mziYE&+{?*{rs*#*PmzDmPj(m*7|CthNa7~%{5Qp2`@46|aUDpR2w zOkkJNH|A#fX??@Hftn}#o&vqgS_sJx$Bdf@bPK!^shp324Zc~E8AznFDawPiN^df6 zah6v@n9x6m(Oi$uv7aC94L@cizeD~DasNAu0G+&vz3~k_P||#Qu}7d_LXl+|{G16= zZ8#rwK=JY-+5Mux*R}7ZZ#OA`i@GI3Zek;(q~;ixbRx7X6`vip4xPgTAWPA(9k$atUH_d4bEEe}2RY<= zgs;zZhC4%nujsHTZv{5?X54}Y(l*(EB1HZZ@1OTtA$vCbH9D@UCaKNuJD;HpRIVN_ zSsbA2{of4dANCF-^6>!=;-FnWUJY1%6{ z>7;b3td8bHw*T~4lOD)yzCNY315|lU(d4`6l{c$bFx!}GVaQZjK7e&caz)U1-y@NF z!+JfQK2b48|8`5iTl4&Y&77#H>?jF#^N0t^ym~ZK?fE7wX0>$gyP-X4T8EuCyu|g! z<=1hWZ+)>8k-$+7io~=>T|lW?aO=!PHFFR%rVt8eG>8y)C#=RZjDGR^N;1h=iMoWF z@Qh9u1^E&8wU7HoP#Jw}AZ!7AJ)+NpBtMg1#}H0Wj&lT2@_E(76lE`i>1hcJ$~y5e zW)O82uI-ihZs3$PpEK9>6yn7c!UhfOS*{%AYWxZfpVjPUsAnH)09B1+?LK;R0qvu~ z(O7Wm@NsSzb-Qj06}1rth@R|_J--}a??o3{AyVEaNUapsy?IAK7*@$nf!KIVrTc~v)jloFtsy=Ur8VUPjWnnh4c*rG(R5N z;;4UNf{v}Q63d`3QR0wQ--@cabqPQVG`$hIT1YiXm~P(kn?3Rd5{$B-a&B|eRWFL+ zlhxU7H|oEg0)xD=gGFEAzynFghvPM2@TH% zBEQ}hrClv!b|U!Moyf0dM>r22h|`)_A~IEx4({11GCd_3W>8_y9-rM^Jo6t|z7a~7 zdGX%B#SrH}1ZltzYiqd<{QM@$sSGy6v7-$4+%gbm8-qQRPzKqprQ?Yyz_jz~llKch z)NrF3`SauJ1+wAcqJIJt=t(5}FO_TVIH9ZqYj~JlRrPUJ+S780VE+8efi4EVnxFDz z3&R^lX2oSbSM==3`}Togj0mGdOhJl};Y^1je7SU03R9RJ|L>4L{%axvG-c#xIHAJ`^~VoG+YJ{~=%X_++hRF*D8 z64Q+*Sr(md7r&*;C;~9d0=W3_H8j`7nbXGlTip|NZ)je^=XiQ#{j{BP>b;OHs(I*% zVZw%v+AfH%VY70xC|c`TQ`$nDlu&dKtA%>0pj^=~V1hDz1}~$;Bf5gPj$Xv0tRo`$ z+UIu?B6Fn~!X7m(Qrx`@PruL?g9NvgD=+aSqzRZUI}B&u1qGyxnPaD6xAttZm25>r z7hlke2&O*ly+&rWQT7>V|N6f_J??#sSbN8^U=n!s1@pabbet`kg*Ee<&XpFADs!`^ zpPbdvV`U~VV_%gYPGm>E^x5#O$>NMe^LKuJ?)3fwtD1u<%>pqGqT{BlNI?WqkjAu| zfgLaUmoV&DA7toI>UZ;n1g)5adJ{1g+O<-BC~u7?lxF#<6%|a~2^q+&gd?5ceEB3+ zPDjthcmRKd!2nK>GLeg;5|?yB6y{+tA{88qBi$;LIW+)>)!_j;lrhaeHba|&j%!45 z^t)naQFPrlWF)ocj}k>5rEy$;DN$UUnhEXfJ+h#g z9_t~V-GPDz@mrWXqND54tFB2wA9^0O?lBj;CC zyX)Dd7xEscC|2K>x6inTeg!riIsV~!!dtz}y)ReTTufsBxIgZ}e^r0h1zaHGo#Z7X z(1C8FqO=`46H51WZ5q$_yY}r>F-)sqN5OrJLCmT3gTdX^$dwJHUwpqUBNs`CZSVgO zv4DV@I0SB191`EF1D=*IT>IhyK6Vz3%hVYCI#7#)ELP6r1&t=rbCg{x`I&V}ws{0r zfq~zsL}$f3@Pk&=p2QS!rgq6J59+>V3u1I#)n+x1NB3({5GaO9^CZK6O~n9Q0I81e z034xrgy=fH+Lf$31T#1b%gOg%C&hSwe&M*Hu?xY?IXn_*7s9u!srTbPv9){9 zsWEJ^z(EL2-l8#I3j= z*Ty@v+RA-!9RI(tr2fCKDJB!9@FW)(&3^Of2j~22D-lsAGC@x}F;M#DXc^UDNn0^HISuFWsTmXaQEl zxsriq-XLva(`W?Sd9XN-pWb-!;izg3vDILNQ`>O?wKbinmRfLCMAr96=BbqAanU~Y zBW~bPh0-Ins!Wvd0q=z<_8?d{XCxT?Uk4Yit$7hc;7<}=W`5rwRvIax153EC?&DmE zHRqFzd7;s&M52Dx9L$jBdqTU#=M&#|weq*l3NV|0}T7@w+g*vz|Z#pJiK)BVD068ma)uMCTEGyBb1P*XuJMlmLQ z?}g+v>Vckfukz7l7qdU) z%s+BQZ3`hpJ&ld7_7oP4t-1Dmw)=Lj@%^;5t0DSf=c?YKZS*thrx9bK+{H>F=~Sn} zi_!N6Tz=84U9GGUt#jzISdToZZ{V`##F@erKN)gRPH;jFunjf}k8-it`?cNhrsNtU zGMn%(lhA^Qic#qzVeS0J_e|c1Tpp}De;)&H4YCy&-HyWtXR?;fANT%#`l37mz>K7Y zQ~w*BO@Ru8p!cdrM3*|^`DamuLS+O14Lh#Y?t(4aVt>>%=+Bc#FN8hb)Ly2Yl^OJa z7$Od)w#xMCtXl{VZWS3Z_jz$My_6kvQjEwV1gbXaXxwGMw|=wyNhc^muJ#k}TAlCa zo-tv8=1Zc$RVm43L@NWejVE$AXrIz*A=h?Mf4EU`*t|^_}G~e}84iS8J zDW`Mgj$fc`+j^ctm)L5)z)$atl6tji`y632>YF5SeW{E+32&)LOTedtR^cVPoUP71 z+q4wXE&+Iwi>6WyN(;^7_{|;kwXxmNC+69*oStZ}L{U6%zXHtrEF}le^D*4DUu)-|5e4t+EVT>K zm(h4`16&2<*@d)k8)>wwf@|({%8Inu2!UMcN~}r7n$EIDMjLFZ#iHu0?YnemVvSw< z2&J5y$oQKu-v08_N`BHkGU_ApIaKRBnUblp@?XC(Q1{(8&`D_&(_~4u>}2AM4K%6d zF!rwFU-4}=nX z=CSV00XKAVg1zH?vnFo;v6*M(oP(DX3-kR0u%m^v$vTwxq;W~AXtqfAJCx2&`-&Np z;ni#?m9rNb?l_3`t<3o!=Q2S(07<^6#0*L4kEE;E$T23cn7;alo8u7kt;>Oy$CVA` zYl^7@dfZM99_h19OP}o?&~AcaSPzVN99lK&pTHybzaDiks7D-$3F{)k{FmU>u=M;e$gcNuEs@t*9eKsGw2V zgtJ-}Y@bM!G-s%^qiomCr#8-Fak*%6WKacXF(>0s+cH1Vn{3p|S!h0PeclKhrARP| zCJX||9E^q{A>Y@ixDPMhz{-;;2fFaNWIFA2m8v*iOZmEYLC_Z+1{#RyLJFT zD8}f(9#0m9NO_Y@0e9mYa)M zy+}cmE5`P_B&&V2P`X-MpR1DnN=#v6gqEz)#Tca}D-c}Q9H!X_#0mv!-KuFNS!GNP z24fT|kUl|AExHNoKZ-q%HwR+$H}>y_B{Zg~m~S59*#2vH?k3zKO& zTZZQ|)vx{P46OlnI&S<5@Y!ghV{y>*rb^lst_x=z7&(-kX6mJz*VPeCJdL$YAXQgg zQ73$BtfJyaPeSj*Qx?25*Plk&a&dVW8Y;~wd?MEhP$vsGgt-J9I?*>Cu0;9py&`yM zqaW#116xrx({OUAO!etnF|b!nKNEAtk*Ez@f-hqIXUR-4 z4dD3+49j(R)$TBzZy%3PyI(u^5T5O>pWmcEmS)&KA{i(+z4giLaJ)LVIYod-fBs&5 ze!jKb=>IV7`O=Et)s_i5E{FzwrED-F41v0Soz5}o{`*Vso8FIkdGF=s? z0C`d-IXbC_d*eDf^vixUe4l2kxTpOaGvY&uaY3h{?ld(h1v7K`#7)Tvd$yN+`Ln(HY_o){I!7Q)4x~Ge702WyT@aP*?~eSjLEW zu-7Rx8CDmBYRP&;%T}hOZcB)|9Z^Do{3d!K@qiK^-mQ|GeR88bOFOYU9iEsgSl~$I zulg^4aL1rsQ6qQe){s$81h8aaSq^$pyL9)bU5o0<^l*#J9ntqfT&-8B$avq=qJh4W zPas0Z%`OS=HRe zRkJjE!HHPaPhtv$(`eGTtZamb+3?D!-C+97|d}WpKMsiciqJ zrBDGnz?RcvbJXYovZ3J;Gp`TWf=jQt@baU&g8(P9g@z!IFu~^k3lo}#GaJWCb{RH{ zpqJ2U$OtO4&bEVB#PPhKTBgCetDNfcg@)UYH1f#H#33tzYZh+^zapDMFaXBLsFcBY z7wqTWudZTG$b%{JKK-inw{>n*f_ny=n(R6`j)2DUgk{)lEXh2z{MSlBw z>h$bW*%$e*`uqh_$M=-v06ex9@VBFU^ukgN>rJC-{*g~PhCS1Pq6 zXfi7Yg#|rmvbOwuZU+hn7ACKA7c(J(C*NKaFggfS^DP*tHmGTYFQ@x0Q#?@Pq;{&1 zmz1@$VCLXkB>aK}CoFuH%EOfqW$h%t3?(B9WKpul57O$7(uffur!wcd#nTl}bsdG$ zv#f9q2J$)u+qBtq)DpjqD(Ae#y-nPL70qka6#vHhN7)B>WDGC2_8t%bl!Hr|L$vM@ zwD)!SGrR9v@M*Q0IGb9pKs?xCbUTCbYlLX)zENYbNd>q3@x z88DQ1(%Wq5^)MU4V;d`LSnyqxUGrc*pA6;S&1S=R^I3kY6^)ENb{$CKbN$YCFc2nn zT^^rnK5XA6Zn`u%ECQ~x&TG{h?kfn~E%IMcV8+lxr>*I#M~Jw zL+TuKeW8XxD9V?mT)IL}4% zy#QWMyicxM@l=N!{TmG&EL9+i5cm-!k!%Beqbjw(v_%jL*YFpd>M*%}Ep3c3Cf}=( z^_Snd*uH!6O|$(imo%5%$Oz%bS|J*t_veJ6OJGR?2QSeY*qT-MypM9xJE@DK41e=w z9W<@>wBR9UX!M%&!k(_dx8>@@s4Ow`X>j_I9%iQ*I2Y%#3?-9otX4 zXZ*htVLo4M#@q}4<$gc`zJDMSQ8(XUaTKeEi&Z%y5dOK2u^&cd=E(^^c{TZf3gjOrEnWmpp)LoiYB(q1913ZM0R18F2c zby}8WA4geXI8JTz_x!L^1CxM|V{hDQVGNRAfL3^jzi0HeVL(|my0cBG(h2m8h$Q@)EKjQ*Fq13R6c0E4i z3ixz~l{#HosHAve8h17F$XYj~|LQHVz_YV8;XIWuO9r@QCuA9sm9#vti~WrKOZS0E z&JVT*D$Qm5+mnLCNuUB%&>Qd2(+Mb|iIyvOQj?b-M6tSR9rn%Dgok@;1N|2@ya?NG zmOqUP@GN{gf^FK*zN_z^N2)F`|zcA zF4;X$Z@toTT{G`buE>;4Vq{4U_7nQ06x+rvUU@uG*5?zXM#v zn-mmoH67EEW28Dlei_&yoINau$$%!0Q0t8n_#|*0K(!ZwgY?Jm3f*Vkp6^JZ1P6xg zgr7e?IbK!{uOLFagR~R=-Hhq~$hc6ud_DWaYGuiU8@I(33b-0LdoX#wujj>B9ZWj{ zKDg1t1OBEqnYS6&67f`h7UZFX=?CDLH**mx9;(kJ~g@Ycc zzK1$HY>@n@QHS5!Ums!{sYg0hKx)vL#(*Npo>4$gl5%MZd9Kg#GfGlYJ1_CT zjs1N?jyOQR>H698j{o7(^a`28AE=nA2D%+8vauWNAj+n?jGb#GW*PE^V+MVKFnA-Z zqr}4RzS#UJF%sPbE%Db!T&Z!R1;mIm5(n1nsZ5UV$^wwV(F$ALHKvu%C0p0^)<_AJ zfy`zt2N^9oMn1EIsUywYSFJxO^)7?9uagx+bVUVH^Uj~DHwo9f_{+BP4?3-jcwKG0 zFd*ZOXHRRcs4o_g@Cz%ooTW~Uhwzi4%Mj3w+h4wX9Yh&|^mPwK)eG@>wDM3b9`5T< zdUgEkjI6rVtU7RR4CuK5O$Yumt|l?|T9-mZz}f|yag}SvQ&a+UB3!vHP4B?~> zX3D77|LYO+9?<6-y21R!q`XZcO>3*`E6VEt#%1dUR!UL^V$neRM z{mqh$Gx0cWfOhvsA!3nb-89m{4Q#VM3VTbWDt4=;mB0fBlV}|5v$ys<k3$QvoA9A(^A(VAjw&i`(YHHDj8^+L8nxF@W07yAI5X`R6ADQ)}l^GID$I$+K} zvCAGg9uJ=vE|~~wnMrlEvhWkyWYo~WHP`{mHP~Z|E1X5JKH)WnL33D@2$i{@KjF;* zr;=}-482GzL@-J;%!qKW3ps>mJa&`WS$cmz-+(*4pY2Yo>UNg%1iAlxnRopg4hQ{H zcAUsPt=}R?e8Yr74CC#~=}OJoosPeRy?fFD$Hd&2lw-;@(=vn}%cypn!)<`@%9Tk1 zYdZE_c0xG;*yB8S~Hc)2EAHO*2RK5bl8|DEW!DP+_H~fSM#1g0=JjtY3T|=p_TiGcf13s(p0<6Jar^?a9zZSe&+7bU-jVBy6prHyfP-D-HwUPdX(9yUE32)N`fW&gGI zcW9}CdPvGH4PnLO1MZpFL!d<)&MrDb;AtH#y?Mk9=ic$2IMffgLh@F5p!MAiK_yD8 zdhaZ|><+8_t`AteUJP#vJ`x(<9(%iXx6)n^!o2@u~!Ao8*{0`&$O*!A+P-g01+^iF!t(X zj3A&1#-+{clf&KXMpu6313Zl8ojeJob%_3dZIf)H2}pmaj~^kZoHiMdw{R(k^H>B* z&}0KQm!y>CN*)>MRAx8FVvt!`VG^TG0>>VQ%htwiaU^LXn~72U_9LxGeK?2fhDvI! zafPHqG;#oHYkNX5Q)vS0GA*>V$ej){gQz5LF}SI*TDq(@OG*49jlcGGOoe)ut^iGwpZyr$2pPP@JA2w0%Nv68_ze*r|WyzJI~y9U8T@zcyIJBDGzO z)beqI>{S)A3a~<*KG@^s6yE7GFf&owWZ-whr*l;37*uK(BViRS@!9c*o_uLZ->olg zoQLy8ctV05!iX8U$>j1uBPU~4D-%&M(QCSB&$>dTWk&^^s0&1L8965bxz5AKjAEyR z=%+~HNPEi>r9GZWpnYI$!YM-LpH)}ic{d5CF%M#MUB7U+BadxiPWHb0aEg8G9rYyy~D@Q;o&!! zNV}q7oUYQ-W#k(R_-vu_Nr%urdwzCv1K0CMQRpzBZhgKcka;0{qB$~m;%A}t(eSM0 zr|Lm*Jt{@!eP6e|h(g&i33w{`%1uGRCq>poL@|vu$&Up)d?t6%l$g)jBC`A#@Un-Znlc7kd9IP)7#Qa2kZLV?3nOs0bSDm_$mj- zdiALJ-06aex=OLTJvz!ANmyWT%+ZymTt)&{J3H&lstZaoFWXH4UsFe&oezh9Z8H7w zSDz`*gX^{J3fhgojJrE`yjxGv!hX zRI@8QDyy4{tckf+N{Xc@7m`Pz@R<_i6*e*ymZL8u@-H$fR5!+L>s83u%8JVy8_SX} z#!L1)55L!4wyQ~3(OpZ0IB|!-&Tz`Oht&2hKq5PI@#%syARzW(b7S0Ji|-1t3rSE> zzbG6JIpaX5qKUe5?T-y~`&|bqqVviec)GU_lMD_73)lviac(Bdk{eI}i(5nAC5RfZ z2;r1%kFB<4am1#&^ulB^#lP9MlaV^GK(wYN(HrQ)Mr z-P}K>Eg{q?^?D~$=QaW^dGna)>4K@Mdh|}`&W|qY<$<#7Y{eXe%tj_%;HHL|;tvnWl|NAkMOKw;=820mFKmeTi*=cpq3x~H^bJjBJctG2v$q9UJ4u~VeMvGJhW)qQe@*IsiQN7 z-p*H3Lufnh#qlvg@rP}k$T0tQBDxSmMvUkrpN2yt5i;X%`+A;F>{P*u+z!RTKydOl z{_pd|L8DP)=k!nvgj(}5a+(7sB$eF@?cLu@TcJ;*QoD$Xu$^f}I(yG;@K`#lRve~x z7BBA8$yc*}X@g7&fM{j>dsBdt<%YD1mS7;X;^Gr?O8>uI1k->vsHrY(vRbv$vG#76 znL0qY+o*U_53U0h1~mK<&~NRZKupAyZ;`{$Oh*AVh~MyO^2h!7eL(r5l_Jzl>?y!&HpI9#+=C@|RXf-ChHbm^5+NfMCN zpm_7y4uvbr^JL8NPaP)X1{}sTUKb#jY2cZUdSDlt`JZsIZlf{N5Yxd)_BU1_78tKk zsV%-(^(6xlFp@=Zje%M=;7t(->$75aXq`VN7)!tYAEw@cv92!c){ePjt1)(LJ82rTv75%WZQHil7>(`5w(X?R*?r#c zd(Zg`bIrBpTw{#;8dVA>7~i;cY#42aefkX7l`?WfDu%d$Ny>_d4C1Qm<|FCq+}Ssl zAx}hJ%rygc%PAe)9~-(_uY5h6TD+!+J=nqz5lJ$^PLpx&<93Jkz}9e?Uv(n%c-2wv zX|JU{5u#IWcl(U z!#|BhPps!I<{>wk~I}q8Ll{FuYp}-cX^Vs)8x-pf{z<>*T_*SWG&rg1zx>bYX!?^wFG8Q(4Yn@+5hAm z&=v&{P}%40S2n;c)%uOgiBVN&{#;~CqZxK*H%jPAS*+_S#Q)L%IT(70Ep*WzIh;!K z-xn};odf{-0(x03q=y9wC(Kr?suVx|sdz;MaKqF3!{JU&bu%T_%vY2?3=&_xtZXNQ z87R+*(-iM|%!q1Dnp#@f!qB;wmgKmqRn)YInL0%lo+e|9(wSRt(e}eO8x<%T?Eln4 zmsThw;h3MZdMPiFY2fE*JnnR~K|~W87wt|IMj_T^h=`*f%48-4!C0bfC{- zg>NsSyFa8^ncNH{?otD&^B^Ze`v|*YTiPktDo`1n3>7b|osSvohIxfO11zgC5mM;i zHX`d&@#6)C-38BH58kO?x^Hw%4Z6YM8y88E{(BhXHlS-l=NX;bRSn%}3b6=k(Q$bf zyV-AHlrd~FnHmbNjqcb^%|>B`9Z*RwAk;uAtS8-YBps^|J*m0OskTGpdXu%$1Ak54 zbrBF){~akqr391cq-Z!E&)DWp=5VAX-Q z$(d|*lx9j(mwg$Wn(V1z07~c};{f{iupi##T$87lLKREv(9H4jITK2c+nTCxqA2AYtzAXNZpzYG`O-g3kVP(&Zi!3vODergi+XGi8n8))z0J=$a zzJ<+{x)f7?=QtktCnjKJPHf+j_#}^(r&?-9?B|~EZm5s&CYbo( z!gJz(j@*Bq%K9LX%`v_nb4WCe}IZrW(wQswwx;$SQ+$L#;7h zJk=gj(d-3&9QSd#WEpEpHEAizq#6d*GK-bNPJ;#uM9_f~ZQ!1qT18_lkz6G?PxvI* zQ+-P9>}TuK1HWk4rps^3-?aQn$|0D2HSHf+6^E6`6NnO}_QPwd1DB=8rS=QVb9x_A zg#qf~Tq_}CjOS^;jg+DZ4^FZl79CKep&tAGyuH-{va{pSS7)jGsjh3)4$dbgCNE)M zVv?wgsLhnrBg`|XHZ_&bi=A8I2=+Lu*HCl@wnwk6Mk*(P`WfA8tB364ax#Z`iCmXa zmOE<# z^7MQSG2i(~;Jm0rYxW!;&S1cOB)^^#ByEoDjI!&=ZD)9on~LPJj+l#D)_bKlLS`?_ zcMLD&DOn6kPq-W!;0IyN`X3DhSGc+3E3}cLDWzEHMBDFua;4i^+|PIr;1Bry!(Tl@ zsZ;VKMeQO4w|#~5Wq-fi{J1EvGS@lIjw+%!So5Xf0YUEM@1gE!qJ~>eA7rB2E|QcxSK)#k_g$( zWBEIygPNw+MlF{uU)kjk) zD6UeWpL@8&3;I6BdtnN$;01^@1`W=u1oy*ttGi`xXV*yt=yt59zURspf4KsyUWeoC z4?!_LFP@jK7o!`0p6H1-L7Jlb-gmDmO@2J@VRUXMSd+v_c_i0rO|0<#d7WQ$4vT&t zN|6Z~Y>QTubDU=ebiJw{!$D@+pL=o3hML#v7|=Y$Sd9|25O~%T8GH(yBsd(Gw@cy+ zbWwL@r28up2;HmE*%rH0HT^i@Ek?p<7*MjjB#cg^nv?5NUUZ>nh!+=<+#A4S8%A(A z*TnlJXU!*Fs&!dUOjSzc;UW>^AuM6xY&stlqxmkO|2V_ ziMRIDxYRrkc5x=;sIKCQrXfaUDB*XOHbP?(z*7>IB4Hu-P z=HwJ{hI(_0{eCrqS@MMfF45*}r6y%Du0~}$BfITpLpo3&&#B&h#esHB6$>P>);e;a zT32!e0qdWL5^}2~&ObD)YK5S(o=P4(LyHv_{zIVn@=n4v)K*|Al=@9o&1YK)Ya^8Y zi6YUJpjdzKvGEcI#OBgq8uIwALkZj~JTd=U#Wt7WJe0b*fNf2#H`cBjOyiF@4xGAj zWAHlNaEW_z5d=hk z_ZLS)`ZL)T=xN3;D#1_3hk&pvP&I`~;umr(|IyH|zONHjd%K?}gUiV318sQ}k=|SeLjsSVqDWg)}Kb3Z}+wjBc zNzf1~FLwQ{+I!Va=yC!QG1`5f$PK(sISt zWVZ8SjFt6xi)Pk!V6Mr&`iq%r(w^|J27c~`2f^E6c_|uY0f@j`(d#HvRe4dVDP#3Y z1RgS*u?B`a)~~AHvwP_G#Es((bI9O1^T{!Uoe&T$fDE@8Vtq zjU`x1k*2js8MvWtB04L?84M=R;0*LVPv!Fp z01k|gF@5Jzum|UGt7YJj8w5mxUO&$nd-g|$J8FetXTH2uC0*VRMjQA?XG5Jo#wU@U7AZ&qmZ<|z#1pa`{0ethf<8?LdV$o-UY6Fkq&xY)RC$9%vo z?-+?exM0cPvT%et)8IQ3(JL49FBKf~jn4aZN21Oge`X)iq!l1o0GnX9m~W~VJ16Y7 znTW{pk|_X^2Py{{q7Yoxx(}wIjJ*2U80G6mqCzFET__ZPAqu>+xB>0aO68nR8whHp z;f-F+phlZiEjE68`Fz$sbKU3)`M<+lxj`t!{TF?j21TDhBszBlVv&m&6DnV-a@u*B z_-%*+6hD4EQ!WcCO=H%igA*2+HaiQ(m_2>LSI0{689Fh&2dcE$(9I~3lNE9;OW3Qw zA_V2xLthigq!6XK%(!@LM+;gKId-Fx9UueM94h*%lD+_9#@xGt%(JS~pH)M80q;S* zwD^IIo9Kvc~Ms7Z2R!(GojSh(>=IhDLQ0iUGB_iW1|x9DF}0?4#kjB zX|(Bg36ptY@2bE&t`=-zENYK9$?j`Ud^3aQFM(nS4T}D9cY7&dK&$iDpCiS4Zv~sz zh|d}z!Z$1Q=-Ho^R%2`mY!6OtD21lA_Oz(2f}1!`{>zcp|e6| zxiW$*^&w~i52bv;&IXvUYnFzZzsX8GZ`fWxz?E{t6kSOp=aQC;L}+VNgRA*Ufl)oj zC|O-4VovjGP@R^b43%OCnPDugU~(0h{hd>16q!dESu4R&l&rK%-3-FT3|(3Jhp+L6 z5y2sXLUFEFFqb||ca2l+Uri|r=Z zgZP3EFMsBMc%=WyH`50nGjlmHvV11ZoZ@`9bT&CkoyNv)@6XA#EfZkkp%8;wWqF+PgFM_4Alf?Gds?I$$j8Kg(N6Moa`0y}hIR%jiDwTQbh=z6kYtlWoJc zwS2o@fW%E&w}PfD)*=~iBwoA_fF^bOGn=+bH7v+qR3cg9VRU%Y&Db)AkC}pa?{Ekv z>vh`Bs{R11O?#pnuS2}YxoV#4r4bI>4Yg2e#Z}zBP6y;K`>F+22HP@@X z1V#*i*SiyJ~2L+U*&lALgZoLgp&jckNQB8n!)z2UbVw0egJ4l8wcu zj<wK_u)X#s}8kv5gt0LxGE?-0A`X2LxLl=>O6KJJ9=OP1yF)5Zw{To(@^%R zFAmcMWcedWQpyMhjg!IUxG=I!F!x&p<5?vZC#PwYN=orO;(iCL451Q^$($!!7fmkK zjq?$B&#x->A1D40uUFhLhmh{`?#N*EPRZ@#oEn1!kN3~VZ(xGqZpTc#bH+E zwYTqD$7gZomvCZ>LocK3|6YZze>zN%s{r&9S%?q4%>U>xa{7Mg zvytw>3)Tv1jSiOYgv;-_^$)^0(rR!%>mPL>o7i64q-a*nQMkFf!{(s#r`zmjEJ`wl z(2c%7*Z&{==obb>KRhECL}(V@*FwoKweV5h10FW@e)xMYt|%q79Q`aSW1XD9e7&d& z#w#d7WhaA;Sm#-)#4exHBZ#b?onm=lS5 zGDeJY@W&<(&Y+VxE2@+7wx!hI$M(3Z=y14mZg_h=A&H}caUaJ!gZp#2+Ojx>DY+}@ z&wr|e?{Y|J+>Tr`lO?~wnLnG1u;J*0^7l4v>x`2P*mKJfy7Cn3`g;EMefaF}NQoeZ z-V7#*|99~P1&|3rK&L0KuNQ^pvy(<74P>5YU(p9wwAnG|M&_6cEZI-GQN*ff#>VK& zLY=0&Xe+`DOsk7$>@%tr`A?Z|NDkZxO*y9cpY1s%G|j7rHGu+BmBIMb2T^L@Ft|Hf zBhrPxViiA`;1AB?4aym5Rt7{&{ZL%Tk9k`TTb-D-m=3&Igu|1ILvH$cDGk~V{neRk zAe7_!cK+kZjRIb%pXF#EQ~$#SVpJk-><|L!Him8NOG8aK99<{~)>4 z$KA7DsImgl44kqoIx+*3={XRJo6^G@sobQ6to7}8+D3@CW3iKbqZmWAB_7^u+jfYr zso9ZV61-y%*mp2rCFdMJ?4XdZ3dNVM%pGj`Vnz&f+^yVN289{7=6TYdA4WZ* z{yJrzPS*?^$>V$jPD9pPa7#I_YNrHAUYl#Krpy*fc>_87HXO{43G#UT`2%igPt(Lg zAD?|FL|N}J^Z1kD$#kGqSDK6gX@0-&FcicyH$Gv~F~!ZS)COW`0g*LbbaD%nQX=-lX_0g1SyGXUupmAM z8qdGTx1Tm$(3~`IuBE_Lo|f=};-`?jH0>YdNE=0RYVmw}oQBM-g*gMWG!GW$^)W&W zuVKd_I) zRtd`PSu|H8-L;p*dA7utBmF(Ed+9Tab=`3U&I=|1Y&%Hq>0RlS;%^5G0)b0%Oq<`$ z-YG*L$hU{j*%U{#SGDUpuQvd@mxO`FpIIUgNK_%`j^&=9O!#f7@FQwA-|<=K64SNs zc4f-Y2iQXSF-$5bhMBGSzt+^U^a_?io!s}YqrhP`>8naZ{$&b1Bg5u}kJpCHd%XuJ z506|GR<^od*+ue5a&&Diw16?ZGfmC;pMR$sOdpS7xKLfXPP|K{9E@h0S3QAh6P=iF zB6yAKT7gqd(d_u13tW0C-=eL%T2^sSq*iAvs1ERBbwj7(5Y+g9*UBYHJJx+$h+aZ{ zC_}Pe&652NyF5N?eR6;C)*^RK@UemIy?_@4$Z2TsCFkD| zQ$}O;vZioNI}!Kb+HF%_)YhVJRqZS(bLOz}9jD{!aH+x4vWTdR+jxuwOHubrSb9cn z1mU_*U~9otJ=KqrYt#aaPd%unn|VX(c@nC1-!EeX!%oxF|J3q+a^|NHokid!_?osG z{~Wqg3TxqJC1@TW6tD+%D!DNx^u#WwL>AC^oRl9! ztP$r?&?*^$gjMP@A8#P_G2@KPY$7m&a0-wPffgpM8eImHu%P&mO+zr3YArBty#`k- zV;IC(4$PFNTLC6%sB93-F5pulwWqPf$;@yqpBm{tW|vn=R3v<-u9$+eqO|7`Aft@&wnfnSvjXcTxHs9`0?CgC^Yxl^O8ffcM&Q}*FDRs+6j&BJ z4E|V5GcNjK-T<8Sg~U|w$Ni~?F2aj}>*OPq$5UR-2hQ7d(6z7~9iG&~E1agJ`*?+{ z){Qy%wDdd3fub&ci!+Mur_ZLnpR`g`k*giK-8n1;ioar@+}CzZ6RTwyQD+z?-#F%`vWcw{hrZ&}&O5x~**9UL)P&|sVFN2FYj<=;D#toRLla|L;A zCuVm!zMeGj#p?SAf8U~!vdl}I*5#_M;uqm;1?&B~oRrO7xb89%#&<2^Ek}@HB*(;yK9pYa<5vhZ;2Z%V06m zjQju~=OUc)@&)zD!TZyeOaBcf&PpvH)f6;B{=K&b6vX>CB&J9rY{-{DsqKJ@$*@}B zRth!Rv5%>^KlXz@9ztqmcFQ$2VN=HDVidcLkFSGm{1{CHyL}`=MLR`R_wcK#s!e^Oa73h&Lxv%c%m@f)X?h^zj5D6bwX z>2a)94M$SbB%L1Sw~Q#DUsX}l1<@F(7ZkM?7HRe|`HprRsfn=#3Af3mYf(2tS>9i~ z-vzjR-;r*O;&m&=>jnD-D}Tw-Z~>?!-t@toQ`8Ckp2aN9eljEUvByk(3q$6YMk@T? z@?HyD*xfGxYtFGAJCpGx5Ota;pdPw z@J4fO{H}V!pKl>c@@gzY^2hLPzz~feE392v;Rbo;sQFEFc9UG+<6&yEmJDH0_C3*v zFGDA=wg5)4kVN#d7##4fdwUeGsi(}m=#X6`5L+dN>tTxE)5Vv^kfCiUG3>vYl@b*O zH9o%Xi6vwB2k{hamG;cEl~YqI`2o&{Dfm|$v&bkB;G&;#?Pq#&r zMm?F`v|UUBbyZ^7(yD~qiloCoOGEFyVQhP^mXL18Bpy;FhON|v=!BUF4Rc~^F6PG4 z`ogsXoyTHcTbOINk;)K;J*+U_q%gxpSQs}j>Y%jExfp5_c_kOdXJ*!)qS?7CB)b)u zV5N;uibv`Hv3xTbH}o_}7|9=G#sA0_|M!@>bM>|}1sSJ3zQ{@|j)cE|chK9VhzkS1ESNln1J zs4ZNZwPC{UpS{#CA$0I{uGSs4hpwL&Cs>~l71_d^@u1X9a=hF>Z}OikO1x%a3bpU4 zs(Mjhs%wsNVSRv`m`8;Qo__N2nvkwKeF1N^_vCHm@Dqj&@TVCm{v0#9!P;{JFl4qC zFWS(2mDE_ZFr#ImRb#EYAXaHSO|cS(O(5}z2Z)U}FC%LGj$iq`+NspC|EIYXtSTv& zvgQv~)!GUPPAz+5S<3oa^D3xIcVsj@lTHse-hMVCijZmZ4&C3sbB|Cb zgA&h+F)>%tyi!WHxiVhD+3^CF2(Bit}QzXWy^ zxX3#BaihqP@H(`RD>9QGN5oQLZ*8yJJK-7fm}Xr*MG17SCiQ{_Xh9Fi17Xv}oR`{# z&=WUA*K>8o=GZk@9gy8n4co{X8+%g$#MwpOxYzoe$c zMf3{~rb~=smDF%yf#(P3>V5P{=x^Ox%T<@}&Y2aeuz+*)G@IqRA&(8kZ_csvkC_!U zcpU1G7pp0Cm*qxM{Uxlo9V^NmY(@2JRvffCe>P#=R`+ImQ$3%@aKm(fHQ_s3k z_NX;%Pb+L+b$`C!@?Hfq`5!tK(X->x=$e$%rU!r)Y}B@ z8ybX}ann2q9HR2}?3>Dx5izu?=k1?C3V}y9c*&?rbclI{zVxos~}VWCi|gLJxxd;ELD?# zSv9V$bNV;69#Np2SD|C=JX_%1Hw`jKQTkd+o*Oy?RMWq5Eq|oL6*#F53EnLY~1P)_`RN!pEnN!no0jJuLeMwuq!o_K{^?PCub~9(F<=89?J^17*;>C?X|C`Lq>h9X^U z3rq)^`*JTQ(e(5ORR$76zfk}(wi&-LMZTtLJTw0W)9U>S%eQF?_WFaEwB4wV5h>38 z8=ol%tE9;l;F>qRXF+6?OAf#VBahMwjDBgD!z4`Cmc-~?zz}~Gk9%k&q7SaTK+l<( zDl-`i2N2B|k>OY$Qu#_{&PF4~I3b?>e7LurvY3Nv6Vtwzfp9WyjvVz0N{hY!4yNNf ziF@{F_lPL#R)ECsp;-2`ri|I(Ps)ZWkI89#7%Brl?J=a{bcJ3ecpgdMcclsG<$|r( zfu`R&cgUbH{Gk^AL^sK%qwV3`mi)CF$FtAPy4aY#0=uiNY1 zXYO+etf?7r-BHA7r$4!zDJpgP@&CG3XfGPyEGlP*PN+Y78jMrfu{1u{*q_|wKwr2+VZ9I(VRN+7OYeTd_SdJ|alQ}lX&^lI}F%BdZ`JMrl3%*x4yYr9Vy_L!Iz z4SG-#q(JT0rPq8%b3t|J8BXpN)}pE$V5X1rCQsWQZW8g);Og#U0w9ON#yNT%4Y+4` ziFd8W!9DZ7#5FWB;&6_W%8Qb&OtYLqyP>Wt3K1f-WQAqH3xr5xWl(P&)aN>v%_P zlX?iHNvZ6bSOsvJ<58TY@Q%B@aE49&1_cW`JfwjVqiS1aPKtjtaflFtsbDY)*b^tD zr8ARNso-*m&kM*>Cxcits;SvU=!hF#CSnDbU_w{)5jwAS0=*)krq}+e==nP8uiZem z#vQY#>hvHpkVQUt>3Nj;64$jHAXw%Syxco~$*w_tlYozrvAv;F`g!h1HBvb6dmds< zXBa3_D5&MX2_wQ#N}yxXzUPg1MuU<+f7&im>*qOyJYKK3x{&3%^LWpt`G|B=7z9iJ z6_8}d2`GT{>=2NiO@M1|NiCm65)>z#Cr>h_mwh4gL-Jz8Ui)EdPmO*9bepv-wIFh~1?0i9kF;Gd8GFdg6fgQoR?c%4BwxxJKRn$I4UY+PX zbZv5Vn;CCSur(V5&w;fi?V!7AS;Z_zifA~%lCB0+aunIjfO|QIN@fMa@8PE1$7je6 z^>pVX^~HCOb>M?kU)Mpk1-jOtmtZO#z9U;E`~%5=X-Ye7#!Ku-BBR&6)m_)uCU=Rr zGOv52$lV!F8^;lC7d{|#v)H=MgMjKbO5kGe1#b^NCaIJMUzR)M%O7DsSSRw+_!?_v zupp<)tp*;)?CufWi3WDRVcnFk_$+OZB5JvsOR4mDYpt7!x`a zv%dUWxoJ>D@jv&?@<~-{tr1T&4AM2uWjl;;*qq#qm(t(bR)O~d9F_X>DFO>#3)v67919xT9yz|a*l_!{aeGI zGaDKB$=-U?t940OnLUGzyvAN1#fBy2*q{8`!&S)`&$@>kz4k+nK}#^3xELVEdyc{V z_ppiF97b7l;+}zrwEc;kgF>vLWy; zq`H#vrf&L?)@P7uI5B%7?!Qg8@o%XluI?~@Lxsyp z&E3OB!w*3EHNvK44VaTJHcBf~xp_3e_cH9B{-S?<9^pav=hUjiSE6IBXlSsM8|Nq> zWr!<^(~9_`)&#;aB`amCb*UB{W)Qj#U`JuHYM29Rp={wiH(Z8j=p;Kro;046?N%@| z995~2lIc{7X$#aOEvqZOR^rvTXOR<1@WZ;T^wEK~SVyByKsG8HH_T%^{JM z+b|E?9jE~MWDD%^Cj&r`IM!y&51tv!@HRNjR0Bfb0a7&)8ULf4C?@2}*61mOVw%X1UV8*lYC* zSWRVRc*A-~&e2U2=gv#{6dMms6`_R#rzC2CeRQ)q;5k-C$%)+DqF5=Oj>?=gWiesJ zp<vcb8mPxSS{ z3AhzhvKUWhZ5@o~khrHGF%)G^2h>^Al%^}h70IDi27w%jcvM!<96GIIQ^3 z286^1M$ruBUaJjDp3(Rf6c|RR)l*OVe7?yFpMm%Tro>!xoOmhAFQx>gu9Z*QUIDp0 zRENo%*8B$?7s1aS!GpPxUo#^{B(DN7iGq>sV!q4=U5aaW_qm6dDIlvL>)ie*u3P4M zPK(}gUKhqCH=oH-Pb}HKGyf}QP~glz^AxVqsFVfNF)VQBa6dF0!SarYUyI}m63%jN zG!1B7iMWD+Jdj-T>g(9Twz8j+z^G7X2FKYYfjFr`s9CNXk2sxtjGolaU}iO@``FO3 z({@X9^YoIDc9|xGILYQR;nEX&TO-2k2Ez$qe2fDbZP^N=av;|Hn=NLxUv(Qw5UMy> z0{QX92`BlErlpJ8_PHiGgm7oY7w4EMfFO4zMMZy=FRSE|nj#1(r zAr@W3K7yfWHkrISsCqmp!Bm&u@S4*@jGk9qZBcX2NuI|dD-gF{$|~J4-Fu!rGt28< zGbzK4;7TTRj?ahFO`wm!h&p8W;jdVZ?@jCd9fp~aDu8MY0GsT>#gHmP6!=NR+?51z zcHES0Nbpb?Lol*vHeXy#^4ef&TCVSBy=3iB>Ur}1&MQ~yVWWc_Ib!%*;LW=K9tqvS zbvfg|cyq5!KM5%N?KQYbr)|(9jHPh&9H9)Ce-sGTbCRw=p8ds!ok0h6*{QS) ze}VZJB&}unGc>>xL!3Dw&drH70l-UJ=}btkE^TeBl@YU}rO?(xEswal%`n~AQ?uUk z9vj9vlXT=Va`E>8f&hVQ)tcmbpv6!ur{p^w7I)S)Z@(uZagZ^|GQ&~F%BMx<_zhE! z6f{zcHkc<8IO4E~D^41?*idsYi!d3hlXsGpGXLOd7b>kCSe>Y)#h_L0&Qz5k!MWec8eNyNlQNvP z&A!Xg^9?#TsGQnOGj(hCBBwGfL>;whzxq#w%}x*BlqT`f%8~3ROkFL5a38ZfB#W?A z;IwnFpG_(D!7-B{V4KaTlv~9d-c*{7;_s$cK`8e(=FD7rlB$-K0eIGoa2K;LC&*-n zkOMyv+wS#^c>5QQ>U-$?o8kD&&}p3vDp~{aF*=Xv-oP8jjJQDWj~BS4fStJf zZX?>7RkB?9*b>I71MG{zxY4xRIxSk+wiD_qUZW@h7j8IwV1yEW`Ap)16q5OVugo}X zf$-wpHp~gu=`jSKLGd3Fs6UHlTvUv(T+%y1u4dJ;9#LAcF+~a{vQpprlTk&YmGYRE z#XOV&vDRGb%jehMw~di%gE&z6=|g31oW{@EY=}i92Pe&{(du?n9I+4I1zRLO$&Wdo zqx}Si;l8928f5f;W7IZdYb5IBYWh`;e&e*{}MNI9B_SQ7^ZN9Z|_s zoGi5UISG7)VRg+s$N}+OlKUuvu%F^MU_hDBMuU?K1nBnt-SfxjmEDmb*%-0;H*6~TB2!flHc{rk1GxX%7ahnZG zGz=Y9;pGZl$$5>l#aPm$%9Y?u7yQ-<4vNL(^kU8I8v7~28*w0c1{wOhrhxrtQBQEw zM4hN6GS^L3rZ?~QF2Jqd;Kbs!HHn1WI)BTr(&f(ZEs8%OXA<;@!Oll{gf*U|ul(v4 zII4RC4Vi*dUzgp1bsO+3SU70i!DC8EBuSarC)sOQ0i^Y^C3;9%~=R@@n~ zloxWi#A~njb|peM?!Js)rpL1cd$ow6P|GH zZVtB4O@+XHy{47^)wO0Tj@#^$fE0SHcSs|=39uM7rJ^hc>7than2dTZP7ObfjBXTp z7bc#sZTEpS6*d(nWZMBz$wQee%X*Hbq2wsEX5`rgGq6WNsX7Gv{;gECof2$0p2~%U z^lQv2ReoWeX#FITdHjf#*>QSLV;Z#~B=;oWiUA&%6C~OFv#~TYygQOHDQxR!Nvt|l zonPH9wxgN(0)&iT>2p2~7!S^jIy{aaR<7gw%elO#b+ne+)c!VsdFsLK{T5kelMVVU zH95=RnXVF)6#JVhPvcRxZUM+8%hjusH_GTbqzADMmq9SYeS@GM=fE#P=3A%kMg2@Q z!&usP2$v#ik=X5NZnN6hf_vr6TVw{D2iL*JY=*Xktg*Hg??Ba_J@~%LYZY}+x9yTt zE`R??4b30SqddH9{9EF-6ti!1li24F`xUH3s)-~EB%EX`%fx`1E7lz&1baHEdmeuY zL`WnWtA(?+f#nWK^bSE}asBqjS16zuqZ)${nbTF>fTkqv3u_mvJ|GEBT1KYfiO8Ih zW8(DzHH5$zf~pKwTtqDxpUnoAHBXAvyp2{$&}*Qp&VZt8mSUl^JRHbkb4W%)1;TqU zVh0XRT=RieTHlmcIU#K?M!vB$%U&4A!0VYf>+kGg3Fb?~?C5Sz_20$5#& z!C^k%&0x7Iay-=h~V?ADscz0vhymLK6xnM*|@$E?d(D1TCuTord*(2 zO}k6EdqBEh1Yb6>3SvmBHsMAKI4IeXDScIDndC?NIZ4^*&?f4VjMu z5}wNhPOJR%l_$;G*gLSDY$rbUNg0j%SH%*)VM74wat0}Z?tZI%=eNI9RaGMjXw++V z*VQ2bdYAz0@x|MWp2(kt4atb#yN^`(;>vT&fro{Bs;(457 z_i}Do`T_Cl)=)a8J}`P zoRKH9hsIr(Nda|$kv{UN2Iqp*yeb_&C4oCWjA|tE&GOS}*n2+zm$5H%czmk4yuah6 zRYN6^1_N@eg7S-0^l6>r-n8;9#ywE6q^#0)c3Q%pQrd8}9g^CBYLnv}b)O4nt@;}r zvzwohxsXL3ObdR@vVnEKt90-M&gMX&SN7K(P7m1DrH|l-k8f*t*O3Rr8K>eDidMjU zj(8Aa=R+xo6?rG7UlH`nWlmEsT{fNR}4UZn@2N_K8 zYLK_mx^XW(O-;^)CbBzu+I6~th&>F~o5_{Gu1?|Z7C&Xxq3oeDGxZ9*3ejHO*Xdph z8PZ{J^1tBUeqaqLHUoyDwJ55`PruPZMTGCur4NMF$^F~{B59s}*`|Y+#iMEy`5f(% z)YSj=Q`E@de!XSeWR)t)AP(pv)!_6f7KG&9p6(&xD?jLH!7^;EVV~izRM)@{1diL^ zV+Qz`m)?+^$q|{szHg}GaS>snSPToyPr4}l!Z1ouIzMUm@@(6$^9DWQ zD3h8AV&rEliCFA|*sEt)-s6;PlFj@L{pb*{e!85YgsCa>4Ndiwr7_60Alxz-hOR?A@~%-wZt;iao)3vQTs>@C9r3 z^PeM0fW=ZRqju5oJouC}xQe2iDT1M#GM` z#f{G^^>Cz2+$`eWm-L>{mc!%mEi;b&gsGA&j1AU_ZA5yvV3xsgK8{)ZUt3GRDRk7O zzxm~2gv^H8n_88ulD5d~35WFfRD#Qp zRH15Rl-(a*>%Ywy%9Sw;8Z@eLA|oM)Tg?!GuI*P{wn6nJbARs1tl%mM)#a`w3IKA7 z%G`5>tjiwdxO%5)h*=VyRNR+4IEMC6`ilq7?p~R%I#c@jXbkF|Dh#1SOId8GM?8zt zSI7oi60)WNj#XlhF1QH!#Mn+u`}rm`-itMLip=uhr3ly2)wSmIbcfsq+?)PetDOmOUTWtYL3O!%?T z*7EXfKD`Xg!FbU{HZ-+G`7|B>fCx^@Y|8@W=d$CsB0=tw-_|=_NU$a*}Nn=I*+^4|cLSbU!7MV9%MKI_xxcD=H{T#53i2{Q#=oJMQjj+yAP4U1Ghh z5msO@rjRHX{z1_5do36Bg6VHONjr~5DnN&Y`^@85O=A~ZM=vL3d<_wom`av8A0el{ zrB`Bv4hafGNuurL0$yp3S+4HBe>{q7nFgE*Bb!9Uv-iUtgNb#^u5l-B{Sw*`2gtkV zD1a%L2<3j0B_L`nJr<-Y8P)h^FbAmv&&q1F-QW7NEaZvOBy!sbsvBw~T_9MFYkZ~A z^B2!Ej{=jjw02=8o^Fk*|7FS8{Uu&zuTRd3dUr{bI~~SDh9R$0{&^z zK6JQ?1;1@Oih%Cw!iWHd4*wtdE8podX3hfR%dUe3p=A*HOWg53D! zi);H2D-=~JD%;9_((z1sCRXq@Q>SIqwy9qQK&+DG7qC)feIkC_9Reegkl49a8^Nu` zYLp`d5-U~_S`;j+2HJ7V7sEQ1TVDu5l)o@}^5%rzVKWqK1ZPv*L|$J5jxgT*OhVWh z23cJEXXj000=_jjK~>NAyf`SI7VjNMwz%tAKuR#@P}>Rijfgz=ro$D$@UB=(A}*!`mdL#?bgv=7M+)cF{(30`k(`vPP-R!9cJzS*89gk})Ln%*JPD=qi?e?y z^&?^W84!`Q=oPvB*L$9+4rgGji zqeLyOt|(*I9q%(l9~X_!{uU);Ga`^WUByw*R@0>E(UhymYu01YF(75ZuNR`B83Tsz z84qPw$B)~jcqQc-Y3En?QssKAe(gvnoM)4j#_v=k755qU3_~0t3&L4axNR)v?!C8l zDA(GO6z!&r>)CPJ5A#GC=L|0%=Yr8)VDt!@Gr9(>H7FKY_qX?R*A{cq;5Da|usA{P zYnhZe`EK7YAVp;}F{4sd5D*Fo=T!?>C;8-}9Xin5(3I~&se~^NHGna`LO#XRkGtv8 z{2!v;fxXVI?b>c^+qP}nYHZtP8{4*R+qP{djT`%0z3z8=zP~Wnx#m1D#y+y8XG-gO zKj;MB!Ci}@4s$U8hZ3t~1ww=>_N_a-DHy;nF`c9gtt$wl*{@PNE+`H$s@U8q|r3){DWeK{~QV>x6AZMgHeLODJmT1{!*l21}D2adt!VY3aX0zye!ac zi1XBflf0gvv$Q(Y)j`~dY6FPsG(6b$Z&mOx_zV%6W6h74-7C=PqKh-IxfMLQhS)wRqc$_!0Et)Au8 zB}*E%>J}|fg{&{~mj3iy9+v8s-#e9$g{n;u`SE>T1-yZK16t$%DB>~wfJO^2Uj2&r z1cI<6({zI(QWTb=vLxzGO>S~p;#R9elYW1clUCq6W(Ihfj3rYEDA~TBay?St)NVeyBZ>R!P%F?$?;)aQi2_dd}-=T|Bz~z7uk2S=>}T( zB2t(A7P9K8xFU`$3o<zLOLi?%z9t zA=g_gMT!g4MIkO1^OY!j1bq7QOL*w@!7LtOrQDx$RDJuzmwrJj4nQ|qF#LW3F1tox zeS$qr_sSuXNP|f}B8nEl#*z*Ry}HYZ}DHE*NGgt6)nT#8CIX$9q)!K|?R$qAbpD=ROM0th9tuSW?Cg`9zL>#rR zl#iaO)e7o1{&;l>zIO+%7@}g)Lc|CdU&NabLB5z7gt9U1O^Q<_l_8nZC2xU@;K~$m z8XdE`d?sP)rZSRK$6#0yW$ z`&JN6%VmW+D;=<_S%;18)tbJf%&Qa&QkbOn{vx=TNC%bksPZ^z>!yP$%m;$W&VevO z`SQ%3OPFu?$Cy>iQS<40>qzk8+7kU1H`RXw@iqROW&K?kB0XDrDjwjOmf#+g0cbv4 zyE~@keqwmix5E_k`11KLP)4(!A>tn?6DI*sS%=V@e4i%&23_UgA&++sw(P$)k~=zq zyeb{*>JsdL!cH;$^HNkYnMG(2J^QCIMCvj(BmlP7-7NpVwtE7>Yx12_j;hL9ulI+a z3?BkrG%YV+9Ip|rDgQY$|Ic&V&SBke#3-tiRF+ziD!y&3DrStiLTRmGxMlW!5$W#z zhsqf%F6UVU5T1G|1*RYj${I)_fK4VbAOtQ}=$z7Z8GSVIAipnYcm~3;0DaYUGww7q z11L?;s*!}iEsG^;pI4|Y1C-ogp75{1-t`Ig!hce6plk1RMK%F)lMRNhd7`S!^ zPoWm$GpO-VR+{Hj=a-@bGYoYhW9oZO&Tf7rLOkT~2HGN0)1l$Am*n@B4LMjM?wu#$ zt(bL6wH~Rf@8YBx6lJz3%GQhX4hz6-M!_`G?tYqF&UM7?9wWLP9)BHTeCogC(=_ys z<#tIW2?C5DD*f_+?!Eh+MqKBID~I#}X{S&bpiUBHsGg{=o*Tly=^%YtadXq`=}G)i zT!7(Jhv$9L&2fK;8kWbBVP&Pgp7AK{?y26an_5_7O0TMP-ch5JqB}03Tq&M1jLo%B zhHhERP3ML=M%K4gRawEj;qbHFihCWv_BE}JlwP@LPAdD;RR-OikWKAWd|%Mt6`!o5 zBvReSWb6Ceo>P=}z#JfzGEMug$tfXTWc5g;%8h;|$fq>bJ65f?+7p?{RrJHOkw)Ef zi-dsCXMT~!MC~`-nvSeI<+?Y#2c26IBf`-*u?9!Xy#yh2IRvi?jFubO1rzo)w^1-Z z72e|9b4pY-jx_`drQ_=JP{2+Ir9z$qg6nh%qA~@tv?lqFJBkAR&OgvssBV7hP-i*m z5{t?!`Yy>xu!lNf&?^x^6}TBBZ#?Hf*9I1k#B|p;GLQbe5)0JjIc&1cQaT{n*NErF z2WK+}OT&tFA!#n`(`&a0R@J~fOFA`1p_$Sjo!)QG_2tb5d4x4#Tzz81I;}`b(nMgxKqDK+3l}$LoNf}vu!{p|4! zl(rqW)X=qJ21hBZmn6_|lfZV!BEc)wrjvHIbAO{GZ`&#(_dk^FQiUri5XRhH*5fYx5Z^ht=5IV_Y z;F!-W4Y{j5PSltot~N|1DrDr$8nc{-6C6uv@t_jtg8Vh7imK-vOS*8|V$d$&#=mX-NN{FxB%+Wb;20$1!0jAN0;jj^S1VXvV7>gIZ&(7Tu;0jku&I$;>ZG zMMIUF1KhF|qgx^>CTIa-kteWSMEv{JQn-2Ao4V%leflY~E_w|K+Gjx=anM7$d_`ETH%V?}yNfPrpw9N-8AVS@orYAWH9 zi(f*ztg7NVVLfm;g@f58JMk}Ba>f4+5hxigv&Kf|##>>Q3K^)eStx?AnLZdrkH*$? z+Lfx>m_o)>Hm^XDjM*ul24}6XOtaolJ%2(xYKg+3r_6RbnMET)3^@sQAVKsrxhc84 z>aInL8JHy_qZ)k%CEjfW4cZkzq=QF#3g3amKUgib_sUYJdlbpjWhp*!E$J$Cfl#(I zbkT$a;t+<8f6c$hNV4dUec2gQfu9YUN3kirb6?Lk=N}qe&r2Gh)Cjj?8oL(x4X+QG z;U~S;^4s@!`*$bu2uLy2Y{Mw%8DF#|a1awRN2#`k-*3FnBYiNVtj#9>N8Vvq9uJ#Z z44YkCFX&2tPt{*G^p>v(?L`17);d;-b^L!2+5Z=6ymEiG>dY6(!aS`ZtkOcBzhg7VUwM zidY1ZIz?aykD1Z3R_hr5_&EaFDJ7bkrM58Mf<)yZ8;46x=ZnIWzt$&gaVQusYB6s; zecOfayr0WS@3C+1SrB|P@wl-oyA(gdyG*otT8lwnd0YxY9t4JQu_5#0mK4Ww?>k$?W>U0$F{H>T$T+VE1Ii{asRY|ZeD zB0^QZ{BP>%`{WnGj%wWJ502l#Fj@a-hRXkodINO4@z4z$p^ZCv71X#91OCL=GxKZs z6l!=pf4x+XcUdy&2sxJ_yald&VzD|+h~vtBu1+*BxYCWE%P$Ca#6MzltUcA-*z&-3 zA=IQ~kIXo=r>sqOC@E_@j>y*kR>j$1%}$Xk%@DUd1~=EjwP6{PcdgN<+2mQakh7?B zV|CFgZ)PS9?J0-wSK%sw6}V+R0P87{B-uKl>ClfUX>gIQXD-jkxyiHKgezU6gu1cT z8z@>FPZh?>iFrZZuMfBhT1VW9IlUPDywEK6(Evq73B^|HS{C+cKu63%08O8J^Z1=r zazFwUGITbaN@4(-E2uD2uiBm^6=n;XBXVa3ohBg2g^cUtXelsxY2NS7@v8_H#v;Iy z6o#xHv&09TB^ZYjg1U*6kqSNM5|ZBu%^6+nDY*VG z5X0Ah5zP@gDy83)ehd|I^jP3Ma=7oVF-`Z2TueU^C|LuUuBL#^{kB0yz`WtG5TdpkA*cVR-vTYRdU*c96Y3BUVrBYpsRD~HN_~WCNm_a(a*7u5 zC~6>1I#K}YG+OgXl8+$pNCuVIxGD6X(TSL;Vw(mx?H@3p>Ls#*Vv5AhPN-WyL4N+t z`$<7XB{Gw(%+soBt>sPn;iAv<@ z^0e3B9J2A+^+5lPo~F*#icp_fwgn%5*}~Cj?~;}3SJd){8G*t$r=vUNGsJh%CUqHl zn-&$U!NBAeN<15v(;u3$j5vt9gc0+;WvcQvza0P1>Gp0(1_O&p0R6wcd3Jn#0${2p z>fB@05UBf2R`&Zb&H?4A$mPCR6^ zVl8BWf$wHdlt^gA$F(xu4w}qkoAJFt8mFQ;(^>_19*Z}@^?6=KlIR9U8w5gTZ|qb5 zzM@bLdHxhX_(8!XMP<{WBV7Ff5NUmO2pucK1hH4)G8chUuMP)KwUqck-WkJz*|~Im zH#G^_b(C1JDMsP$qie-j2P=E-4!VUj0VV1Zv03<075p_-NdF7en)E9GAzlXJb{K@O z4o($1^&S4UDdZ&cHNmgG(|nsmJ!TXFQX#n%QHCWFf;G^Kw>iIlBl>HiQ-H{Arn=61 zZ6&fg-!}bY@E+di`F9U$*yX09CtRj=e3=u)kT$3NrTqB&qEpwG_Td3Xa{5$2=6{XH zf5Hy2=U3<(B?(XYgo^+A4uK!X`?3-i34qv>Pwx^i_NqVA^>o|bS9(Z7l1XDOaY7z5 zO@CQ2Wycv~*uxm#7_qI}9+k@k6A#!$>9*R4{|xbQwMVoEx=j(OmX#?5a7Qs~#wtNt zwZ$fArpz@uCX424IO(v6RF{m0TbGetZ^af5WNK%0_BoHQ8K~PYenHrTwI%TeF=q+j z`#aiIA&y{rWUSOaITDi!gfF%26Wa~V>=M)rEt-sowrEWxW#HfIESW?t^-`MRlR6YFoN!8PQaoZ2g_VtZx3eK_-`6HaOC)y78iJ{}59F3=9A;i-+?Df; zi1m(~f1(I%*ElIbiSoHQ!P=?Zodg=0c^c&YEU{Ml8zm^&b6|oHfoMe^T_7|+9Utd+ zu8M{s@o8mtgwe(Y^h_qjFB77-IH*YXX8Xl>})VfT*6=5`rKK{Y6$QTrAKVaL5D-)-8>9FE z0i)Apam1RZ@83vxdOh)bU2XuGDhxgZO|JA!Q_zg`@iN)doB&Wd5l8J{(cu zS{lP>WKZ0vm}miW2h5k#AR#41KW)S9w@?sLs6WWqgcaE8&KSO4PHgCE<}Ci~si&tG z=9X(aJ|u4Dy$~%ICIxt1Y7Cp6LmK6luA9j?i8@Vy=%l(I_|-OL+jw63NsS{>D-21e zLDv0uTlex^0G^jfYeOKj)*`dd4gU8}-L~<-L#Q_Q@bQ?EL$j*vl?%78w^yQff|v4s zYY5cCyjzJO6+OL=mv4h8lS8s0aT&hzF&9W2PzE1 z42d5hhY9E&S-!DMb|3&8hPOPEuL+C>rp9E%C9x~2OMp!e>mtE8dK{UW?P46qG#Pq=Xhd|SF*?ek1j;;igXx6xIDH5mI~B-nfhB(C zsMezK#Rp?I+Dw*CQ#O{AiDcb4uLI<|{`$g~~3M0eT~qZi@(DT2Vj!#X?{ zaQP<3|6lyUmX{@MV03gLwe+Tne00-jMFlt};~#9=zU`B%NxLT?E&9CqspntVR^$Pi z@%x{=QmoS2T-?(V*SNV}F_hW)U~J{(Xw`F0NsZ@@b>LTJRqQC{JZ2GSKn|yoesXaw1)*6l)JH+bipQGX^2@XSenwylusQB~7sxr#rYD;5! z@dH{*9c^txhQN{H*n^@$Bba~UelAZTCz~45jAj&DvPvl#t3JjQD{B=xL_{@q(`~tO z4}*Ghn7N0p0wTYd`C1-h!xKEB@*nEEa?}ZnmR4BVtULxZgJTalWl<ty zv1!UkfY>dNs)+~`(n$!APgDk)#0onlPIy+h8kRk$zp$Wzf#_fHEa78bY3Yt!N^;B6 zLihgRoOe_bh?b4~&?Bk?9g#CGD$>hwV4|CpJ= z!=^Bwko$4R8id}f;n!nlGM-S=IT;tc2HQDhsn)Wo*~P!}OR4Id@yd_=B8xhdJoiGd zTJBP8PnB!E=I*b+cg^zw&MMyiF_V5pgUl%d8!KWnjGbay}u8~~UCykWO)j6IvXUk6fH12P-~Aq^-}U8$hIth9eUq5`CU zN}+<%8x)CgZJ`5>r>v8O1n$0YNFhk?I>!)xKz)%lan(-tbeKQgf*#R($VSohfLQ^q znQWUVM>>m^K@}dah_urJgajs-9bKGgF}KKOw$|1-=POc*X2yr4-{59^8r1W!!`cn+EA#g$_DK!q)Cee(Ep0&@Nbt~&Q3NbtN zlW1LVaaqz9C`!kz1Vwa~g_JPn!Anz;aNT?JrK0t`d)_nL76bT+hJ1RlwZ%7aCkdSz z9iOi#55kz{5LBc-dslTDC!Q6_Y98G0`dB?~x6vQiQ1~s!ZM-{H>MM6YG>EDXK(g9w ze>{1EGsDCLsIhvfjQlH{#H=XvdNm$P-0kax%x2 z5S~PV`pZrhEizl&aYfX*uw&cUtCM$!{rySf!*eFLGU#-t@KH- z4j`>}_Yv(rEp9`y!A+eye<-f$A>X!7pOI$TD|oe1EaBqihQ|>k7+gA69JbJVHoH6> z(rbMI+*CkuRl}y*-erHt9 z_E{3a(sCu3-+!UQxq7iWh^M>=l^-v*UTvZd=Z<$UmW>z1Ou<1v<>GL^x<+M3AFOIe z;|jN`$P}m^VDbl z45A`{>X-S&v@eaO<(_ys!*D|MPv1QJEp=}+p)MtPS_GS^k5QC|IUd_@hovHjueKBD zOAi`Nhugj6ZA23UKS7Y0K=XLP`zU9OE+Z*q<{WDOInZZCGHNJC$@VsAf4G_?Lw#qe z`p1;GKNF#9BnrQ@yh`8r#vHnm6}Iy0?_KWdtM^kcJ+U89DD>QUCcta^$=co{xm8xo)PFa&fjoH;*O>;QjI{f69_XrhQ7|21=(ASB#sWKt3N-LdFHMS;v zM`=VwM{z}EF|`b_v8;^7M31tnE~_%UcR`GaiuGlE%Cg=RV2NT8XSL`qwtO=wp2{}9 zf(npWhr_vv>`r)DK-+HMCtqG**IzYNg%nUuLYopfNJ$Xv?VJl@?lWni6}me_x}2W6 z;hd8ssV*bnb(Zb9^|kQd+ak8liRhYE1`qZgfuPNs&#<$ zgD~%EAUq8O=;iqikSGtso+BbWD0p@(1Ws+Dp1-BbK?WqGyzw9?AE3Dy=AWIA<^=Kv zcy-?0<2p^M91i@-goY>}DU#T*61)(Z4RQJl6^7X*1P(1(0=au#^JhyD4#Xg4vnmp> zS`hEqEp?4CC^bc#^8DnAsK{CzdJPepBUL17C~vJ<{#eW7Yw?`FpKW3Y>HG&Np8EWe z;E%#0F`j1?I2iY-X78?K`{Sf#39eXUlQyA-0BLlh*S~0nw3cPm3RBh3E3Mt|R-=$8 zfRA;d%aCvP3C=1na88i?8`2?jb9#C%d-!;HuiXsbC~ysbNnNI6z#SBz4v!(N%jU>` z5Y#x8x0{=Abn!wxMKbx^ZaiDvR)enym+rS{wBsp4!rn>K5kYqcWxcq**#;C|UG~TC zco?(4Plo=wKHFXU-jKONVg8`6O8y5G2E@)UF`{mt(p=l+F_Hk-@`7kqWEyq;6`#PP z?ebgXJ@HpAX}zc9D(t$1YJSjfZhpss}#r;bP@HrW*~k6KYbLVaT3E))zWz z%4IEAm?Oe1Xf4R;dW(`k*S-Xb5-<2!;qkm%R$YZ+*~ETe>8Gxm>YmkmiE+XvAt&p_ zK|nd;zE8Iopa^AwLT%BLJ?-Aw3aBC3zoR)kHT#rUW#jk`WNRTqx?Be>L9e{i9$^Ap zQ5KM2fwRoPYAM=&y~LX;%&_#z%%OHTvwW^Pv!o4Y^7zAm=`$|`C{lg@S( zle?NmSTkAjqtd;X!9D>eyYwC&JFef{*S}GQgyK4zz<@l5wDWj>#oQKncyTwbigOO_ zt0rXIT$cM*b!&ZGA=L)z;g46)JRC{LVNh+`AQ!%RV>5HRok2C*-!1fWM!7jdaR&8t z){ZtYgdx03e(>1O_$ofPREF;lyqo&(N0J5sW%u{v6o9lfTB#d=*F(Jaj5t>|Sp|Y^ z;mR(Mi6>Si*8Te<4a>&Gx{h(?WQX6wzLKVZb@2B76IOp*bndxZkS)q?PA37^^rDI2 zt#C}Kd}t>nHCxf&~NdoqjJCp>N3?v@Rr)s||Yu(-78k6Ga?VNsPI;KSi} z>gRH{)D)&l+V^Z(h1|t?5n|^F7`5$YQ+RHc^6Wr@ZMf3f8AwM+{%!bn&#eTST7a+! z@}V`49-B^h5_tU86-DSaMoTSlD&s>R=}u+JFaIaG9m{@qq7B zEL&H!8?@)FMJVdN9?vhAkE^WhCgC06So@y7XBXYAx!FjU|24X7cPHZid4hsqK>mx! z-C$s)Z&nN8-OkJ{KTMmi6|6-@L!DTivU_?w>woRE9Rj(i% z$&hk7BtU#Shzd13{(k@Rc01d))B9N)wx*w#xMGq1-!r-$0Vq&|Zyr%aYP34wQ*2*L zX-!iXCW~bn85k49>(@k?6J*CW-H{o(&%~%CB`r>}UO54w_u>~eyKq(&wmjqL+U2gc z#jGK9t#)V03x)9|Sf%qWDACg88=A{cLmv}=a{W( z_hjfUw9-8I-<2u*4M${t=X!gP$%gDPF+5K$j<(01dvIW8w%CW@S9qC#+}Y3(f_C&l z2-0gnx_x1~DH7xQuHVaRVEhN{fd8>kgP*esp6;4nEYn6B zm~+Hd!dWRO^U}oAL(mN*db+VFXc(%>f+~XecMer+MfVCw$fBRw*Dz1^l8>G9);G_p zFxe!?g559+krvYP4yMqg=uAlsQ8(+AulG2m@m`%qV*_T(fd6O~;%$u3smY);H4Ks@ zaBxFD@Xt&zD6JJnX6?)9%LF^aC)f4IX82f>4WcYKuRkuG@jz0=N;9}I-A2RAq%&-$ zc$Gq@qJ5jZaP>0`{DI2Z_+sMyzECM&MerA+CW!@y_rU_b#0Aa*v2&2x{NgzVAN+9P z7GiLa^Tj^BeYU=WM{vOF3-Qk@ww7n|#J%$!?PW?IcZ7tG6&}C zGcb^YvnzLn7Q`vRF~BU>4s^_g*^=&2Hm&uLF*Lel_Mya;j)Hi8dN~f^Z~SgXdxBpo zDlPc$`}+UId)*i~mZr5;h|*4HOssJX8Zwn@Ns>Zpl&|k0O{MtK2!m6GX`antKO6}p z>Q}fWc;h(yw;0>Pr00)Re_m!Sh}VZfapoI~V^ACxM)z>Ev^&NB%wJXVlra=EI&4CG z?oiweIflJc`P`cb5Q0esyI`wi5pAU8EPfz>8LgtX0tbAZu-x2rv znr9-n_Tp~(sQSvKqZ0Ns{!U#$h)g@^Sv@PhPq(vATXIoA*~ZjoUuO#R|8oBZ+w=kI z!}GVu0yyFUVU_X#N4)4gm)NO=`u#T{%sLPgWNw~&$LLNU&&nm?P&_9DhOucFB%)9` zwFhYrcVhbEpbM|Xbs4p9{&HaY?BW(l5nfDzl zU~XgYUap4|2zgELBf~`?TT*1jV~t9khau#px z@Z8}V2_70r&lf6pi-}hUGikWYYwq`#50S7xs4=wnS?&`z^&6*$+D^jYO2&A)Zj&SA zMMHIr{>Hurd<$5AAGuel!DcYtH1^5^&GVTdaa$hEVgy(eq;_Ymr-&wMCfQuC`0yg%wnD%~EWI1eZ{xE4Xhx#MZfjahYumn#S&p;*q(xNGQel;3t7|BvOXDyj5?1%fj!gc7m@P%+ z(I(*qnW#tM1tF%nvMhdH@tdO|PC3niw=)A1_$vsn-@{#}EiCgF9 zr^mGyoB}4E8_9ORr2{PffJI_kyKnFIFFzll`bL!KL*-M^dF2~k%@QvlkIp#nmXk!8 zba$Q{j7w&e`$^0k;rKilPlJ&*4+H#%Qp;-#zaStcJln<1i5_PA_6stPKeJRq?jqWrcxHaEgx?Nn(%$YwC(#ST z+c==T`7LMfezENI)_#I2Z$$wyV#x(0mkASSRL$0V|D?ZD5UNM;<0Fz$SwDQ<5rdkHJ;JDB{uk^r8jXhj)$Frt6f<(*6pU=S9A zsQF--!f?Ic3eT|f5DdSu?HRDu>7y#IYksO%RH%#2MM4fhWvDlT7JD>h0g_%6txb#Z ze#4WtF%i!+LJP;W4vcVN?k7{Y0n{O(bsh|!VU-dnwDEWBLt+)dE>R28D8&gQ3^Cr} zjs3|m;a>AOD;C`%CwlLC)LTay^K5O^R84BkI^13K6nt!5z(mK~42{d^Gi`fW!A`s- zJM{yH*E=j*3b(&&z=I~;-t=mIo&5asL}HM{j0?X73*>g1gQNv_s{Q9Q-$Z(|DKM}Q zrde>}RxIx!003kvhx@?7DS|(u#+4DnRIpE5REO#o6dO<)b6^za4D%Sk9sTULD5CKt z(Ce(kd17aJN^6O_Qw)RuIy{)Y?QQ>tp5h1UBh4Vm`mY}Te|p<5fETRNOucSzxTb&_ z;F4`;RdW902pcG88VF{y_4y2Dt-$w_i)m_<<)(5x9x_PSFl}BIUQJRSq(bd^tat%j zb+`3o%h250x?PP@tn_6rRWiOW;W7h_VjhxCyWauPH!zhq7*fA0JP4{stW*UW|2iIjU;`h;7u=7V$`M_e@@0(E zIQoB)LkuW(_&G7RvY2fBzFNWSxqBdS&B$U$&%%swKtCiOpy(00CN=uXFp+x{qcQ^k=vRHmiAmkGC z@ba*^o3aKvo=QQFVt?TjX-|^2UgV_%U=OwP=s_hWY<1U~g1Jbef&7e~%0T)rFIZTN z0y5Zb@1@)P?+>Pd!A0_P+8X>ZbbO2CI90$1bSG%kW}))rOE+vXre|VKb5UqfJs8_m zSTn;u>-3*Q-9$_pDB$;re68fT?>y7o*buvB(ijX9$Znez9RTV#vTZ>rn%WPevzO2| z;)|9OpNP8*pxsWyx@rdf+#Ifok%aqseeJaU!u37_l;oG1fviOYkLXgk@sDJ9guQCv zz1LX37?aH-ok|9RuUCj2tM7~JX@)!K=l*|&qUhLqfanV`S+~(jP&bxc>W4x&*k?MI-D{ z1;ZoL|1$$jTj4SR9yzaw9*WL0doxnwfaq~9pi?lfq7(^661aqw5qpB^8Yy9TqEfrF zirPr4V92gIdF5MW*p1h5FE;C83B&GYEiAr2=`@G)uo<0suc#$TkTmTh=?dZvcreA_ zWl^qMu<`|pg^iTiS!~#bW-O4bDB#xZ@M=^7U;@Nio978Q&?cPb9+oonw`o2^RkzKe z>eliOu@7<2`#R?^kW>_G(8Z)a2L+irJ1uM2XdZgEbp5R?J`}Vudp*~y$NR=P&YrJ7 zFstE0Q3QG#ByNaGqbVR1T$BwV`B+VpZIAB)|zXVY+0f;F4lcMmYu| zq7F=8b6~R}JJB`A&*V3bjSib3Qvc!fidF^-DP=zf&P0Va4BljZ*K!VETX5z7)3bmE zNfnxmqzu!x7vOwyzt7kz4wgf~OW|?3A71AX;L7Jmw<^#$Yx)dQC#?yO*9!C7R`|zF zCz#97io#q!oDcrJpTA$FgP^`saNAJkqEU(iLaB7r_Ni~#TnX0|^-^N4ft25~!~5Ts zbvusQ-&B2`11U}ySl&7A;lioLms{`0xpKe0zbf(Gf2?aJfF}WvQva4;+W#gMUJ>h9 z3mcLhZ_bc_CObQU_c!2W)Ay&-CFL5i-`!lQq?P7i2~B4qn8J#NtYR#BmbU=Re6ke4 zuSlz+`5nAhCZaUiL#Oo~`> zdmQ??U><#Dj1>c0v1-Be+-@W5zyeBpe8Nt>cbDC|K(dr$22(oG`t-{8()ZFv^XK1{ zFV1g&oGTBEH9rX4x8UMqdIN@6*4LnwV{j>I5_qk_+(TOIATyi;KKkO&6gDsZYfMjp z;K4#jA8_oxa8-*ZG&-kU_($-|y{BI1r8v0O(TvnhGKM+IwxB_k=Qo)&=X3-x!?tpk z7xuB=uosQby}(AjK&PD*IEnwuW&1as8v*>`iBg+fj7>BficG1-^B>j*`2D}4Z0cK3 zNxAav^*K5LeY&9m_{ky1u1_^#fXHytN{%xZJ}H)G4FvT%xHIfc%Em8I9o`tPMHE5o^oy!LBT#4H#Qi6v<;c?l{ifLr|B zYchO&BMU|+fx&{>hh}~`1EmX-_q6hi+AlbVN$OQl0$Sfffy&WS*VtNP&z1cdRDk;> zyo56-)yo(5G5>LdhDhZ=WB?rI~+S-8x32mO0(u-T+@Pis7dH)TWiFO!@@?lb}Q zOH?z-5t}^JC*US%=*{^~zXIF@6Nw+-57=#r|5ea&_5ak5A%IM#R`}spQq6{AQcC2e z&=whbix5H*GG%vg-0`@dpq}p?QYG+06v%tA2p?Z+X@<}1B$~r0OBMH6BX>#YgapVC!_xy)2sL( z%#PGL6o0f|dbq!^nF;b^d#1flu3$i8U-3i{aNh>|WUFtgegR8g)VHoYVe`w76+^zB zTiQj#Y~|i@_16dTj38sy{CVrp>7AudUF0!9aYJ@nu>GO*tRL$hD`4My(@7ATX&TX6#kA|Is!a;FP^R zj_l(S0tph=O@cYtXyjc4#}p z#g)u{{#s!m_MY1=x8VT30^aF*Y5-JD_6D#|^&XV!0%WVF=lhoKE_KO0Paf8W+g{x% z2+$e{y5x>v)2#<@cNecO&sUoOUtg6=M3nC=e^x)nEl`9=9se=#WD%v2I2!X2r?F#E z$9P>a<_sDSSFWLw7?0#j$#iYlGzJ7UVgxhHzl&b^EO zc7lB}FL;Zm`HfGH z*N=VE@0G7rwsreoCub4a+<;$CS<@P@WcORGO=~43b$hz?xb zBr3%{U5YbQsap_{6F86(;iFh6%x9C0d>Oemp`(gNs1rH|fH)rS?F}mILE_RP8=(5| zd)YnN=?s|5UwrICix=1Ic|Kq5|NRS%uS*Pruv$C($>Q_Nt8$2*XRWv@`WGLN3-+~d zohjX;FS{BBhrdQ5;fd!HQ9Sw$6iHU0DUatCM&g3DZR{oONx2{++SVOvY21qtA*k|k zz<9P|7JEj*c<r)hL>rQstd+u@>aJ{KaX8p8 zW?Zg(i-Vr{+utT_i;Q$g-Hsp7{h`A-iJQWPTU2#y%m$ndPr66vKmHKYbWi#)WntKw zz~mE3ce=xt5LnIJeE^4C{yeZSg7gcRFCzOMZY&Y~!;0nLnZRox-~gSJQtLTm9{=cO z=2C>=hl&38Wk0v}Wp?M=tNnljDT;kN@!#bB|5W52)&Xu9UTXdZv z> zT+$pHRn53$uV=>6M#JL4MBcSUqL#2RT3}cKi^kA_vzk&HT=XW@VYC%g8F4BxMW4UP zxuyDX{MB=;15*>Q4MT5i!@F03V_6h-H^d=JuHytGi8w|Lmw~RspVYa4(NG_;n)Nz55Gge?pOZkf#}LWdn1N z-l4J6)g5>iw7x|=o`{a4%$5iGt|JS&SY-MYu_g4E+5PkNuVW%VkVVg;sHFdPs?&Bk z09?>Jm6}p9{+sX6nn7Mf#nGGyyb{SV)TJp9faS4CdT?cJ;dGw=r+R?N1tqT0h@;4(i;9WD_C(j))8-ctvfEdoK_8h(_$7BJc$^gw3SnP`Z2 zIJPA>Q22^A*q*XMB46MOh8!1x_2AhUS~Gsb77BG-G}|Gf-zlY;W>wTdj!JNS;bF!wa}&Sv}=Fp z0)(SrXM1V0=qG8b=?M2ENAdPBUG;uQ=pDKfqC#LqJ~dN4=y?HU_gAe|zdSY4JQ zJt{hh|LT{|@Zdek(S9QRA>lf#+2wFd%v&Wv$p1&xIdJJ2Y}>kR+eq8CZQHhO+qSK= zZQHhOBi%{oeA#D@bI1J&HEO+8Z_PE=Gix^c|2}I5nEbsKyy2iiTpLT~0aU$8_rH7Z z<`;U5jqZv3+7~ibkY0x)Iw(ToQv+!R1;DAE*u(R6-<*7mMimSMB3fr|Zb1m(El0Oe zSK&g$RpU>|TP>${jz~-0MDz_8+kRFvurUp|maWD8tS%N)!P&(KL578JhQ2DdG?TYe zTMfB_1)Q3n+LOhKE9;a#Yd2;|9OetE@Z9TM7;ej!QD(cZ+6P>5`~xA&L5xEt4b*^r zLb%*xki)pdMKjw(u-jh2_nnO4#hjXNmWu-EiS=}Q;0v)BDulW_YQnz@=w~66&k@XM z{#zF;vez6K*-nuYA4ET05c0lUi&VhTfLvTa6}Ogm0F41-3tMrCkJgm~#`Ft3{UA?( zXB4Z^1c!Ey`>l2Q;L<$Y69J4rZYHcoKp~rCticXJXe0{^b|UIbHZp?hlh09wtH1^~b#fMD|q#C3PB@cxSJzb$n_?)65qS7cl zJ^hcY{o~z>(}v*(z}Oq%nC#v%60UOFlMt*&fOuK~KAsur6op_Krk$l#m6?N4?p72A z_B!%<&fYrE!!0k2z@-9I-=88oF>0Q@jEY7l7zsMdr`gGRz8j07%hXP-R=-Qlj~?X~ zn@)AlVJW0-E#3fm(cSLqOia~=97qq<+&{kgI@U0KoJ$e+GDCd-e$K0X<9-=j)A$4D zmh!v(L-qn%pZ^4}e|V}82A_+%#R#%Z;?$D`7nx-r0G+BehK??so$PPlmYh6aYOtYx zxWqi1ipLKqq2xquxDrR=>`9&EEhOw)DQppbxX_R%2;?}&XdZ^)14+$_A6C=!9V*p~ z#qW4|u|ix_txITXE7nAGjyRC$eUa@$*$SpkaMC zF%6{UA0l5;8M+u=utQVLnZ>n03jm7luO2&@+LqzzSit!I?IG^r9W=r8DM3EJb;0|y zo?)l*5H;sxBlL!cbO*BQdD%DZ=AWy*V>-agpPVxll+@dfWJ~}069N|^Sh#8dc`AA9 zXBh!ZsV;C4jZO&n+INaW+}qkK)Sb4`I5!9Ekl85NAkX5kOOW&HbE8(_%&#s8_G6k| zU5|z@qQf?e`Hg93c{F*hu@oPlkMrJd^S{^PH;8w2m3O)S&QXBJ9^g|82Q&?o82A?8 z8}WIds};E%55SZUfyo~|P1d49ZdX%;B!c| zHXVl7=5sb_DGOhrL}SzT=pj*a5du{n54#yH?9ykq9hH;`-?O$?+kVOpO{*LU>~f$z z+OW3rx^$%wbI@K@nkLgI*4VmAr-`#9W!iZ{`{Ao8ODg-o)WuZRFu=DYqN$d4!RJWq zTHksB)>GxB*UU82Je~D}SN@}C;2fq8X)Ni0zt-p3u~sc|9DiX=`AL1K=nf{(PX-Ly zf*T9dYKAy}kgjAOE{M)~&F;ZIG-^RnHr8*-5TxvseK@w_DK#Br0=P}tKAyf`&WQY) zS8Z92SSUYIkJ#)Jq$|XD@pKzZfIS1chbKuO!)&Hu?4g%Z%2vjnOCN}Zm*?JShyrAX zsee>|Eb2FE8BCu%J=4o69_Gic*kRhk6yyhze0M*lNq_2H#s}{AIig}QeLnRV!LAdr z3)C7x_;Yta_?!28f3UFtuz>TnVKN}*DlSRE0f49+z4wjoBvU>@Z@B5FtX5W2Q>C(| zEz2O#!g9B=+W=|1cG%Yf*aQix36Lz$9{m%FNJSInTYE9$lGnDxUAI=(U>12++RmLT z6gwfjAExoNeFBhQ85dq-UJ;)qIi;v8nNiK+v^$(heqDg~u)oJ$T%`6kwmH&VdsdF<5;TQ${9J z?^Hz8R48bVJtDQjnF~}mI_9?{P$Lw31h3UvF-NMq{h4$$OqjE0Z+L&ao?i$Qe&+P$ zDe`X^@=(Bwb&j|sjb+h4hSad8by zH*=0FJPtvbHx1ce%&4}dzE2pg4fQ{)hmYSbDGwpYP1rw{50uq&Z1S+>7Cg_XE!*`QONwS}{vA*B-pc${+@6YQClPz1y}2L(Od`b)55YvBAtkE&*8Oj&@3k z1f=lU9q^)aoGjeEX?VSkA<0Y2`E+fD)`g0T`pMgY2OB%P4BTo%OlJ3yf6Rz4ekrLRU?@y z2jJgHOVImILvr6Onokh5bhTcF>Q;tW0saKYjI7>P#1>nt=;h5#24R7JmJyDSrIs1A zy0k29(VR@rg1a;|?q$wJT}YgD@t(>JKYVZ8HVOU{sWyHtvzJW0x`%av%i1ieOqBq; zS%zy|{@RfBmiHxpvM^=J+&Pk*Q-+^wmda{Bg7#u;NkqBkN0PB~ij%*#6NFXY425k8Upv-jz*^C@-n@Z_R6xTH3!LB`gEB?(Fz z20^=GL_j_O34EaImYxCX>ct~f%XJsep((BPs}f;RD1{ICw$;h{f8C%%ye z2?04YeZYsH~kRm`$zCF8Y0?~ysvdS0oNrX@?-I|qxn*SSXXCTZoSHSF~m&l(f0L*}u0Y<(S0 z6dP59{;Uu0AB-Sk z4EsH#|C{DY{6CBjSDUiOXhmE}^;Oxq_$2YTH3kH36nKo8&FMbm_+&31Q)I?@R+f5{ zVJ^MB>KSvCq2GX1TneVYqjKVlxa`FUnd5xx`WmGjT>#FFJ0NtbFfbMzJ(|0&-jBc zJ3j`0|J-xsb3&q0)?=bBMEM=(Io(cu6PuTSz(LJFz=jGZR3oyC<8KtI!hdfm+i`G( zXcnl?bS|RXkZfh7z~1q2O&GwkzTYC?zsS8&@=98PhiVg63?qaJZlC>;+QXQ?OxH3k z9yT2R?v)g!+ss!SF$zUS&BgwS2K**{jhU2z{w^Eek1{B7Fp^ujXd`*k)v7X%A!`oA zKLT!!sO>h9PMqG$rtvv<5tBH~U%D=euZ1l*&YdifhN_sp9`3hG?*)F59uiFi&?wWA z<^I`C|M|qyqgZ!`uyEfgqs^HiB}*s$RRxU{Z5tTnr@8zt;?p+CY5Z01dp{|q$w6>_ zG7TBZB!>%e?j8`8Dix>Ho`jsnv4%$Ka_@Oaw+WM61y%MdF6(l)8J24bVs9q8DL=&6 zv99N?l!>iMDvJ!GSE)nQ0L0)Fb!hAL1IZgB7fu z_IYuyxlA2fScYDxGK5|ojzG?3Nj>997yV_q=oTUXP?5B;M7(4M`?AaeJOyT84`7Jp ziBUS}vQd$jJeM`DNuIntfrm1a!H=2L8%{Rp&cLa^P|Bn8t+E#Iyen0pTicHuFxM4% zQyD*%Sz`M)vrR99te87ie_|hhuUpl=E`wQ4g#$3=;w zvG?!j%|_z1pIlAr<0I4ixuPPH5OL6h zh3WdZ9Mr4aEY`PWw>@I2y|#JD7qX7Mm$q2lk&D_+1H!N(3u-H4{F?ih`tU}nQ?aB< z+}jAlSol=8!O6_=tv^b>^u=k?qD#me!2BO`VQnpV=^pxm5QmPS^Vf&zyn4sw=$Bzz zq^(#k+B6m|kd9J_7`kC|8~jbmSwdOK^y|SSIA%>w4Tzp~^}ZE}=oEPjaWgc3w`mwl z+T;;9Y0T!L%&Td^uNj{vr(2PXu*<=Qk&kb5OfT=tW9~=R7Ovz0{!-JFbO023xIY%? z`U5+Wj>9AXH^ME5w$-Nrmmvx%h!Rou_fM0{QSE6_K80r zNFS;y4W%Rymm`-YXPs?D`frxt)gd47SD#@vG=(pV)vg@q|R! zO%XlVDO4KPm-|roDF}ZLw8p0(ujRL7TX=3^-n7@`=m}A{=uKFl{v^R`lcfzWE`(0h z%b0&K?3QKKsE8d~ZJF|K?-87~wXuj)5aLD& z*o=)i08S#m@PuZ66EKW9xKe5ydopnE)ob3U7^`?g&^EQzg(o-8+wLhD&u*>I^|EZE zBW69*Y;waj6SYI<6Oc2f@VAZV4HBtyCngKl*Lgla<}LUAgfG5NBj{8`;kM_rVE;Fo z+h@T@{l{wHJDj6q+~UcItPP;dY`Ycu_NlH}^MWE&le%czEotHw_EtEQ z<@9ch$3(A?bgf7G?Hf7*2CLrg(G8xgR5L!7FIJd=q~`rWWUg%L_)ihb(M`n#JrqR9yPNs14md`ds`ezBzzma+M`nRu@y5JFDc=)z_e48Rup^G-VPZ8;%0WJVt8nOsSTU zMEaT7^g>&^lx};E7PexcoX=F8AdZ{7rxkSG#(>W5^PAw%4cZ|#4NJY^5|hBbo7T+( zQQ8Jm*L7_`Seyzx&4{yQ>@SMveQ+=I$nhbF!u$v-$Z;)CbWuD_l&f&mU*sXk{ z>asL;1vpQTK3$g*q?}><6MLmk|D^No{?}2&)GN1*+$&c$w?=0{$HzbM)Nr;Y`b~}LaVZ1${qw|?L$SXTb)YE_3${$ zae0hmS^1pX8&rftx*4 zXHO>WoJ*v{fLT_^=rratSDv=H>pJY|4tFzEmt$vo&221h=oaZ(lf?}i9!aO(lfOk< z_uuP?Kj4ezjRcwh%1Le-5Xy+u{Y7&I+4RxbCPUf#vLoDQc$2kBOS*SpEBXAcC++Qk zC@hS!w3Rg|RT%9qN;9a5Gj2+qgJH@Yyw5gi*JoCcptDw?O4WUI%1u?o)9j?U`9 z_i_VROM*V+eWSHZ4tk1ebdWANyS$ErW(pmf74_JPX0c{i`)h|QC*I@Ufk~jkm_GK~ z`gDS)&r`$8C3;Gm)@@cP?N}SuEIUsbkt#dpPX&iuqPnn!EGyW zTQKH;Kjw@an&vpw$`M}HvfW~)8UzdhU+Vh|Jubh}0E7g<8{^-MK^# zDy`+Zh;r@azC5#bcF@`}I(ME3!`dt&9f;JFrF0L{*+M0Ln`|yzkIb5>ywNB}z|NSY z5=(rUEczQy;`+&Xq+X@3_9@R~p0x6SP#eHtYjj%Dy4MfNQhO#}*ixwDNGqQrZ~eoTsJ}QL>Jr zN~EOpR+U5Z+IATZco8A5ITXV!LI@HrIw{tS%4dj(UA6}eDu~jvO`B%hdpRdOwy9_} zJhxe7v`rjWLE45&Zy#YL(Hh<@4@Q59$dTbV`@n3Z9lS5^kjLZ+&fw{7k9Y6NOD>~+ zfpYbI&0Tv?3WqAp;G8Rc=&!^lD7 zZ@p7s14G}4+obSsER%3=q$>&K(n}bwx$Tj6Q?n5emOkgOwH3y47?T+d%9@Qg<>{~* z?ckm{UzTSbF!Jw7)EgN+K2DaE&AirT&$?##1R@NAJ*qtfAvg(E$fr4J-2;^A&OHS| zHSCI>=>Ca_iljf+!{cLwz>g>lX`e0Oj>XsK0WmtiLENoosxkpSgS zIOS)pnsEYk=S1ZWUv4q;Pj;{7Ap&fl7hOnhr7&OInS<15wkluT;+wASG!EfEt}$P*~JE=ErYa2YRd zUOgiEJx*_&KO%JHZHV6<6DR7Op=f*pzWWWL1MWe3xc_r5#m!3p$7b&p-6xZtzb}u0 zj64`~FvLIj`-K!VM>Z2*%g-m|2K1t;y6~z-Ju4{8d1^6IvNWxAGCnyu0b((H@G}W( zm;gdqxOjP{6otnKA^`#4EvKf3ort*irR21w8{ariwWJJ<71|;=N_+c)Yjjb<4zgr} zJPhU?#0FdCoPS%FI@iKO=kOSa!kvwgSHIoh*>_!}Y8e%ZDh^w*FpvPc5!Ou0+2*%F zU^!1A&%QG(OH0;aGHAUMn)fSH0kc`bkfg7$lzY7h8Iw7X1Mnn6)}0ysMT9Zv`#e_T3$WiNbZe9w$A z$~r_6sX9-d2j&N>DH$%&cOjJ|N=r)9r=Ty|6y07-IQFjRHgH=;NG>(9vFdV57O1i( zMPMy>%lSu;T9MW;N)zDEQ^vZ^Y11v5%6BIzCFqkob2mEPo^KtvA`rs%;2ofg$Uq@( zd!s4{_*U9^gAtc8m1t-W4oJ*tRX^)`j|U(&oPWkErn`2UgHdDd6t3?daHje9gzQ|w zbo++15~nE?s-Np%r!yXpZB)s^o)w|MKVE-3SZr_%t9b{dumTpVJXi-9An5s`d0U&d zN$YURAqwRjilX4VQ?T(#!76iaK2xdBRf;T><@u zpnP?M0~e0M)eq37h8sj3I-d2A|@E13_?7gp#$7J^YfT z@uM<|d?FHl?#21BOf>5RBFyCFfXVnN#zvi6e&R?RGDLMuB+626`mB=)a)z6$l0Ahw zV-&0A9$;EUev1NKimp3$9GG%*Nmn@3_xnC7E7c;F!2w z%z6}-I*~UJ@q?a(iyYBUzG8J0depCJzm#_4$Fn%kqWl>{R?2>P-~QHicYqGbD{5pU zE>zZk2=D*s)JS0W{-eG`N$V!{<50v1cqD?+o&!HU$hD{%NydRs-@#HL2dcgn^lI4?p4XSA@;jxjnMzurXIPe{ ziIT#`KQL3a3{krz_flF_9#9}oS-FR>S)iril2#td?rlPD^ZQ|XY7g}~%z^-E+3URf zZhG5y&=BXs4VHN!X>n`Wx(VZD9={j{j`0okt^4o-@?UxdQ~a&K^##~*Ip42^3aL%` z@zR?@bf?ehI#!Hl+&9s)G}PSK^a#J%?fZb;h+Hjl{;fBj=O2hl)F+ z@}ii@N2NC^Xk!E04o`6)epO!cPxKym(?tnB?Og~sTck-I61^eU5vh09=y*IGR4H5w zREpzZ#e!Un`VaLAx?#r0bC`2f-B1@KPuj0~ufA)m>2(UC+Ju-b?_dc0VwmlwnbxVl zKoB}Ekd+xdw~7=&?=Yw7OTWQ&4eJ;&4Lfop);T7WNdqK9(=e%cAeF2$>uW~LWva0I z0Sm782lB;qEl&Ago$}wWBltVFn8AQJN!2Sf@d*U9(_0Z)t2x-S2#JaFS0;dnTB8wD z?AgmCA}G-ZHlj*723!_XD!syF^Mpl-W>M_4gl)!5=0H`n$Tejv(zF(phf|NQnz)Ip zTm`pO(VgGgOrA6kO^0YLDC|5&Q?Hjac&>~`+_bbA5i7RPs-P1xE!vL0H}^2Nf-?Nv z_;={qWL^i?z)%rJsd`X{Q;MQYa=U3|?^ggYU7Ro22;@D>?w`iD`mu4hI|F?CRt3d% z`jK;0M9$0%&`*dYBM03Mwz-Dd1&Z*nE8TVEGw+vXqzvx5Tm>DfijO}p?K(%0+E;#C z8G!AMi|e)rVL}4>`ilM&ByzpZ6|X2Ng-P0Hc)NT2(~+H7Jk-}uF_m4pI?KA816h!T zD`YSkeHz9sT79AkAqtOXK1zh>gbHk4G9?iftG9g&tBG~lv5343ln0KfT56x)b#7d z9#&lf+uAewT?`uM`BTy~^yd$Sgt#petoUE5q2t{1CcZu24t&0#SV^w6|JI&1yDbOU z`LII|4JLTfCp%vus6}AOqM$~;y;h>V37g=He5f)YPwv0V9%qISZ*wHZhO$grFlx@p zOX%pu2`8n|T#&eOjPWq!24&MHNzUf@A}dG2Azxq!i$-K^TVP9?sMxVnhECcL2GOPl zF7hMt-NAqn!92Y2*mhMmsL$MM_Jfusjff1A9_F~2hYkb(<6nK_cC-qGE#kPTtH20L zGE`6Q{Ow%70s`B_cYz~j5#2jyqN7PP1 zgb=8?y1hc9W}r&^L8SXb*=YiyF*YeL@tO69QmSGt{3ddSk*p-=#!bvtHs?sHdDXgx>1`uro5(Fn&h}`*mMs=xbGa3LsiS zTjzH5EO@{2%Fs2xZcE2*5Wcj`maTVBwukr2XEC!CTurk7tupRkzX9+a^NZCdp={nN z*oGp}xI>k41#R0?AhS4~U=8l%CvXB8t2ronui~n%6P!iZVpk-ghlM zKXALOt6d)86__`xBs~gP>B8Ti#_S8@qz>6FKYnxog|!1oF|*hWvXhlZcDF~vB4s7` z2+&(-qXW;B&Ozd&oR&&Og)bybpnRRE6gR%3{hYq69!~2+l&Ih(r-(*gy=k0U0|K?c z*pHCpCGryI@XnCjgiKnF-UR0>b2%yD%&0Y!3Ds}PFO8DOkqO(z6JYo38;BXn2EW^X zFL?UM$xyCewj0t@x?KX0a0#**yu2L!{$;A<#S8swqygP~kNOh{HJRF|NnavrL-`FzcjrLi z(QG)2_#0?{1}-hnSY`G_2WqOq%eTPkiRJqf2D+mfcXIWs}A> z!fozYrj?0EotQRAE~0v$p~!E>t2kFP>EKbu;;5Lzsq2kV@;4(=6&CdxY{68( z?qYiK40SJPgXOnxC-i(jZLB@Rb{Juaj8JKEZdle*-FnydPWOYJnV@#8XTjFO^#c2~ zO);+5uAjo$-3va$>1_9xXj^O&2^aCmm*N{%*wU@vgixGGMv-dj`7s8$q){)r&<=s;#iYYE z7Nu50Ban5e*a99%CN}Md!9h}Y-SS&%wSkl&nre)JlW)ftp-sfPT z(@!l-xflR;PGUquIFW9cS#vh5*5~VtP1c+J@nTZ4nhG9cT_c=5ldPV{&AM)R59No9 zDMlk+6`NX|pxK#3=Fki;_I85rJ*fWE#8#?Ns?Bz(w%{B+{``e&a2sKdtyb)?fv*4I zX=Ar1KYx(>JSqe=2pD@Y^_Mrk&-!2R4QM`)vsU$wi-uio-2TG(M0(81DvFDDF%FaX zW2+_ZnOgW?-!JWi&+xg`Hq8IFF)jYTxOx{DgTmE~to}k6U|g`AA8CGU0`ALVEK1B! z9eh+*z=p>by%YidcIM$X&F|?VOeYP)r7jpZ6B~OzmvV{uc`u}qR2erKA)42(16)UF zvDrs6CLw#=G&@CF5-9g2;t`a|i=wC#9cfrGF&ob~=p~?9KO{)2EaS9B6WCX<5k!9D z8TE&8#JiYp&@JCTIWF7fDZB@Yu6b671jfB-*XS~2xY+zw5UjX`FC>r&f|_Tzm&i0v zf5vQq`KnkaIpL(#aOF+=r(-I1 z{{wa2{EEI+-aH~0Ko(P4B2%L!^J^J666xci9pL_TKdhC$M84W*F5awyf=p?Ka|l`A z$y%v1*@`RaG~O*#BR{P_1;Gx#PF72M3&$z@k30R;qh@|T zNPbR>pVe)SwW)(tzXE|#8e+h;kCB39(8x}2keicBBehu3svAKh9cxb~b-h;2G_Cce zhmM+7(6pG#{?Hld4Uk#hxO$rw=-tFR{}YUv_0QBw}zoo;G&@qd{#*6Vzg_sCll zI;<0V_T9JDM^Ie%j7v(U-a@LSkoP5bd*Qy? z{KP@<`rbMe61O=UA!fF$v%NAO(VsSp$$IHD`tP>-|1`_=xqu%(f*}<*KqW1@Sa<+X zlNqADJ)t+CPgQVm1GTt0TD9y+F!8C>EWJ=$trQQ#;MwR_l|fL)#!>G3-sU1w#=z(~ zIJ!uDo^@h7T9>BH#MQAx>2zmTDy*kM5=@Co)ME9C(jrmGy{yy{=rHGO7Yxr>o$Dv> z;d*KVhNrm3d0Ik&_kRM2%=L7Ns&;{luA`DX641y_n;m`#z!U+o1JEq_v924Z&G7Hz zno8LTw|~KnZ&lOQI&h9@V-nY0D`%CfPo)AL5$crwKmi9%?CAjMBP~J38bk<9?7TI) zJ+NivFRCygz*(3vc<$6~mF6}`PdS|wrRhEN03>;_vt*dB76sU7CSHbFs(3-V(lpMM z*sKXc1clG(u=fB#?Pe0I!rRKPG`~e-Ps@Eo+62@}&6&9*YLeI)JM}CT{*nK)(o0a4 z+M+;|y|Qyr2n-Vh8rQ95kURWeLu1Xym+;UIgk}f_`c8g)|IzWZbY+(hAoaM9K||wv z@o77S3^*MYn-lLr4XZvNw&J&QS=v+4ZVnm3nkK)mi8sLD^zg9EI<*n%2c zHmKkgl3bKa!&`?DTN|+}Sw+L;@#pl-L1BaAFS`dq2Eg;3mN*FL^TLJSdjSF{j8&G{ zD&A7isKeH)S8X+C$}+?8BmXs$ugHlhAgy9#lZ?yW(5M*`@Y6l>?y=>okJ2^PJHr z`uR+`7eedOUogMvoSHyC#gQyS+$#&`Ge80?B-`Mf;uQm*$e8|eFn#B!6}2PWGFXJL zqC_w=16=ZEQtg3Ce&Zf+y33gPP8r@6baMa97TWbMuW`k3B!&qiv5*)Vw2xxn&&NhW zgPB0V6VxZgX4Iwxk_uuYTr=um0X(KhUS_3iRZE>e>JE5BXiI z1e0F3r!K*!VmJpjZRw4cx1!sIC2p^$5){5zg=2qYUe-XF((hTnWTJ@0_mu|L{lH27 z8HZ6PGL&6gD{ljXjeiDQ7EZgCLgF^4mX0tZgsIU>MRnWS9uiqJBy>cOg(U6HzJ%mU z)Mne`7CNG3EO}(D(4yx*GhI)x?d=a?QtPp3=5Sb8vKGC? zs{r`%0lq?CSKw6mQz8fVMU`tdZYOBB$-N`4RhZx$VQ0I}pijV!7S#EuN?}wczwCv~ z-=d9p`u)+4eueu1@3ohP{O^BV2xjP?HGpeWw{S^nX(TdIM*}9`Fj>~R(2i7mWSiy) zcw{x8XY>nTl_KFe5%LnQ4{1tAtCd@lhqvUyk+w9ICDx8W5V;ER+D3A!h4(1|-`y@# zR(^1c@1aK8tSQ!~vn3NWt9o<}=;EfL&7Vq4lT{<*B zeATqs+L1+ox8K`@flJnTSmEbsb6gm=kg9q4nn_vs82TyGjF6|5@S~1>-o}5keXH{F z(D?n4jd{P~(2@@@{q*+m!ihmtjcD#S$gDAltmrpj4B0uY=Z9=LqeZ;>WG1=R;b}e@ zEvPqbZHb?A;!~;CH+cfBBO_W`p3e(PlQKIFn`)^?KOgaiCHK~p=INX3Zz^JV*pDj9 zuhPGSS3K>D+N`q5;;MrCybhR8)orM4Ad+jiI~{Kzn+aoZf3&khx46;7@Gw>vK~?oL z7An`5_7^krwk8l!{vb@CK&A<)u&YU=zT186p>sLg{Ib}i=*ReC1SliRjC6tqA-;7v zn%c=p2C6eei_?S^Ob!KOr|WQ6(cZA^bs1J(y+T&;HRVfXPp#jZ@rrg_SyF;};@;qs z-dSF7C>ELaKH-1fleinrq6f3JXt?=a-o9=99;Jqu28QVB^Y%x8pwOaYlCjAx!5v>B zXu`#6epQu$bM~M6Jv}MML{4l&vT%6iDC~7W7dMf%c9dok-?|99?~L8l#{8M5tLk=h z(bAYGf*_pJIlF$>+a|2UErkN=&7P|0dPDTgz2&n~!If$%IMhhp{}hK2d)x`FdCRj(p@o|4~^22LWBNUwF&RZkMmq<5hFUXl0iLf1n zpPp)4Dhz!hLK>?e6vBY6SQgCq@gaV4LSxvK(@wz|J{wTmc>AFxFW9%xEdyG04yynQ*U#S0c$GABm16QlEGeJ zL5Rkj(90Kuvyk2ZZeE{Xpsrk=PQO1tjxfPTIJx^cxp)OMBq}Vf1bewSyE*-Ty}b@* zc|X71%wGN?UijvXZ^inNXibk~CV?&Kg{ClUnrVal7d(^+@+Lf~3qgpJ!bt#vI4)B2 zxO?EGV7RNd0$+gd9$nEp8AVamDk>~nvHt{MB^WWctr3W_~}lq>oK`Y!so zJb#(IpBz*S-zh)})EqQ!Df;j{^t+q5xp{NM7gd2Q=Db#1wXddON8Xj}-l;D3w}6sa z4!ZZVw22q>nEvJLUUE^VGZ(%_;eA$1Pu;)HQcen+)=HA2<93 zh8&#_?6MZ`MF_wZ9%Z}^2z;a2o-OCjE^EpZst^6+pBus)Yu{bs*b|nj58R@*FjCBm zK=J2VyrIjOV%c`E{b)dS12R(=0##*JyaKLzdRYhK$KpVQ3t2C|@C>lwm?WHX{;vU!zRrHF-Th;k@Q}(N%YzVc)*S(Tr^R!4<{E3kiHlRYO_JZs_3CTdp zxvvycUU2+SZ>Wq<45iH32nkwR3TrLxk`rq&)thl<`8>@5yY@v^?A5nn?%gDubc&i& zAYTZ@4<>E8M8VAN8BG>wG8+`cTqzwa;-4uArsU*f7RYxr3wB1}l$GR)<*A~tCY-Xx z6?Uz&*~#XhaG7P6!;aW*iXIUsTY-HbJ08$4(SuYiBaAIjPvX?}It@Yl>MQcXqcC#nmaW(=NLsgnn#WtPoFsa?{372okTVG~2Wj^co zbIaeiLmSXtNL1t?wSwIl!Ok&wn=(yHFwdB*G}V1EfT+&RD{)C?;gENgAz-ce)8NVL26l@2SL^_l4P$-`B#iMbP>vLoI6_C1)E>4VcolEcqBc^>$UXGPuqK53maDC8jXf`PU-64MxD{lh?^(wD zyL(IU?Yqd1_A4&0+H~sAR+q%~r9=_H$=S1~@id06B;egWUCUo}or zF&?vC!O%mn{4gau`m*6N&gsad!|^;GmUZ97C!a9aU5{X3fG4Q2d>pkr%(}oghmf#C zFtg#1M^Fyj2ptMa6R)68Sbzti-GF1L`K5&>um#Vb+`nS;6Xcov(Um<2$TC|GF~l56 zb9?WCZ6KB8YGEIdF5%WB>tQ7?=>OjRuj;zujfiveIIHrDQk!vwNxRR)%0D z&0PCb{H2Lr#`%E3UziBHGEh1nxaj-a11m!#AS9>q{41Ik=;wj~BB((wE<9sk@cmZy zXfM&r$D=bWCRVYP(}E;3z;uoQ8Kx$s87(fYc==-tu@I!uZ-5RCLtGY7-$>;pJQxhB zdszv3roo?FvA;1WkoD!;5^tbD-H91`Hq_i+)2w{O5UwUMD60fv(d90AX`w6k><=Wf zg$1yKW*KpOG0EhXX^Il(DrFN4VkTXof{yg|NP0e+mgCU288LkL&6Wn6GPGFEyp=GD z1RQbvzJ?cf_|+v*;i6$?tAq3F>{d?m@n$_;*&s>?dw~dMG~p1Q?x0m5QhrUIxJ2jQ z1<`}}2|19@tw4vulJy)@!a~GL#2}-nxPc&Ws}hw!As(qiN2s>h0Z+k3#zurjN~ich z;Nzv>4TAicW;U;~;2>-y@1aJh46C4;&CgxnvDA@LWtrAV zLb^$Atqs|5Bl39AO)i~cP)c6osYWUlbm;AJDlCXPB=|3-NW4oi9Z+&0rUbw3s&>VN z>~j14emy<>?kQz&sG0x$v?XE%gtyPPsWYN6D}}uwi8;h}l)4BK%4wcg)KZ$0CX38H z&QL}v?h5Yj3Z5b}=oFFg?JkPa*`=R4fHn?S*lCL>_!mngma{ioUqH?0BKPJtFv6?m z>AFGgz@-(~9^s>K8}V>?`0u9I1V0|bB>ctmj*h=B<%5%43pC}aso+GJVS7Q)85!#d`**GCCznW18e)!?qS~|?z z7Lto_&tk)!4~kGCOD{oe`Cu1>FSHE5Fy4%$j~xz-`Tc`uMWu3bZV57e%ZL(Y7$@aT zk|8z^t^JEyw64P1{3!;gP)1i-O{6 zw_nxKI4?zHvq(O`^T6Z><5x(Ns~YnFTVuGk#=fyjboHAWVP8Ap@dqa(47+b%=NJ_A zKv&-Oy*mz;zy}oXHpPi<1{gd)TQd63I0Y5Ih*@a=DnIb0*v+v%g1_6qjj5k1Y{W3H zjB#l`S*0`L_n4DNP%Yt&&z#y65i@dcppqxsJQ)b*(zM(5b#;}|2lk2Z5u5M@TBk^~ zV>%o5+Y5XTl^`f_Hrjlq?3sgM#uFlPUO2yh^{o|kS(Qk-7iL4AB{Q`#PCcDYD#u~k zjfn(N+-!IWTEXF1qD`;_zGTXTOd>EgE8~b7MpPwU zS!k6P$-8D^iMn0g`h3Lw%-~i3Ar1nzVY}S~dL+42GifT-{}rg=D|peur+9tVx5GgvrCD38P7Sg8BQYU*LPr>qW{{5s#Tl5QB? z=~f9$LNPS+Vz4wXUf@BYMI2K6!3A6-YBRq*e*{by9OLc}mGw==BNbS2nxi~zUYCkz zqsrnrN^$7QJ>KtaTKO;6l>-l^U!a^nb43+3hGHea2%Q3{pmgHZVHC?ZV_hXeO$^Zq z33AyJyD1zD`Z3mrEeedl+K^nrp#rDCP}Af@^zCzsm++RMf|xk{R687Vnl2BN-MC*cpV*zFnVk3i5giCu`C<&Kmx72jfV_bkr~Fo>6@i8IP(S&rS% zrBDzDE52-SZqlG?>O zO2ey*Tw|T^CWj^}F@sbU-XPmc%8(r{x5;tqZ5@^31H@^li~UN@nR`jLp!oSD>H_04#Jm=Al{uQKL<9bfFQn-@mDCf$ zn>H-F@It_K2_f~8(;~0ll75a)XtShK+!1?6w1dYts3ap3^zvHo6mA5AL*M%78q($T zP%Y?TaYFw!74GY$`pMZ)ktY_kI@W)UM)t_R{v9mW?A7fCWNve3u2+jL(xMk;O-7V8 zB}*+glitW^j6qPSUn5emGgjC^x5)UdEaFN%aFj=aO5jsoQ3$LA6gg=t3Pz>WmS0!9 zQPo=!)w|rgvx|`^u(`6M@xwsV*aNA3BvPqS)HxeGh7a3=&bR8Juzd05i=-7?m1pA?E@E9f!V zNoZPfgj+=yIa8N?0a3&rv#p1P<+seS|*7?M5 zF^qsomlWCF{|i> zSS2vj_AkWa-e9Hh(CPxm55mJDe(~J~g$Im(Bq|7t0t$ebnm82*jiWJ6;f?e$1AWHx zYEv6*2p&3C*ei^p7&)`YptzZD-TVB0Z)`uhh$YG60!2K)fFKdHCR5U1pUM5%%lVTr zIzful*q9W<;qg)G#F%@!{+a`>#)EI{jhn|ko<~9nFP%7)&zre<=Tew*wHN5}Q`(~5`SX;Z!wH_uc{VQYcbwHZ9)iSh3gU+iqR?qa+H4lzVz^Ky zdp$w|!d_qBfNueZ#X$e@GHSF$2lUTQeE!-|hxxbF0^An!8>BC8!_ps%jxAr>vD*#! z4p@^2<~QJ`bXlJuB<1hHozJkcJea5WQGJvSZk-!l{v{n2d-0(_ZH+o{?QPn~38)0- zj2N~qOO*Lhjk3u@>ZwxNl-|O0B$WN`3i90&_50GH&_G7!AYfV%x6RX2-VEvCW%v?zzwRpF#UZRw6iWK^#;aWJcfP>|^yy5r zixyEc#w%YlLyi9o2~GlY8(D+48Q6lE-9eIM^w@&z`j)Ts^AT@EOSzz)*J-XcPiJ1? z>sPA8_X)Vg8gA>yDXzZM9i1z zW^9-2)M3%LLoGdHH<4qw`odZ`1E@6g+B6(AFHzYBmXlaY(LR4zNg(7qENbNy^uHQH z;O(*;kK;Ub>Nap*jn~K~e~?<*imcir*2F)c#&!VcHB-BY zBX{P@?Ph|Z(5&-Rcz+?oTSE?BolIlr*fx_eIaTDoEo$l{I?UaBD|Qkb!g*Fk$4a>y zqQ)ko`+&#B8HQf%PL}D=%oNZ{z$STlzgPIUUoYPo@NPX69yb?f_`Z!|_DHEs0F zjx`(0R)R9(u9}$im#7V)pAk7LPp6Qii{pp_PU&^$kK1yFH{1f3`zqXs7UKJXd7Nu8 zq3a+J=wpiD7?sFXq1yL6V+{R$|Ef^N1^uUAMy>+!f5s{{^x=%mUUWRA@(k^M9ICIS zuP5`OB2i|>5mVRV>>hHgSQ=m|5_ebcsBSaE42rZQ)8zeR;#_TQ-%o)<6e~zsX^yrR zY(A{X2k_KB(O+1X$s<)wZKArq%lHmN&xq;$i7*dHQ1^wu&aPfj6~fl8ZoYCe&cj?c zAe}9UK6Y4(LsfkPMQ8){!%N!?O_}Gwwy?zVcskw*b(R(F6Q;>A5ka3OYxKOb4feL( zq21nOuK(GL1>Yb-4M)%8NY1-Gask6bW9ys}+*o$-cYM67zeZDGq2J23?ku02I_%bh ziz2rzjH(n%qSQe_f6}D3ETT=#WT)fz>U9z1pka0to3_<@TVhyIYpNtXm7aB3zptF_(Tm1=Ajs>8kDBOb&3GM0=% zM?Z($h}(2VdmT+^4Gy<9KRD%#uB5fJje7l&+!BSo; z=;x(9N@9*|LBL=F&@gt)WY6Dq5#QTq^w*<^t~lg1inHeHs!AJ(-1&)kYW7#S+rG$W zShCqwHcZZJhCb~V9lH!%AQptLZK^TI#9!YztP6VjWV+kLK^?!Rjsw&B_422Gd+Sc0 z<;S>IM5d-;mG`2q{5(hFqk`5vgoZsk&?3lTi>3UabyeV%-LA2n1lnSU24hA0yHcF zox`9BO(y02A+6a7)9%fK2Tzw*O6Bw0ZI-k`F@Q0(S(F+j{RxN~8_~ET^NM_(NcgZ@ z#1ZwMKgZ2u((*_6r}sZ(Q5g=cFz?EHKfR3Qgbe}s7y9G^ z`w1>Dj=z@VA1-^!RJyVhebuIM`JXG0hDYOPCNbKk<69f9Tf5$P zO%57&l1)$#KcwCv!ZAwMIm@xEH@)!*d`_I9pTg*#2ro!0stEI9@mhzGkAu^$ZjcoMpuEogbkWp*TLrztrgJ$8NGcXU0%CBmY z`)YHdn}+CS^y6Wa=v$FE?3(5&80j&%iq?-^MDf6P<-eL0%Ypv4xqk;7xC-uUNml3} zi;ruA<=v3I{0$j52!jq*pYfSPeNG2oVRH6tB&KJjub`XAzIUJ0x=&FaEywbQUG^Qy z*vxvgH48^M8LqLu4=z%ci3=`i?O2Q4FI16AJVWC-%B&;-)6l?(P`?xqsMDMTu5Ba! zR+YX_CT@UV-Cp|umUY-HbH8Z-qBcAK#OXoju5dra<~Ho715Oj+TaSO_^iERuZuL^u zyzsJ1!nAiCq`GhJQ_nyp%m^x5P(8TS*dX>WSDUMb>z5Y7+1Jhr4n))|h|4UJ&UU); z-gI>d^xX}Hq{PGMdzbf^K!pu$7S&;W6`bV0%Syf3C_a-nS8AZZA*kg)Y^-Ue^)reE zPMK0t4JL5h6Kj#EzQi9?wc1<-o?Scj1WlRzC@n)8UgXZuo^bR3haiI}I6#_GglfhS zvmZ|HOT)cZA6J4x{BG!iX1&o;RvA-lOLLaVns&(dGYLGKTsO}=22$_$D-E~vP%-Pg6 z+HJ)Dm1UodfDV42Q=+lah;8i5EvQ$6Mj6u!r8zO3Jh4TpVxdVMhoQW7Y~*(;plrRE zxnBiB9 znOZ~pRTzyY%#j9VMWowSEvuk6`{$NI$FRUA{o(r3tt5>4$g6x7iRvNoB&?mcWE|xd zR_cgvxhoi*E9o@l-hTKD`R(5+Z1dcWxwj6_cSw$~pMct3Ubw8it&1aIpgs75ZA6j& zWry3NoXK7zxy*{+kC&vjR`yO_ z9^#X{jz6JHSMKTBh6u*S`lF8)lPRYHe^$_{`93y>ST6T17~{xlE`h`Y6>lpnep?pH z9qA+QaJGVAN<*MW8p`r4atirUh>1wrbhv_AB<$}?kwxUMrB+5ycDs3gZ1e9Z%|Dk^ z1~41a2wGOVZdV>3k22t3f^>RjrR00jA#Fy|7(5kM??=sRlsJ%`UD0E=+vGL?$yYJ2G(1}%9My76j$LfvR z=bE-K{u_L%lvhCEI~Qd!wuv?#_H!`pL?PfCUT7%Px{^ebe=ql#=hkOZur~Q;ZJU#{ z?_qP>*n2%CYfE(qYqY7&8Vha?i>{$F>!Inni+IlHG=LhmP^Yf9q(VFkNP<4yukyn7 ztsyhA-Ko3(Lqz1PwMe2qHtA$pvV}3*j$gUAUTTT`VF5 z%RU@Al5PZ;eS8)|m-7{&Y9=8&W7Lz%N85$8ijxG#bH7u*aA;M%=2>i)#YL!uz=t@l2}L61kZwx&DcFprqiT zYpiVCnRBZ^B=*?iu4)+&QToKh`587%NKze~w*T%8;hw%zAe{*YrL-mHw&}lYdj`qq zQsMDlnB!C3JcUQc^eY(Ljc9T>khd;W?V2n)bI7}7YWkKGk#VU3IokkV+4JISXqTJ5 znlmh{b}%;C!I7?QgTCBGsaBlXhQ5h^;1w{7ed)-pTcE4snw#uQ4PmLCtn$%;V_=Fc8xV-`$O{kcVPZ8<* zs~3~Pf==ZS5!As0p8O39KjHJrQz3}{vTgeSZZUwgI$7aZc&J(Q1xvB6K|o-Hz8euV8T!(LPsQW6fCo<|JQ1-yFH}HC zl{fP##`;~=kn?6~qt)Var=9&A;EVoo^#rbOcs?B@_eXDP?=oX)OoG^#Lu$LX`(`2u z!448L?m@>h3zQRN^y~B!H1Gnn4hjY+4kHQyWI@bT1bUg$f&y2~kimd&7C9&YBX3zi zm$yAY)khfM$b$v!^r-<4I>VB<1I0NUPpuK1xi?{(?YLm>JnwH&sgyeq762argQL$o ziuKI0@tyEIMcjwF3ZD!_LDS-dA32l)0nsUf!R(4b_*Nc#Hs8u4@mqPIpCesjf{{n_ z>rZ%suQLtAAR_hF@86(ArnHByrL?=9rZDI1`oA4k5`LgYFXQ>3c*Ld&SJaG;k9(M# z*_1X_XrCJ6TUetjkcI~QQz~k3O)`MKD=W313&n+s$dE9~I=u6&8#U6d2_oN+`e&W- z=jIqHuy=(NwyVwNwhtRcBXzcRDG|F ztf_cs;n=r zShCg4>*M3?57Q_ZN6PRArYHwqbkzz@nNZvdS%HON?@Ab(wfB2gkP}EhcibNo7%R!a zjLnT|3(*xRI53f031yPKWtH?DaZ^99*T;{WF@@i^H!!R7>dSZ7#mtM=-{GWo4`uK_ zf)CIfRkQywA*vG%k*!=?CYHE-3lFQ5{S8j&3gG&Mdvp5_-pyuj5C7j`n_7AwGFb>z zQB2Bb#Ly~=cQ@^jN{Ids(mH6a&CL)9PiSe)`zJZ59za@lnsXtHmaSy-e zi_F)-&ZN=TWMA#LPZ7tWKJ@4EgNE=P<^aB}=vFS|fWqn1BE~y{qADH!{qs5mq3qml z>DKA#xO`=CEM~+pMwurQzBtZG@wH3(n6N4)Xtsa(~hSiy{Yu=(snBkz`V0&K_6K*E9PVF4ndq9OF#J~H}Ucq;i zGr;C@hYZLJe~GX*=z|++R2|Rp{g+tO`myz1Iemc*7}7z*FVt+Gsh!#VevIDyY!9E{ z@q}VZXhU&JQSn*}3-f+pl=9Bj^fo^i{Ce$ReQ*y$ZssvDtvDo>nL(mNe*9e8G%Qegz9Y7B*HgY8PR~G&Dihp26U&<0t;9_}r7jn=I}Wn}zwgTiTD0 z-^<-nw7l;q9|ZDgb{vk6Ctyw+4F)nt2NAay!^(^~HF%Mk-Kg#lNJS-AP$GJ0lsc2+K`9vQV`=yxHmZ^pa@hKC=@PUhb+(4gC zXdm98KlmCXm|f%&eYqcF46Q!()x&h3onbyD&g_p&*r_s!&hOwX@;Xg`ie|w3N z5zD{G`|O^-S88q$fiPM2dHI39K~|ZYEHX@ILU7)cnsEco z6^F3$4xsV4mpi?N%%=gdf8ajf>U?NiH9){qxLiXRI5-@!zjmBQYP-wV%hO+<8Lzc*^u6LTpA96Ii12E2=vzyy{!dFJf{FOo z^?i2+{*^9)$ws?Uawl#E6KoF}D?~;f7%|?%39G5bB8%V8A(TyRL|>A?ZkHHS6Y#Hi zWa0|U^2Ya5TID)MeMV5WmGoH%&W64|=?ictbVL}TZG*MR!CHueh7>q$9CWTbQ^C+H z?;(}ZC&;}xW=jlGxJCiu#l?+0&mtvZgAP_-Qb;rJ{N_EGos>fWHBxl1gjnFZDTfQn zCWdKlX-RHb4%J24^W6S3{GmfKf-0`1Z=Pg@kQ+L%;CNC;UXBoh*r;e?uEcT*4KWcWL*%TeoZCH&Eu-^ zT0Vt-sMDd+)j(OP;(|Tmq>xL!);}kTw@4~*0=_Epjn-+qm(3civf+&sW|_6bwE0LT zglH0*R6ItNL{cIcQD!55=YRi4N*p1Nv8#Sd34Q~+G9o7)GrBixnC*@@$AArNNIU_9 zIOfUQYps71fY`W~UnqeVZy{NDiFpI1QU!f$FO3UmS@PF(cQ*0ne>t8WJ_TdLiyLzY z(F(5dW9yyi!jk3{<;^L61adIB<49y4#J7z(fkgPWxSTlF^fzQLokmtjU5cNWChFfY z2t!49Hpbk!BW!kosR4K$#q<7qjUjyT{QU#~Pf}v2VgbnRA2)`Duql+ z(j$JycE|o83Z?6$taA#wMoN}y82Y8oljc8opf?Q0WWy%~i8-R{F37bvq4iTl1PMKk~I}XdlZI6u*JGKDxdy+() zHEAT~s3;zx@hm}NaG;w=>o)}?R*((TTtGyp$JvGSs2DyWKUfD5r#pb7-g2Ic!RIR& zq84XP+oFH16-z=W4>8a+wzqZCDZidq?vM5e!FCEs?Ou;nyZv?&G54h*g%*fJ`f4wu zn*fhm1DRtb({Cp+h3xU|B*q}Hl8-nbR5WE9WS-S9@wbuApl{C`HXCaKe z`Q#V<%{+bhSkkmDWr+t0{mXpEeK~{&DkP|8_jA3OP8h2q2nTks z;*ifeB;-_C(oJI!oz1Nqw?|U_uj*@8+1wk4H`^#yLkzZM6)g?f;{71A zH$uG7Mteo)@IGt^aoD3Uu>D37;|Wr6@HM5T|3wn#-$;VF8B#|_rM#;+*l(tC!y0}x z7oGhnc@!&l1#YjIiy1dXRvx%>DLK3t>VV;&L{x=>i&%#1j=#&*pwBOz(U;8K=>oeF zo)?K(^=%|<9ORx&xD&Gr_M7?yP---afv zYV%6`g%#MV%gj&AQO-e_&4j3%OW+LN+h@A8Pu*pOvM*VSz9_~GZoq886>sVk;23fz zexOaAHuK_DzOoBjlekm$v&gL`6LV)-HtAb^#o+QH3OU|c@)Y8>S-h5Llev5!7%djH zx#b(!YcWNLy{{@C2sDLcKaxMIdB>oe)p#&myQH`4L+iUyiC=Fu?22~r)UII(dV`rX zzyC!9TTPlw)pJRI<(3_)kol_t57w^{pmCI@a3SH2SxG0vERG?&aj)`c8YSMH{P`KD z6bqMd&85meFmRw5cXKKD#t&govXI{EceTPoT=0i7$R#*qvvPla+sND8Mszbp|BgK_ zndWHY+57XcQvTk*NYYIX5Trf~a^g-K1|{7k2Hsb@-TUnnGJvJ%u*8<$#%|{DtZ70_ zW)!4bGLlo5e=UvUKLqJu)FMX;2XopDdkiVtyz7kdR=h3WUIQOk+U4r=sq+{P+x|u`H&55=%LmBEw@!ZWPlDVW zMS*@5p?^HSI#Js>7nMCPMXc^oe%VZO@tRx}-6?k*StF2S<%Z&+Ayo_#Jp&OZ+Dwf8 zfid02oxkd_7L`+@s_{6bJ=M!3VGJ`n*hOtB*2(vaVk2nw?eoW2;8<-zgf2x;T5Y?}&S=4c|FK*63>q={^(toGltayj0wmgiu znJ%1ZyQ9;0a^=pA)r5sT3v!#0Eh$noOf+l<3 z6k)~Q2NP;*5G7l|@Qs?VsUq1rPI~(7$-BE&EnnS(5>@TZCZMQDo)H(P8`K9VYH3IC zR$&BVPa%6LX5Vtj=&Ht@hQd%g71?PFcs#v7czE*(nW6mdJqT}soQN`FXy%`LAr2m< zS-3d51D{PbT*@uo`coBJYiG7Iqn2k6)0?cOV)*o4iVkb&dpRCOozodoV1t%XEhi`R zz>gcA<}W20mPd0GN@5&+K^~CG{T@38{bnfR#z>NUypp`XB1AvkE$SaaBaz4FgG*+@ zzhaN3{<_jLd$BqKL_hTRh=Z$i4U0y{manhGx}qVLwm7z%is7^xDp|9s+>DJdbLy5H zh0CX^I~EDN_Y6OQ+JtC)#++}Y)~O5a2m}jISGULL@Bb&t#kWYgj!U7$6)iY`_6SEW zz{lOi#pCC3Yh6C&f2ppz#KC28myfJ{{FCvg)U@0OoruWR@dW)FEy;sKA-%bAuom0& zEa|0yx37j1NH4Bd?-IGp24WOnGy6kP(=*xMlg9;#JnY|LKQc3&4UTnIH-BRJMlMYqXeM z2Q`76$y)0LYX^U~0o!6ox>Y9}-2D6`X@G|a+(HrAvK%&xomd5vT)ONBY;>qFxy3!fF%e#o^yoC)_GA|$sAcjZ zk{2&SeaRg;wOAA4g_e!+VE!$8yN!4RQF!mDvUpxI3@4nZ)`(k?!NE&cCdWB28$9(DLYh2E!XYP8}~_?CQ1lo?s- zfr8eqR|sE3vqkTDH3OLK;O+^3Ju1o1CXBh=dcjwPa7)nSqe(pX3ftg{L{TNlqVlBT zEWb%|;<2?QOg^XWnp%kg#$hOA$76V`~fBD$q}z=5Vi+KgR7iKS~qO~m@^ zN$+1wGzY6723x(k3joER28Jk_p{s)i+81>5ZgaAl7FrBu6pC+>BXmB&uuJRD8mOZL ziq+CGkOGGW;_=sE<*YP-5$PYHuJ>)%r_~I8Cmv8@E3Wih2by&@coP=QTU;(+LN#c( zxPz`f2TY1T`8S<));~u>Ea6m?lQco5MY)gtK5endkqy%fRLb$}jZ{2q-^ozl_aW@@ zxT;P{VOugKQ^^Hl?~C(DWG*NfgyPnP9L3=A%n$6$yJMln(kFaOp53u!Vd32-aI)Ax zMZWXB9%t3xS@F+SB!}6%{RMTR@9{mmW6FN7DkEo`UTr*nJ5V(1)$?ZmNUE7 zwjyUvvgQw8n<)t#B2wMe101*421Fj{hu%MohibHqGAu*TgRFQZsODp^)l_r9Sozs` zJH4KwlO9>I^#rk5qtgCniYtu9i@qL5uTy_M)8-tMWJ$B7=gF(r#_+LTDRlUC1YZCH zJXRz2JBK=%k8>I;@hX>(vks2B(S|R#p3Lir2g^@jD_|T@@(@^9WsDMl+lp@)K7*G9 zz1|E?W>I$?l+hnqk~j5`Y~W2g%UD;lD25^YNs3di5REfT3&*k*KGogOVB$|UAPor7 zl&_R<9pSc$<*&SPWQpCb4xR@aXxUHTR~3fIbe#-=)lkx(ZFVkl{1-#ysk8To0x8|d zuH9BwsDKKRN_+p9&$gS*mPx=-*()MKgn7g@TqC0?xyDi1S+kYGfz~msU%u(yxb!SoVpgz#t{bDBzs%ByJJ129ilBjf-&$dG8wO5NA2xC2g*gKTo8d4U=oS2BkIVL2~3Y5_&t14IPEiI521d3 zWhE?!73dbH9-RtCiTup7oN!$}l0hJPbm3UM7@vYaDV!JWMdeDLR!i&E_TQQeUGcBX zgA?07;hwVp+TSc=_Xp~G#{G)G@);Mb!CW)AQx5#7uI&r{3qdOO2xCPsm_^+xWS9#3 zv%(e2E`Tlil54|q`(a!A>QHv_#-Ga(4alGYsa8~!iB0GM zvmPElD<>|b%0hVB(fKAm&QSw7+aXiMe<~+)N_Vfi*RI&}Lr8L;%vya7brgQyjNOE) zSPK&jblX+5##2=CN3CaVpI~&{$_Roz>ft>hY*JUEXA0y7-$nHi=IaZd?^FSq6U+(k4Jw5Z2SiuKf7%3x zA1(ZQ&ItVm?ZbV-EVSLWk%-Yb?%|W0iE^q8?1<-^E5JhOZ{h-3mmxX;)D3M!O6cvemzX|{rD_1TgqrRg`wSb^%^2Q-eJJs+$!tG*m7| zfy-U)1t5Z3VFf>#^bT@Ut{O^LE5FHHwt_yhONnJM+~_2KB}D@XiXzQ<0_`KSNclB_ z;jW*16q>EAe|~5RQ71@4X@BaA6kLN&`8|Y`w<+`H`uhhY<7e7%{{*sXB-7dl998fTG2Ou((6&TPDh6of$0>=mi?(IejP)8mI5Th{yoKP?TXu9|S8#F9H zD@s1Ri&KoIj0GXcSrKR|(^s)^8i zON??~5cMok5N9PzLoWYDDssMvam}Rh=XyQPbGNG@(&x1P^?YA^bG*~6$S@-JYjh;Q z%j(Y@$FozG{;Z2>v`< zAdmC@^~_r52(Gt*+J`b|8}ndm)%+0g^R1%78tXc!1FBIo$ji-c=+g9PK!boMB3j%) z?&0KkIFJsHl{~_^I^o|~Cdh48ULgl{V1xNoWRuDweqXr~NX=Jd8fctT9T+6c|62+G z7DyT-*Y7%%shK&ki>tGni7Q|h1|1Lpg9$)`AqOhLU_byV5fcaizTELZZ=M?{V1Td% z48WKb2Usty1?pmfPyf!O3E{dbIr+2er|!SvR=hBVuy%3ozAD)trTMtAn=e7Wo>_Lv z(>7?r=)->+|7tU+e$R9DtY$m^!MQFfnJ43N3!Pvr9gZcoG-;j~8v{JMgbG0MzNX zM#shZ#RFY}^U|lkXH9OTP?iezq-yx?{wb4E)hA!cykXTce6qKE*Q7679`qm}vk3Wj zbSB4Iv~#}~(5fGO-cD@{BlQrA@P3&!1R2Z-3%5_tU$nzo*vdC%%9lnFD~P*dWV z>F9)&dI9xGoh78d5hzC+h+H?hA=zSr$%nh3>C;N{mPf9mJvD`OOS2C6jeF_ z->UY-U1sbWH*9hzfN$C$LLs|My@y1S@#vb=Dx7FMpdCN>6E_ExUcl%~cE0=5n&Hs2#Yelz|CMle-D&_@!Me?Zud(wM>} zr`)lLbS>!~MHYsQm+(d*l%p5c$^`y8oz?%}4i~MNr(Q=03H%A^Km>RpR|lXHVF7+q z-~kfp$NxZ#A-YHFLH%ay4@yrlceW!q7l~ zt4H9D--Bu<3RZ-TENaces5<%Z}D0pUts$40oGa-L;zGF~P$`#TIjyEbKQ$mW8pf;*yz&)Tj z@59$So{zdy&o+MfdDz3-n(V3Iy=`@PT;(W0!6M|9C5K5{L43M}@7Q5*^zUMOuM5*4 za3zgHmoDk$HGuSwqMhZ{E35GXX0$BGd0^N@gqA())ZSY&e(u5{^5h$BRX5S@iYHt0 zA??CuYb^Dy#&d^+rNH~fpf34|Drim{mqJsfWP}UFn}9J87 z_bm#PY87?OZ=MjYEi?~Z~Yx#Lr3E5!U!i|r|wl}7! zCl>r|duujB+i?5DAzL*zV@?)=UDgymWEL+UBM*Io2yLO3-Pa9o)UdS-Xv9lY`O1(3f`2K)nm2Q1ZNmwM)D*4$G%|<0 z6Yj-l`ui0>((YUM&rq+Tn0``4oP4T^f)luAnEdq`gc5tN@h2L{`j@M5tVJ5`J z2Xe^AEX<@gr9!~Rg?~+V3Ot|5LJG)8k6Y!9;9gcIGVKViulrE+bo=+^@yYsA=HmaE z!g*FE{7`hxdYASGw|A;s@<@w>sK$;>7$OPf2o)j1^NWH5arbt(l+`Scnq80@c>8_? zo8(S#84$$;L6ibJsE72-npdD7l^s*~c{ImJBTYXwvp6SHEqORMJtiwXP0u_>CwVld zFf}bRA-g;w_xEUSZUTBw^k+CNL)ZO5k|W`A!iB=Fif9!zzGSKf^M7_@*j}w_c z(|}nqQX3Ax?YQ15u&6l;*AczY{r3ihwTJpdhK#+Gy)FA_&l6&s@&S*WYl0|}#a5>m zYZ3cdjFh0t;iiQ9m?zevgMy$mgWE{`GRC~y&M=>&Dr1gslD8d0vE6h+V`VvxZnB@U zEDw1*XL+#+gf78!)CCZC3SXtPa)&6htF3d={1o%^Sod5O^qK8khiD#~v)R9ny*k~u z_KWa2#Irm7tKgQ#ja)oDLei)V6&BN=)?=G7DtR2Hv8j6w^_DoH*9vB;6%n;4!b#|y zHb)Udld6W*eP7i&y-Ew3pqVNi?%#Z?L__J@R>q#Myz6>K+Q8;WCmpfcZ6oYwPKf|< zx#7lUv?EVO0GH40FR+XULt6$%S{p?n^agX13vW#_5C%eTB8cUov_8&=_qEc62oL{m zrdh-te70p>ErPn@{T#FM&Aow(z3D?XM|@jtDQTdr%fGX}hTt4^UW;3ciUD&oIa#0{ z$^xRt(U2PxQQ!HzY&X0?c^A!Qi-3sP+YCfM9%J;tzPHTD*8Gk&QvI!vZvk%I)Q|Qv z2CN|wf=Y}?-P##Q4_%_dnm`)3VgJEaDvKI>oh@_lb2lFB4zU|lG6=4aE0WuMLhqJAFaDb;FsJWL;OskE5+8PX_fHj#hZfedG97>-cF5lmA^+Hbt{ zFLVNP60M*8d+^8D6jSBIM;Y~vNp!OCYAi;7{5I7sA~B!D3eII|Dd^68 zvapEC%#1!+b|N5{_>P%g6#no*B6uFYsrhB1+tbnZE+kfy#6=n3g2jd`=RteT-*FQ6 z>?YDBe_>k^8+(ttmnCnSG|B->p{wwy-Tk}#dmrwNi>l!$HCJPoei)?|iBA+mcTeQ2^9jYfoZ z$eH@cVSeROl5YZff3f9P~{yt~nRfiR^9U>H5p^zPxlv~XWp4umd zBJ}y@i~2%O*)W(3Xeybg?wmCyleeZc3p}Y^CMt))$8Cs~e{mvAJY(iKTf`8=p6TF_1YO((*3IqMher%1y7sy36N&XK~$U>5rkb@hkk0pI&chL4xAi5(=I5 zm}9AjE5RBc7hu{UVZOi5Jy!S&t4__7+gJMY}_)$Qrhrkl+;RRiK8 zkQ--47ux>?mZR^tm8(fV9rZEGsvBHF!}kflDifmEngr{aRjsSzvd-1uufOnuLftc1 zW6TElyE+lwQX<`)tl1HJo_t{X(I^uUKZGcDid;nS@iuS32@=$9`e>WIAd4SGJY#u( zcm`i|Ut}F^zhw0*07ox*NWP~?EawDEWxbQut!a;ni0IPQ`hm9krcmpjy2IJ2f%z)6 z+?T%k;oL&;*!6_q^)r!o=8{~uE&TV1vVqhfV-D9Z2k+xnVAf0w*x5VRelt zXb?gDi&3AvodMpYnq#~9-h2x=218Dz=ZG!L&Qg;@Q94d0+gxkQFu!Ckw7F#K08>UM zJGCKUtnkxPTBS79-x7;0zZ=aNbqIW}Sxcj7arz}{wxeR`^o6oitl*?hC?VD0CC2Q# zh95en8jw2}f#D|$KW~T&9Gz%1Qr5pSXV3vb%RO^7vASve%Vd|bUNVKnkSk+0xm&5W zKC_cugDC#9|VP6vSh()1HJzTS-*V zz4HHjA&6LUYua3Vxoe;Ow~Teao9i$CobaiLS7@h}?P2%A>DV~F|bz87X zMi~-zc9Cw9aOWjdG&%b!zGyWuUpA?*tgYjpvD7=%tK_VDycEcvZNg3n=}Q z#)w|ymkY>Z@gerPNlzRhn_J-VOF)Y)BAX*nN(XtSV2P)JLCQy`2A-v;bKiWzz;~pB2=NB6kYA_E=Su5b4xUF~ zsU1J~_Mns8&igS`E;Bg{*UTB4?*R|z(=|MsNP-zF1~{f~%abVg%%-ib?+2sBa%fQ1 z)2Nu{ld4YbQPN>UeidD4c&YBHT2tFk;w348v!{A^SH?@PliGPY_v6b+QR{XQ!cHpxtb;yV9-=sKrZQGzZDAKSKV-(%ah zZJYPlwr$(CZQHiz{_{4OnWSDS)!pfIcRH25*IHlKLOPqNmEZj7E!`S@_~DgP_K;$B zZ!f`5d=3|5IQQZuCwWPLSPDMcN%~S3{2+r1QZB>vJ8&lTKJx`1Scb4`U#MjUUGMP(xaH2d0z?vj#afe5*~VI5PJAD zvbg062<4c|qUO;}zf_<1PPbEx7Psx5nZ%90)_Opfvd74!SzS!?RT@qjI=H*2;*4?{ z9yd8#e5%Gzf*Ebt!g2s?I1SRBG!THbI9qC!%~j~iHp^4uR-DBc7hKjnN&4TmImX62 zhS5J3U<`$+!4kN^LqM&B3cVtI^66nE$kl(~Y#B0YagALM6~Rn_WBXg!fAiX}aw`-E z2vc zNud~}@bh*Co5Sbn5)~-t-m9XOn={v5nJHll`O0Qywf;+@!AVOMpVm7Y67O+GBkb9< zkMH>*;>>2IZTk1VM>tzJ9B!toT2-!r*#ihB5D^R^t^i(m&@eA$Z11L#=I2Mf4J!z? ztryK=1nkC{5(w21BNOj{(2VbTXf*%2;U7EhUE`%rB&uR6QICSh&(t zQC1yGF57tYd735hEHG*uAYjjmx;8;yZBtVLU1qh6t922~r1$`2&UYEamcfI_yeH3& z!(`Crsf{Z@YS19GG6c=8+t2gH%6l`)>w)Z@5g5Bbw?(&Coe=DrB!4Mtm<%CzVMByT zxc$oZUDRh}o!KzvNhY{&Uk*_UC{V_ms|*1)-r({fDG z`819eAqyA6){oJTh#9MxUBWSW$W~9Y;4P$0SkQgiyQCMrE=WoM2)9k?G3^-(`ZcIg zxrQWpG^$Y^%zB)l#JQ%GrfC2ZI7Y`C^_M@_CCebc+I{dOkV^<<( z(2cwBs)Cn}VaJejvSg@XJ}l+?Ky-}9A_DnTN<`KuZ@i@24kFusRZM$)%H}3p61}KZ z>?lDv5a4wL0}*K*lpLTN|5wC;in9AG;IGMsW;g+msqjLy%};{+WK=PaV0ZS|JFP|PqOE={IBe;V5XI^(EC3bf65iBX1{rAeOgUi}#4x}^qq|==jOlKu(KptKJ5q5lsilTl0B(pY(m65KQ0UE>{CCQ#nueG1Y ze!iD}x7!oxIO?IKU~~GBDLW^>XNBy3$k&H0+%tSor;(@$R!WymUDRdInk8tRnm0=p~Cd zSE?VRe`>wh;?2$xcHYl67wXzSK;c?W8?db+l4m(Sm z>Fx($1lh-HAuu@0Gax@nkMPj)h?`X;8Xc(6=gLfj*7o6GT0)xO9Ya8?2EDKk?x7Fr zz%mdn^Rj3V;494oxY154I(<}+Hh|u%B)!1GA92gKwXh^kTOjGnc=8+1$qt~pr%OVO zq!}5JGLBkKm6v*y3%8DfX6iHG=B{A^Vu-x+ zfmO69I9!BaBPi}rg7?$a zyH{`kRD2i*d^_P2H5T)x$NGr%8e`#Jiz$)~q+kpa$MmQoE^C1R&iTcnU0?~_Cis9Y z3!IA@;-f>$Vd5Huy#OO9Z?``sPy|p$2O*I)<5eA<0JSR+aA5VZxex3b+FG<;A)|Rp z@>?wj<02u*jw@i4Iy68+&@h-?ERc)gNM18AJChg6?x1Wzd`?)W43ncepL7hU+M-2^ECwc z>t$x2@!OF2y9bj}T0~9X4^)q$Fg5YE#9_)yaR2S)QiiOR(!iS~BhZv&IExeIV4@`f zU&ZdD4irA1sJP}DcXMX}!p_r$e->H4Vn*&2uz-{pU0F|6t*e9P{E`ve zdH%FXJW`$Vwg4^SDq_XaI6+g3)+rZ(7*(9`%``c6p=7`z1)JWrZKhRGA!JZ>$4??u z0!tQ(RZX*d)e^B;+T2G9{1>PMc$2cpc5f&eym7qW*U)7j3BN03ax_07YN!xYi~#D?dER1x>>Hi!2b0uetZI~j*zsIx+KS14kzrfuv4zr(UBUsIbjAa0`&rbvXypD6lnID z5(^joH5L;F?mwx;^g>;-FT7~;4=rq)Yze0Fjf_2k51uVE#_{->z$E)_g;8CD8L2`M z0IzNCYP`*?&aieuRwgZ|jDnH`%ed~pE)7@(nC7orC?pGWIyp>_wMBU`yE{j8)3qxDLq&tM?yjm`*gwK2JPBf z$TcuZV_0FxdlZ7+Ld&;ejnsKOB%cGr7&xnI?+an~pD=eN{N!crBCS*Cn@!?nnuS&Q zZa4pfeP3fdM>j&5dKjJ^Wt z=%_+F=8s;Km!Jdwo(-b|-LOMV+#iNGPRT^OC}4`+z>nVgLo!>-H6;S_FNpYVHqXQo zZ^Ct+cv(b+17A8usynX^@y>NLRtmFB4``;{@-{LY@p-+QIUYrM-aw4hwba7up z9sR61zG|9u+P}!Uu}&Y!LWgKNTqL?|yG@|wX+h&1#n}661xMuc z?S^gGRVeD(k)%Xz4aT$AST|W;v4i8IsLb&jL|V9U)Z0?zAb=H)*EoUrvYm@5iVc#;Yf?+kKGsq_x~>1D zRJW+NiD){LZ4E7oWtU0*`>Jvdz(q{LyJwbtADbgmML=D)q}pvZGicZ1v#_(JFTa?7 z$u#j@a@T6Afx>-}ma`{w96DzHT>L8;k-$Beo>mA%G_Er}H1xi4x*)>3qAQ$LdeE5u@8Oq0k-hCKxs^p{5w)dZ9U@9xqcoOhvSSiK;>v|^5u*j26(NY zRD;X|ynV1B7dFIhRa@ZJhSAcKu$Qcv{kS%ut(s&ZBc1JA&1)5qBwL9IVojbRk5e@4 z+`L+=&)7b^7^O6&+II-L-adTmH*5Ro2{lcIRaKU0BW6Q<@HHDB8ngK#&D zxQN--VzDmLS9skPt>orI$j5qWJquOr(#r@Q2$C^bK`8sN$&6vgd2epBZ>bS*m9TTggR&+P5HVL%v0(e_-5mY0PZ4;9p|c>+8hGebyU4hjbt+zFJ{fuv4m%YB%0lmWIxibgs*55Lor3O)GSbCR_ zVpRzKZAWAQ4hxJP;Ud01{S$WPmex&DkNzD>teH`ssd5cJh@=n}clIU&EDPf?+Xr(qt1Ex3*2r&z!yXI^l)Ap5jS`A&$moAteNmj`VUji?hfA!@cr7B{X@|&XU-OhC(B8= zsNcWaGi~w{af;Ca&+%ozojZrLrN@mjQHy^Y(iA>=KKN}N^aZOfo`^75dbqClY+r(7^!vgN zgN*2A5hFJ^&WgXZBVgG1asGp-8~Ebm76>>24^SxjVftj?%!BV&a#$SSG<9{qICk&F zW(KyseLjAcafU0K`((}X&D{frzvTSHfP?%wPt22TnDQCEmhuXWgC{Y5#%#Rj;263s zE9U1_^o}>m5 z91v8HIJ3XZ<8CkV6qQax1On5KxDCSx%NJuB4kg$p)oJ=5Jc}o~YV;MDlX&(oh!0Xt zJo4uyOsNR|-%}JH4X+k}+m06iC$vJQCvJM_(amwQx*f+qI=Jx#Gbj`}5t>F>oUKF@ zl@migK(Ac9`}lB>tO!PQ4=hXPNoa^B_ojgQG_k>xv+Lqz%zX~sf4gz;Brs}v;HgJY zYN!eZz87Tc6juj(dIP3)@wt?hdu@7=*j-T2jy7MrJ9)%N5nE9xf^Muo9PiHTzjxTP z>rY4-dn1PZI{O}t)3Qj!a%7>xT;cfi`?!Mya}(4b_27Vpbj@KT9@SLVa-4yKb@54> z|7Ke)KFvC2-ucOW+AXYzMiunNKe@+_Lo_L1Ky>!C-$$Dq5) zV=PbIimC|+F|3!v|G;+OCEaBC$GLKuqhNXTJfg6GIDiNhWYaOQ%46^9z7K5gjkS_? zKd_|ncG}WIOU9;HU=|11AHLF_j_B*`wcBCEc7ld4IpDa;K&FJb@@~#${L=UfY}OWX zy`bu;$r3KZv!?o8+Zs4CRI-dqg7a0>frs7 z7r7J>!yNC52xZ>o6pHu&_rtW+XJ0HRdyBTkc&5b(X>JtZ!zVNK{b%cGsxGU{zW+>^ zU{q|l)g94Hqt%6E#i;!Ti_+7FsFd9G8c_kW@$i`RKqKM#RzTm^?>EKo0e|;Y4Js9h zLj>V9j3Al}ElmshD1&saL7-AoC%K8R9bSAd7e-H4e5Y}>X5LCprpx20RZ{V;9uBu# z63~FIr$|C>3jiAJF{h)k9Wxa+)cX%HO zy|XTk1>6OsE(9Qt9r_BbH2ep1{2g0)w9O!{X@0^-w^An)szd)uWUOr7&<~LHgH6Ym zl~t>cPYNH>);BR}%B{#k<=v`a7g4$LF`zdMBuxa5P~`u$O>olC2& zewO4IsTC zWsm~cIay30h#&q+BnAJwR?Y(`y!#6PcMvJG#sSEjqab_(D)7ZB#sXJPJ9R%gm&C}n z%pQqnCJQxl)wsU(Cc4w7&n-zS&`lOYpv(kG4hhLTna~Z&7l~%12}qqGS^-JhxKNe| z!kx$g3H)drySQB3I3#JG;b34?0VLU01Ie*Mnym&ydYW7_vA#i{A+jgnKg+tn8w_Js zkN}FA_w;Wljc-yPNr%z+kas<9k)2Nm9^A;>aM~`PKKHn}^{gj4dfUJti&MZ~X|Kb` zd5%5FgP=3Ya~XjjmwBKl078d=oh`R$nG6hpBThg8wpenV>SFN@!lN-V=M`&Pp;Bl~ zYMpw5zs{gb!9o&%83X59gGQ~QZ2}vI#0+kz24pxFLH4^wyxw*6G7J2>cEmL=U%>F8 zY6MJu-s(H~k+vuw-tGMed6{ucYF{Nq3X8tOLi8O{kkC9g$c8+P5rTn#X zc3-nMjYEVf*vNoa*Y;twsJCOC$lT>x5rL^A`FsFmxonS(n>!I5ObEZz~BpO z4(aT$iGAbtn=5St+BZ(<4O}PQQo)T^@a7iPTc+Rat?J~klQ#vaz1az(J&Zb-qzer5 zME3JH3{VB6bbGumB9^Mu$%V|w-=E}j=TqE(A9`?2eymu(Aw93B-~I2S`R@GA{t27C z?@jS7rGgw+}Z&iJic5!;_=5BmWX`CBB+>!l=SW+>kn3l);_{#h~o1EgK*3YBf>@Dh}{}I%7on-(C zJ_+#naOj$(!O&|?lu@rE*6;US?_8Vpy#(33@|dQKV6jj(!v`iUKp(A%ugOYm(LxXr zb`5*mjDhm>1&I%SkPi`Y@DWgTE((<8|H!M5{-$FDXj9v(0QhKXo^udw)v3_BQ^!ro=JpJ)8?)u zT*0D=TB=ogNG5_bYE|d39Nj5!S1AAGIM7=%`Y9L-hnJn|9+Qz;zm2%|>i^DWnQ2-H z-SGqClvgsTGM7P_q=>G6Ge+^kZb_!_0I;yq+2iOrOQF&w07B>a<^#k7y<8miy#g4iJXGizP+s(hHyng6zLZErPjrORb^S zM4mq74XSn&Cz0${opjUqxKpm^52{H!+-F!^S852-cqa)=@z6KER8QihIXM77H`G2b zWMAs(>E8#}CJ$^$0GBzubCnWZ{5hH~5s&KyaT}AQzLv}p4O(|EfB`?zA<;) zs5{@lblmg{{Zz?x6XptaTUo;4CT2r0v}-P8BL@k^%+hjpAQ+;_Po$C<${@L+zJTCJ z?o%r6%+YL*TTyJZ<+%?Ua76m6xl5PhKtqvRe|p)g+&aX2piUY3CyCE1)U%TNY)P?c zy8fla9kCDwZt*02qps1k-DP?(ph!_F?tw%oA&huTC!?!%WEB@dt@c1;`R70;P0P(X zckr2i46#0Fx>N7IM@iakHJ@9CR0Q?zL8Tbnf-RE)IiwgnC)@(_Hhm^R!pK2)bkg)( zT7b%{z#BzNZa}*uM@eRo<8p0d7Hb8}42RzFJ3F=Mdi&)^ z+b(sbH>lpe#<_>>3zn3cr8%I$tCy*U=7V3lo}17E*hLM7S7nj`d$ww z22nzWx*stwd{Dwl9Ac3>att8-0oNW<&BsmN-jI2bK$PIV`&l^2tp7}k&p3Kmh;}p68l!ayEQLX?BpO1Tl_EZS=xwk>pwQEP8_4$ zKlpdB+iye}GD8!R7uae~P-RwQJ-td`oNTdpF%nXk>)Gt643+rde#q{%OK~wEY|yn86sD|>wm$94+wVQxvn3UEQc3|w59mrRkgN&n3^h2v z3F!D1D|Q{;H;UgtqX9u5E#?2M#N4#qVngtW={2mQ)E}L;Oay|RGu)?e-6WC8qC3c= zcL0)Ks2ZXXsUSIi#`@0x;h%r~QlFJy*sy>`S%a3CKAxIN&%ash6a}x)UT?J~#>6$u zTVp8aWt*AQ6tP@FRjRICTS#6cRdNP@6_NI;Xj>BClFG3S(e*vtfd{sxEcQ4~=kN;t(eFT_M=60op ziv$6}yr<2@R~`oGxN^nxG45f`Md85#3vY4iY59pD5e!>Th3$B0+~myWsq>`J06>Yq zRt0{0ixWIzlbE)t83K@mQr&E@;2Lp5m^Bb1Xz58kAg{w^w55uq)X}2S^1-Wtf=U%- znSNq+?j-y8u7Bs&fdWY+F_d-AK(ph={bBFz?D4NWQTXnLA489CJQ_JU8aa4=Z&Cz5 zsz+;Irxw!ji1@j4v1_htm<)HaLJmT|I;3{x2DDDv6b>Vlz;#>EbHqR4_pZF@4^F{R zfjS+dtO95X#EbpNfZxvIB_8&GQGO}oA{~50T-IC%86vr;W+a2G)RcYk8Yd5Gxg0|I zsNI(C)$fn=|>pRf^b{xPugem{-H#qo)8PDe7TY!gjs5K4@*DnmoZ zIWyZaDT{Q2bgR`Bjm>-<{P??Et8IWYlg#Oh#~~@SFYQxfw1?jyFCYxK0;QRSzm-Ep ze>$AO^i??x59n!IJjyqCmXaMu=F1!ZY*;SYs~IU;{)dd(~D4L&(q&CB-qrzXuL z<5Y1LLcvz@eK}EQlR^WaxB^LT_y-)8k(GfC;7915tz8QoWqG845Yz!WN0?__acRnz zX>|dWdFgHS6~+zua~qgm%964~UY@}SdZn<1mf(KapdOcmUX*=jwpp#@Z%Nn*g#Kz( zMbsD0$7o8Y79YO%w|cG!hSg%6jntxTor}z+;U0&F?|%-(&!M*fhXA@zAz4#JNz?d2;m>IRA#rf*JePmAwj?j^ zL@%6C{1DROl1L<}a865%$!;eku8!-tNeRYu8_yJ**^QB?M8U%Rt&27?N*6`lc~$2M zLXs0-;c`NnWKm&`Wyg|}WKJHx-rd~Y)7KB5UicBgdrUAzLPLfKP^3Bj%Xb><{<4#J zpW~YQQn(M#p^m1f7|VW=GHO9&U_^T)8v}#rehjb%c90NE2n^gIHQ3I{!b@G9Fo=|( ze?RDS9nW_POd_J7OY?!Q4o;uFLkX$*0FeT(FfX~`0W91kWEiiq7mHV80$No(eD&+ zKnZHDqwNcVlUjqNXvkhw9QbD6Ymc^5zt5$0!;LamtMXKX^6|v3xfHVAOQNjjP zd#wVLc2l;xjcU`bY`XWn$gR$o6X@D$o<%bebN>A#=Gu^n>C$22iY$se`595%OQ%-w z_LVlBf_ipX(MWnlCUXqx@uFkPDsH{U0(ozO`<^s)E&$iGrSabp4>%94M`}=Ln?F`I zUWBQ&ovP#D3S~#<=ki$qyF2WTy{ri)i$*FP$Qps;KG|wW_!^JpI(CC?`$m6$Z($MC zC1z{sBPVk=6b^80X(4+O!tpdLriUd|p{1l&!LB|SCjVkArta-?ys~_EPi{Ex_Z!*W zqR8H{DW|GF1TJ+Anfr7I{kj1`2)o}PN;*C4T5@=je8}n0JyL4rr(V02X2s7OV9|;{ zjC$wXextAu3T{-?BF0Fydz&ST_nhR9rxvaPJ)D2`r+iLi~Oai<}w(7 zDM=(_&H z4uJu4z!@s1ir|^?YOW98^!|ETazMzWigxbi4dLbnQa)sni@s3KbXK$Yerj+?XHhcw zr-GXmmE;IfN5_xJy;O#Mo1uyiSn2GOL(i?@RoJduq}L*%y(1^`7_oiuI=m^I7reI{ zFgnv~0_1}^+PrE`BeIIDXGaIOc=#z1^|(bW>#tR+lM5L6EGdnKlGdE3H=iJ-KoS3N z_BXIDtJtC8y^PPG2Chp@h@ZOMWjR80gxpMFIlWBAT{dXoU*~d%MwKvm5g7c>L3Rli zzcyH0p}HDYgQf6@X_Zy4sXmkhqW2i`hU@J>XP*R%tD{ixG;wfUe8SLJ>n*~cX$ss8 ziZ3Q07%)VH_1ur4S6X^)BR>A)+npqX>;u6QEcWQQB`O{6NXO~qdTB=r6!*WX#YCe`uTwZo`bTt0#sR=-hF|p*f55zy3iHhsHT@g1I5Et)SFj=EYgLPar$nfeX6IH2@;Vl%TBRB*^0A39X@AJX`1B zb6lWr{q7D#Ru8R@*o*-2&YG*Hkp)#aC_PG3HQr-s5Exh`m+e@p`*s#Q%fb1aVHRH| z!D5$O)P)1jS+%Y&%ik~~CCI2}>;<5>3g}d5JV%~V(oQGSFT+}gL+N=sjEhixU3LfV zcGg)Sx;S~{a7|lZ?J_5DMdrqR*(c9Wbq<#&r^68y-A^viP4sl>f@C3q$$m7S53)lH z5MMY9=IdViEQPzR&3p7G4$?lq=|vx)1W$@$WkRyl6}kj^XIB* z080hel)A5xEkiSGhn!D1T;WM?k7UqrNSBMPT>YK`%fG;XVbOi6{<+mm2h%QGSlA$ZU-;fViW^%sywcHnpq?#e}17~Sr^9kveyo3?1|nsO zgl%Xi=_MAQ;)=Gd>{D&#&{_CvsppVv9;u{4C`KhZyLWwO|F=m~7e^GSGUqjQCt%oIK&=SbU zd9a;8#Tt~|IwpF?N%lu{IP^#i=@tUenWT6|5)D&mOPQIHOj%;XZ<3B3sg!c6yu>tU z)ag#NOCm&lS8RWY7AZ6e+L28jJyLkHUD!63qCS@bN+2VLK?sIrF@7FjW6=%H8oGH- zl&hK8u@o|{8aHkE7L~qfCyD!0BIKG2JyQAOhEgQ7uLhG)${?Wvs`k-_P`77F<18(I<)@n3sd zchQWk2_7-`$Xn+e2k_50E`(BQTv4}-B_$Yj$+S`Fqf-wqdbJ#R2*W)9MfGz!H6)pV zz8CnM(u_BVK(-2mtT1wW`5hZW$8LMjxTHVgRw+0_t%Xt3z&Pd0-VH8u!{m=~Ua9SV zHg9_Da7=Se%|qQh#tb<{NH}-6w>fPmHeABL_S@g?{A{*ADz>V`Yy&>wa($(obmC5X zSFitwkVrPQdV1U2b`4E#ryR2Xq4T;A;0TANWBC4fAa!zF-F7)E!5L8(@6LM#XJ6n1lkxcVhh)o-TT&`zrv^wQ;&K8UVnO4kO4$$?8WjX!a?Vi7s;}?s z6&xKj79^uNedXf__PW?2>XGf!F9qJfo9UOgbbGZRfno|O+GA8qE9kN0$cAbfN`jhs zFidZJ)q98Hh~lX?M}*;4Nbe7b(5aJI3!^je0~l#*Z>8l zM_FKTfU6UgD1liT8Md4Rlr(7&a&#=Jb7jdjnodA1rpF3^x!N^_Wcw?8<&|cR1sO>> z`b$F1!n|Uv)%n9_Vs=|&K3_T@?Eo_*lhDMGlm+@D3?(^~C6hA5BNW1DC=ih)ZLqBd zBo0xxJ#s#}t49bn7MrYW>Ji3>RLMUGIJ!2akWV|mve-t17u(YyF>~7FxO)cA*5O5V zg9h0y#^{d%+k28#!d2`ng|pIqh|{^@skFIOo$*@CW@J*MQ1BKsBo-Ot?Y)--z$ZNg zeuLMf?K;8IsWTB8dmW=fJbMZo=wG|LUb0MePi&vVcZ>1FW&SI$50jf!W5s-LguM3R z$Sk94x7P+|+?Q?E$|9r0r>*U0+|)S^Zq7>F0}v`1&c|xf{A2dFu^8V93=9$XIT+9= zYgD^d&IbS>VHsww<&Lsg&u>#5KcQ88w#yeb=XHff+q&}2ZH*=-i!@}Yt8zPAQmK<|Z5lmT^2VDfb0z&D|* zX;&phP0YY}#deD^l*@iYUHit}66dCj$xcPPRVn1}%;)1zH*^X~D#-*^0wwM$!CE>y z@yaS~g;AUjfLr)~8i`|}S>8N?*X?T}%*{e2_Yt#L8F}yIP^8#wkE<=CGOW75o))eF zwrbw4o{kaA^B;_ZArfzAGXMPzD_3{RC%Dy`91mbk3$uiaTu14}eH^e!B5b%P*MpUr zJ)t$&Z~w;2^TBovZl0y@nPL3et!^iDzx2@#H(=i-Y+QVNJB>AnYWRFUnD4_30oRc} z%dc%l&uxY`XrruO2L(<1h&T19_Fd!dU085G6R=Y+^qc%g%h-{ANQqb{miy7ee<1D= zOxMBr-E`0?G4Hj=FZVX9p6WAMLcT7$OlOQa0p}Y^i7h2#bI6<{ahyDNv0f^Rz}`(y}|9RT~p3YJdI0jm2JIU&YS}j>o8x7o?(T<%nPoiEI9?j z)KH3HoDPPc>xYkSzolZSMaiQJgmP0iNwF{mzd7iRpFoWSe(8d=*w`5SsT7b=F(W)N zmH_Z}0ENp*>Hy-73x>e_N zB-Uq|mRA1JSv1FTvMxkDmlFePIBZhY=w3_>Y#exSA862rnO1devb&}>%yY|DV_he6 zW-X>tSxkV%bpH6@eU=N=)iH(|>_!=OJ5m3O;FZ`OWq-l;ao_21%y9UaQ1!lX>2bIg}%Osua|TN#qA zWYc~2q&u@php&JGrYK~{ORTO8wY>r<<#tuJ-M32x%?>mdcw(Wn;ZQ8)B}1eI{=&gq z7^t=5x<2rydC0p>KDB-qVcz>)1BMQ6r1?*F(WK?Sh7R|pUj3XDmh>XZhLmive1edi zj0GV`V?C-@c^A_{N4V0*ZE_aE!<|T8cKY&E-aJDHVV7L)sJ;yG5R^2n^1SRZ0hl8& zwvkgGjnWJyI9jnXT9I&w3iU-8i2WbE2g?+dzPZ+zw2ZFIl|paduEvroK=ts; zj8vefZbBd|7#3vy3T@S#2XP43eCB%mN?WUxO0`O{y8M_uP+2jHj6#TrwP1`3Ia3Oh z;gXn(sUxVWiul#QWFdP>i)y=OAo8X$P_M&MU17lY;)Z=aU)HU$W562?gAO+xy;*ML zeIou(zocL3j^zi_Z^n>=nuI_?N$5L!_Ip|&G8zo?`i|^J8NN$QLCu&1#R8;rM1JYs zl$wKquEX!ls{G`h_>5$ee8D5_#6PuqI)7~Q+sG@5@3;Y;2zil`eJ))GoVV=8X~f4s z4l-Axg4{oY-)-kjR)?T_mW$G6%mxF351Afg0adhGB`Ba^+2lh*b%kUxyiW5*sANha z`%tx!SdaaBu;1<4euK4Ekhr($N!ET;sb6v*s`vg)c5ue`iGKHf-AUh3h7GNSI zm&+at%NBtN?E1=mpAoeJXMW0R9H#dkdX+krLPQoNxaY9Uum+;!DymajZ8r@;WOqbI ze7p!TEwp8Rt8YRVB2{Y7-rTf{4zadNVi7*>Tc6ZPF)&F>J`cLO&M+V|Heoy9b*jph z${*RKgK#0EfWKPbvGk5HdMFqzh(gZla&X%_K{ALo~^UXqYco^d$}j2W^(9h=?a+XQTw#L{s`_SA4y z=OO$bFnozK^LiWli2mwJ;p6tN8*{MXAYOY&w>yl<>lq78 z*v0$TdC<4{US=HvAR6NAL}@uA0s(XJkbZF4*Mqxz55?G#pj#qH%Mzs{i{)evGA#i~+40UcDrnB?4{hy)n5YzX6eNB;@ab0^1LS;mTxnMZIPd@Vf0b;`%ah-SNU*>s8>mfPqpn{>3K^ z*9RC0Ar*#onu&Ln=Ej!hR*G7f>W0@Vc!!^yK#j;q12j!TH8+{LXC*7&%3%p0e9!1H z1`pX|2`n|`Ya#=Okwk>xx4cZ6wr3{F+`7(g^MD@W@2+!k^AlL`#X&QF?nv)UWq$ZV zzVyGs`=F93~jAW@RzYbSSU#030TJEJu8X?G4&yMey>coZ5wa| z$zW2eP|%UsN+n-t>=P1&At+a*vIhI}DRxWNK}lzjNNPb4XN5}y^);V3g)!#ju{Ae? zb#x7O#HZyJiw23^y$=nm|rO7p%@x>!imv??X$9vTl{9PjQ?MoN22ui>= z#|)c$PVtejG&dSs95YRLh|^D80tyYUyPJp}W{B>y#DkEcVbL}^C2<{Tk=n+sW{v1b z7V*f4C4P$wc%UAeKlC}hso;FfQgzMAgTgHAEm{@~w2A%G{!Jno{aH;s@_k>oID^Qs zEy}EwI~bK?Z`DkYA9tcw{Guqqg+J%qZGH0|)Kb_QUbmI7Y0%=VYY<18p?qa(sjQa- z!Cg9(j@_b+wjCr)a)g{^QaG-)CZdoulf9y9zT&MaM`Sxb?_j{hC1TE+X)lZCR>;tN z4r-6d{?=X(7_4I)u|=yZPErD<5<2&m1tkM|l~glKwPO(cRLGKdl`uqI1+CXI)=+Wr zd@L0D{6YNZi?Gubx}|0HCi{|mUKqCn8&wIOOhB(qq%^v;+@y3e?2mDZa2=%0Z^4(S zi@TrR{i99o?ze|ymX_!I@^@b9PlzKut)K3K$O-Kvip&m_9ww@$I|3Q0Q}ac2U|{w$ zE)haVr6on!^=d1gz=#)x=HN0z^n&Pw(| zFWm`t@9hRE$ z9dnf2?;1IT**W~#!)=k=;-SWcV#TpBh?yy=+lFt_WE!0Tn3cIcPv{N+ogI=h13j>hAov&q#!W6SQDAmyWg zK2k=rOWZJfM0sfT>2Un+BThMbd-CaIas>#+@yX>@%d_gLooL8?sr3XL&E?g9_yE*fXTrVNeL<6y;)>-~%a z8$@Uz-2S*#Nb?&&DtY6uz8jriot%9@mQQA+o<2MzK3QX=+@#JQ`|yu_>~zCh)F@nJ zI1FbW`!ihdIEbQz+xgol&1mfD5$wI%-{0Hb|NGv4A1*JBNZ8$W`xif)21}2@2HL>_ z-F&`LX!A3>En)W$Zg6Wi-uT&WgHczI*sS@fY-W`6b-w11F^@`Jp35=1t=1WH^V&|7f@GaS9MOvdf`J z-N_rECuM5?DY%y7Fr4E5fVoLWvmT@F!Yu8>UU$%LxBMA&v{c@;gI*MN+btpc^&dDJ zV^Kbv58=Y|*_;p6C!#2}+s)#M+d`>l!P3;dVRh{e8h(-$dhrzjnPQ~MKjky5t|okhgd8fVbCc2j?< zz55LsIN5Q8dn-$lDB+F}E@L7f>4~w}U=4WPZteCkwEuoOd`;USZB=A}1GV!L?-)j- zhcM4oG%~wIbG4aAlu<8G;=aPn`k02K{!J*hNDxBK0`~@;mm0WhI=Mp<_SDXW;W11? z^`hk9++@@^u0QNa(Dtf4J&#P%c}URhL+`peAR=X2R8W^%P#Ew=Vyhf?1cB@kckveo z@ByRs=w_xuMmUrTwE99Wypi_%Iu!sTn-hyqG>1f|HGo0v3j?=ZvWEEFW4ew znbI!oecS6p4ZU5e)v!);1MHVu4+t@Mz*LFWG=A)qLy8i#A_~z)hL3V5k0Zq}Ladar z^)X9MvLd#o5jcv~t`6#@Eu_}buz*aX(A=&>3tAR`qHR$Q+UtoZ<6tGy=N?W5C%R-0 z3q56sqMecjOsmKeMKi(gWFXp|fX4+al<-eSj^)}#KK+5reI;=mXfU8VF`s8*-CpP} zFh}jN1(qj7MRnm!w1nwA>4^D#c=;uKNhOzJ8n)$&vep-Bu3=RwTE82O$Cu}m;d^C= zlD{qJ7-DT9Vx}mfiV-?xs9Lma6>?0Ma8gW6a^36*=V{6MNPPtaLwsP%l zZ4r~b4qs`TP?C9o%o!WdC%Psv0&iNE7Q|Ksua$vAEiXez&i(%|h~(^juHx-0w>*rZP3Wk- zb8(9xiDL>axyjd?rs%)qMZ`mg%vh)RY?5<-%X6WjGsQEFI47X2* zPbP~ST@e6vjid}o^y`vxJ?lDba!CQ9n05BGLvL#-iN|DEp^f~cx1?@P(@kA z5!H|?L2N)xA~G8+;V8!_GwhoyiwT91pN#=uqfit6tw>o|SNAoRLWksP zK@5T@3k7+{5{6ouGcE2V>)3YG9@5Nia93Kzv!tdqAfkjpTKY*7?$u>unRD6Gm}?oo zsu|bB)-o+z{Ryng`_NheME_I85Mg+wFp4mWR4VZbiDsdPLVAkJHoZgTzxffmd|jOx z&&4}uR^?27`bzBt1|=OUi||}Svji)i|0fmYAQu&7Uc#8F_&F8P zSiOX;B1xv9ifS*QxUQmjg)`M_Wl(h?wZcxzS2|Lerj^?kXj&@4Fjz(00;Y83Whz*G z;z4cQfrZ`ncJ*b;IsjML`cENfnb8^qrD0asnJ^^z=|w$p3;X9ru=wqZaf(wDA}FxX zDzY!F2a@iKP&h|`S`CY=vN*@Ol(fmKD$^gN>gVu@ z^t%o(N>EaJ8((W_F`{!vS7`%z7Z*CTP#}B`fL>u+<{I?yRMh z288F(5ZVT4_FX=kmbz0Kz!yQR73W`InP)7AoOn$pEtx>OAT7m;iMY%}V~z_^+4wM^ zRhe(_oy=Ur@(`w2s7!=xlA0Jl2;g>ir_Ti{R#uj$wBI{`SG3#@klHm(@{m{CwaysD zQDbM!!+Y^48;H(8f8el5uXW!y7^#h9xBBBYYhM?0YTKi@ zdjt1Ted=c%Z%gpGzr}SQ9fJ1nfoX1eds1xd3*6|Wuq)2Og+B9Hr44}w>{y$(G;H2sl7hg z;@;hNci;K$+yT!;206XGyZ(CrDPpPI?YL%J#>fEmT!7C+23({?odG@DaQ)g@UTx3z z^tuA*YASe?>+g_S;ER5$`3{jE2~oPLQ%x~qn@dOp{35}Tg@*2&5RcKhg#vz{z1LhK zp9%Rr@#QVJ(%!s{?-r8mL};Dx!kGC_V49l4CDKnNn9J@-cpy(s;BB4*856WEySa_o z^S7-^Ml@+}Ft_2rJ z0+i-r(<-$rC5A4Nr&f~}$wpmWT)Me`lswy?R+b})VP~616M}&|Aj@fZyz^uFOy0QI zRAc)yEu;d5^!uVQTdgN%uLCl-a8p5upD}fJ9j@y`J_@{vz?*QgUGsi^JGBP zPt3Y`tF^ZmW{FP5w0Tkr5C^y5qS(9W&EZCA=ov0|{(o&pjou~I1MAF;|MJNpWwSo4 ztko70U^NgFySembaq*R$MC7faP)jbIAXWXbmIlq6}~tfCSsoG zJR(XrF@vKeS3R{VSQwve6i?;(>ZoCjqBD9$9x4s%+x63R!s*b*MKHa0hhwJ$mH)Tg zraE7JudZsvJh(&SWdFGKNyJLK#zyv7!)J8%p__E7``Ric|jb z4&&KARB*A>SQC7cy@7PW<^_w?9=PQq&bHE~E6D{Za;iur zfYmRPxj{aTXCuQhwBQ*IXX8QN;8il;_kOz=K$?lA`Di0cB|GFqcNw$gpgbMj2mR2> zOKRbwy56s9=8y2fz3-CVA&ep>k1}#_Y*DvD3tx- zQZYf(0?~>^uWiRi?RaS%w*^SxsO*Um zNK>dAL8Qcc>J5uL>`|U_91gA*y9e8gMemw6^6?U)S_u+F+%BcYnp+HmDb9vZ z(7*UPFuaP7mX8)_9D~f(q#sUtrr9v7LFlJI+5XQ`3#H=13=lbxIEaV}-3ZB-#GW;8 zYI{4ZinSyjj;#}vOxINCQ>*y>KZ`E!A9?o_&%HW$oOP33PunmQhVT6=&Ke0pC7SUe zB(!N#2PuujN=3p3yE#e|haM@lBimgCzaE=3AuipW^_&l%_xN={r6_m_@$BmM;X1-x zu2xdu5|IU#li>S8EF2DDB2~`e;v5!aK$ayM(Dced3Ygy|@#6@FVb=sF@oj{6lSvY# z_%luuTgX^IB{T`eA^wSHXQxMSZ~$LAhF4EFmLnc@oo?c^Nre*@a8Xd{`iQ(*7aRu9 zWJ0r4JS&dZhAKT;4tmi%Kej6B%sA|BchX(M={Ui8I=zp^*DQcG|9joE8ZCdcS9vwR zBaCNh`ZSLcoc8NT81qtd?G?7cOlz*pd#GbvDItAS(Ta@rnKng5i%*Q?E>a|(9qYpv z9exbuVQn(A&F<8_ub6qFnp-|VL5k;Q2X06da-)4ZSm}TL)%PQI(v9~jTStHvwUuE? z!1lzL6W}IHlK5|gDQM?7G~a9)uQd1OT??|i*%>cWbr#z0TfKYz(-_@%jx&=_{_isT zm{RSqh2CU!qp#=V`8b{8ukjK#UfwPK{#lK(1tIWsvuRlgk@Yo zCgVqyuRs_zo5=)HqYL;|m9bgUkz{n(Mqvm*f4(tR>pvpOrE8n&>%34{%Y()&8 zmC!j_|5DaS7?=3?i-?Q9HuIZ40tR7N+1M(9w_3;&Gp(LlVNj_jIknKH?`{|fT~-$A zvQqOB6A)Q!pxx#OPMyj!iNbFu4ilJwbHCo*WzaUn#~qXc5?!b=m0EWe28jmb3{(m& z~B3(ic6e#{S_}kxyF>S(-0!4jIr;MJmp0I{w(z6F>>)M{G(k!m1zP<$XG|gps z3cW43hr8<#|4N}5f>oj%IG4`e?fUTI>ZuDxR`}iQg5x23vY-wO+Hjjm@gGVwwxm;b z2Chv(Vw4qIlNc{sq9i5iZmu5rI+}|VN^SW>*Li{gC(@+3Ui$jSLddEjMKc4>3QYs~ z@=aJ$90v}y&Mg6PUKlI1G4;YKUE-8LCFg03h(5UvLe@;n3;cYS@VTog>qc{hr7E!@2D)qz9n}>JjwkEL(A0}o5gx6;yl-)<@m63qbMTL zfByRE({Yx-`Ty-a{zaa5{|w)u9VOVi;UZ07+e>G}q`Zy#9tM62oLI)q*lF+%Wg&|F zAiHs+B*^MVhh7*H%LstDN}@S%}5T>$U49vqKczqUhQ! zWfn6oShsAP1zCIEf~F0~99?~4M+B2AD-FKxP&3ll6Vh>laeIe_iy#>n{w3Vh6Tdlj zOR)!Aozs2Iv?-V$r|k!vzv8W@&Abl6+~DiXZxk2N*>NYqJjN5$QQ!cPbU0E3-V=oAcGB)a2hZerA>e}lHDJU8gv{eu=0T2K zwzdE(2e~7?=P<}v2xhYfFX{ri`dMm#-i)`NJYXak!jOApGM9i!NL&J!DzXw5wDUH^ z1F{POIil;a>q)9rvhK2&80|2PX2wI1eTEa*7!F`^bbdD$oKGCHE~M!rTorRZA3E7E zSm;hnX`+l=r>3aaMF0CKvh++kGgY;vs8Qs1qSewTjw;Q8CBu&fJ}(@JbM)nS1vj^U z)b??;T5q>da)Ok#rj%^%Up-|%pnh7sjjuPGhYdJ8@h$1=5Mv%#-V#ip;x-NK}b&^p_!!Q(upO;^8Szojd8&2@0A{0BdFsck? z4lhC1g<6ON|q`T=Un-)x}#veiA~=Zo{pYH^8EYw8&;tsIjCqr+0ag(JXyV zp+fCMC;ap-bcj(*TS2?n0}6!KrrZnV|Qm1_7AWiMiXH}1G;@kkf*^vOcF4*shB);inlELy){ z+>w270O+1W2k;RC;HN#nr#lGSK|(U<2Sp;hr``zT`0&|6JSM-jd-ILEKzN*eQ%#TB zFc3W_zhVkfm9Xq?d!`&{VY^5ysRDawtCba;2~0QG)N%T;i2vTP11UmPFOlte^WMyx zNtcu?>l~pY^>(Y(&88D}+c�nB~{CrLy7(-1eZ*20l)gVmVtt?>1y`0XY_=FprM! zamYBP+fj+vmbS9ETy3TavJA>J`uUTUhV}?mTD#KQ!gOhK4UKbrJQ@HPUVTJB73UD)y5UcS-tw zIu;M3*(~|M94GneU-Er$?F5G~FlcL|0DW^^R5=x`(T#y{Y)aKzPVv5i+++rN9OpDQ zB5j1!IaXhvxN^qteNB^jvP`DqK6K{VLgp3%*rpB~`sa|lR} zDz|K4Hwcx~JN{y3`MEildEbcf zelq+H!(pS4EGB6hv#Ce7S^{sVbJG1#5&1<2f_E@V)6r+Kn0}c=XZFM#yt;BkXA0-` z(bJ8uCupTEqTcd$YMn>*tn|+#s^ez(2hm?qB(N8FoRyAE3xYrphR@BfSoD$}^au2D zDG5Ogtj-I$V-Cn{tgDykzqfus6kWQ_Jnz2GtWOmytVEjcvdcb^XpANpma07!K)Krg@g;$&%Ox z!s(xIB zI}zsCfh?m9+Ch*dDkdU{0!bzH+Wz<5QIcglN;_cv;zZ=#@!h+3M;;woa0uRtD~Nf* zfc{FxK#5pC1d*Mh=gZ% z#v>GIj;uu#p-#l)yrDBgbF^CW%wSgV!1W3QI!nlCTX-;>-oU$|>kg;h&0xbV zyJux6jtO#%jIxtKrq`Gcd0&m(vrBXtzI7&!cLPYq*zu;L`5eYG7lv>>bUo*6F&VmW zy>PE*^AU1CXRMYX1!=E>VKx=0@`&kxC#shC4T@1Ax+H>CfZ~)aWGK?ekd?2$-)Dx{ zM4&*7{){Rr`3*o-*bJ>_v+EmYdV!Fgn95_rgXE+}QMbuc{b<8)$G90}cUV!FYcxae zF^}=UaUz5?I)5vaCflna^j{qx_g@_U(m%FgF&|R0N0#+7&%&gL7#yGuQf%|p!PXjK zOhkD1cva+z7A>U_O^Cc?N<+8`BphBio-FMssj8%^iVYzn7v@RDME>>mtv z-4y?a`5N~9CZp+vcZq%{1H>7z7*z^y7tZ9|zaDy*KG}7B3TcC%2YS_m&+yUeq$~~d zb=NH64jH_7^XS7*Sayp(gMAlx-eP7yLRV&GqjRUzj=VScXnnOT>@=Kl+ON6vdB$~j zdj$^5B(_O3`B$r7h4%OXRl;kS&8+aI=J{*8z13#^Q>u{UHK9a6iR1`ZO*f@qDy6Q`rX z_GNT^)1VD;13Ni@63bD^Ap(qrUs`vYs8r4VK1(>uT(>C@o#&TQfHI6ZqKSfaJ~=tr zD_7(7$9GTQ%2?v0JB8yaQEzrWdu=W#hz-TPdiY07g_7qQr)YBs%@lKb$v8ZF20JM? zg{^W1EJ>#>8$N^z88R$GS*B$X$4q{B)&KQ(s!gYw6hyhdTx+HXWT$l6u!46|wj-&T z@1D=5lN-{I!B#m`gtRl#c~}vkZnrsXa{?_@LF@{n4Fs~+gEv*s($Y-x{Yo@GO>9%O z$|+3nDN@BJ%&7KV?cWO??TR1YPVMslQIc;2wGl~KI+6(8W{o!Xb%&RqWGTK`A~dI) zvCtx=@gF4k;xP{s%9!3$d$OXY+2Ld_v?*x0Pmjm!uDcDo)1vCWp|fp#(Dm0km&+-P z=1fW<2S1F>pZ3w=VE+#-TaQlUeeAry8ofs93$@y#?oY$rx2dx_CZmn2sYE9C?TND0 zuQl+}tAh3<`)xC&-wg4J%(hCDJ@fPhY1DsMw@@__s#~JIG5;sI)!H|ExLe}r)j&4) z)K}|Yy*h{>wjy|(eUCv)12GVV&&{tGx))uFe_&5VMGGn(DhMKBO(wg8X%dpGqT+uy z2`F1ly$sBI?@Qh^q>Mxbo14?CyR&nyNTasmnU9>aCOKrVZnB1q(33=1X5G4QGAcq#b(QI*V{{ey}p0!=8;VOw%OwQO~|8UvPvcb zg|edT*k{t>o5Ormt;>8#(M-=JPKM&q9?|Bx0%1*vP&&4`oUYg}ntu=1;v!W8WS(U0# zt!3fGs?e2)@1jx+*HLvB2qZ}J=vMpvzxq8|CE`R7HB->3_#!UDpJ(&4#an;U@0GIJ zlm(KWo`_@d6Mp@GibADBS(d8wfb6TQKQ3id?E$b-iQKFIGW>mUIlp*I5Y89Vvm5%l zS-hE_JFo(l^6$U_w!}jU^c~O#;-ktEF~T1dwnF>K^Wp$HQX* z$31Q6OQ0aRC~g@LKalsbRCuNMQ5-WltpQb`#L0=6&gM4@@#TwXcFta%&E`H*_P~2p zR%|4Ssm<)#)$4sVN)Ae+!N?NRtJ&4`+q?i&i~&2Ymtw?UU#(wX&2GZ$H|OWm>+6me zAIhwf|AiY_@c+h-^3P0HdaG8*ZH76DW2v>NkYB>fUpb>ynufI$^q(6HV%JrGOCEp%p{5`~XqgWsHLkgqwipvVa9! z!YX>3LT9&yObkCrg^cO8(u$w4WLXeAv< zdpP?0O03Amn@Ko&UJakHB9Ei2j+l_|^Koj`il{YkPyNH&#q`j=TZQp}i8fqgNA(@J)67%?!Iv&|YORxmi$Mv#-0K3hib=(2qpmx+7TF!MUEW|YF zf}-3uJ7glPG2*lN#cV$HFxb9{PLw2JW&GiFeY0zps55mXSMmCj=NK>&we8f{xUab$ z8JYgls+Tn1=sVV#Yyq$XYAN+5ufRv0ibTiM^4Tkv(w&b?i~`ZX4J=xoY}#RS9LNH9 zja~atJ8s+d+xER`J2CW1RSIu1G1C|`>U9*$FqbJB)lH|dwE~T(Yf*q(vTC4(#%#ih zveil^ zSyajVQ)4BHKkdfLZx68B`RTg+pNy?^w?A4vt*+}1AzMy+Y$~JvW>D65y3>!GEx&zH zw&#x)_9TOwxAN*|2@Q$%UcgnTKL=d?-Y_kEkE^O41$;Q;9f$=F+RXZpggn~8HI$p_ z6A`|gEyNI%PV7j|2w>9=eg}pbW=w+sykho7;>AAqn1>Xyyff5e@%%kbii4v8a`EnX z49Xp<(TK*iqd|Myo#6nZd7HzRwS}<4#v@m~Mdc;ZJd05RGWp`b9bt{%5={7lnxXBu z6O;K-{t$hFesZ6!#o%xtq9TER_^|n&NSNtDoTT0zv*CvW=auLj8^3^kJ6?vnX+aUZ zGMxPvkI0~EWn-EoXn5^Ic1M5>7moQ1opQH!Tel6?(>H4bMR+07lW1f_2BM?a-cD)Z zLD~kQ4k&jkK5gFDd)3#`XhMvH&34 zWm$BA4?^;@Z^$U~sx3IY%2iz}IorJ&+|{fZUlc-*E`Ba^X{*`p*TIz)HK!W_MVLM; zKW3kntDk<1=(JqjELV#dtx2E~av$gD1q=C(X_ykh{pxNhwpKp#M<70>toO$9x`{mz9V=$}8N$*WWKIS_ zS>SVY0U=Kas1HiEy3PJrVp_ak-YjnaTq6yHgb9F}WQ4Ct1|%JlqsO}M5s@=Itw(Nc zQmBVi9xLJ;LdQ=e;j$2Abm9I1Tu+ZFMY-=14ZibYiugABeYtvb_c`ekzq^6gK}OU+ zp`iEpeE%MUzx)VaSNAtJDZIw$*h9m~Q=KoVYUcedR%M&Jhf-xZ%dr#(=XrEW_|?HC z8C3q8wk)yG3H;%MyW;IxgC=?1@9*` zGKJs~>^$cXJ!)b3|KlAas|@G+xJ+gGh^;AnfJ_0~N6@0mGVAn^q@kMRocGBNM-cZx zf~nek8F#jEKpa|6UTV&X=Y;#5*|mD$UXzzuYE`E}zE!UHN7fpPacj~|0^tOkgMzv#`8)^9LG2sfmIbK-4A3I3S3$RHLsOE%!udHj!S5iF=B(SmL`4K z%ACeOn4M~?0!sFPau_@aZCf1io|~ABJs=Y*YlPea##n<rPqjQT{SX_QX;~64pZP(RMQlpxdCK9T(PGWC>kObVVKC=OPS=aWGKrqoSWeV8i4$p4@9E%RG`(S4+?Oh`l^%V^j}rl8TW=6L+Uh&6 z7vZV=^rqvLn>*|Kw{I8gHBj_g=iT}7adEp|+}+U|lUNU?;khUUFK7$YoP1IMZX!z0 z+}ifMidmCs6-N_lERe9xr^5k3Ro*9R#hD47bJ>KMVN@<01Q!2`qL|!~_5AqU=iQ(FN0-$D3=(#6Rw>7vzb(v3j7T}GF zKpqid0t)${_I#kzDVhQPR^TDsnZ}BupAeIYH>SZdblz~V-OmS(p(z4ouQdn>+MIxz z9cW;S^5FOaB{qB%=^EY!GpK23e?qV0P7M}=JjCx6Q~6`2(SJ0^ccUZR7t)^GFD<71 zaUPQLKDUD}@q&2bX(^M~5A|-uC26-x`D{22g`r!LaZfz+bB}!g461X*{1YFUpKNX6cH2DB%dl=v@cAI?7cxudZ2h2Yh)|!O z2UH(pefR$p-{)nYt{29=tV-HAfn{Ejt+jgJK||wwE}6RpQ1z)rMfpX=K=t-SL$`1{NJ8m zD&Vvexqb0~l>OX_JJYq-blj+cD$h?z0xI73oJr``i}o!N@;<6r3|*|8m8uyhbe?_h zTPn_bR7AQ7rZ_VNsMzM*!|yduw%pFkJ1(Yb@&448%FlOi2CQAarh#i;-L%BZP{l>5 zW#x%E*+31(UCVX~)k^eUg~hV-xjqb{G!WC zd!bb#6Q2ePmp8nt_^5LX08rJ=p1i~Xc$}S9!EW0|5Isjnrv1yx3S=pinO(9~L9 zKqgg^vg4CLkt=H(iYstQyF!qE@0%qhQ%+JKHSC1k-I;ms&2VNfh65UsR}@s~$4zai zQdU(@Dj#E=w<48mTUUD3)Y_DkmN_+6kuJ%arplCCS?MyZ_Ov$D){f{|*BdewTl1r7 zYTBAyuXUEPj}fJnqMfR?x~^4DyUIN291ry-t?`e7pQ13&x_o38nJIJ4cGlT#RsErZ z_RA}9mdyHqDl<9GHns+#It5zxo36|gZ|(MuEc+lTO|3IE!U1imfIIfm4_fA@pa?Ou zBGp?}jem#)5qqK>kbr950NoKx3*m_9=fSiNUJy}7H8)waRb`zXvUXuAGT5nTo7Sq* zXYh@e+-xs`3X@H)BoB0+ebN8z2EhzVUiU{jDE&L1KxM!OkqUwc0QBvhX9cmBvQm9HkW}vTTEmy z9T9v`5GFK}w=%)WBpkWW-&(R^cult=@^7%>UCEhD9$eIGnFJj18X-NJdr>0&#mtLn zzKG^wEZnCKiW3?8Gf&=%$ruOz%(CVf)ttAy57y z61R*UlEjOvIFZRB5i||MiBmon(Vg@~e988+kkfHZi&%^hC-Gc(c!6;7B|l#+V(BE5 zK_a4PF;8R|oFnb`P^i_wgZ0G89R`jz^a`T~_RD&>Y>epsMqoW+d7Ww=}igu~*R}mtB(A&U|tw z8Gm;kRT0asf}Dc>O_u=vI4%Z*w|ZUXYTcEpSU&1{nc)k^f1BlU@D_WzR6p8=d6^Xr zTJhOo2cO;M?A5x_`N`rRHCowt^XFi2F?3(($F(jLy*M9l-0G^*fW{4|U8Y@HSv19w zYr1J&bGNS05CG9S3&4HE!mj7*r|hxd%wgl+zc`hqGFe`UsSK7A;m;gun!^>E6!&~g z)I%di|4R?S%<6BI)nj&0?{|t-M&Ct?>w#OIzFcxX_#j7I&Ler}C1UVBt1p8$ow9h* z`Q_jZYq~rzUGf_io6_pXl83N^`{CEo;0+yq)7-@4gvR*@<7C-P5Jgwr;iv(m>jqQt@v7^3aqZu z>@&N2jR2R4rYd{OmlQ0}GxZ6M++frp0I7d?gtsHP2f#6ZXI;ijzFO8Jo_41`G>>Oj zIfOZRN&v_V#%94)+73-d-WHr~vP@aKZi-?*K31prgmxCZ@0ZB%yk9ZS+U+B6JJiXL zF^+gr+qSgYQX1;~{PI`@Q`KJBkdj_y_mkDJNtw)(HjORz2c+N8^^mPYde`j@qIdL! z&MR=IjC6iNmxk@rchIN1UD4f5DNpN^(maRs_W$$f930BC7XVpzAy&x(QhL{Y{o6hJ9lqmgGgZzPHAAVZ1zKxWka<`GpXbvy2=4~oYhv}Z`v>rejb0tsXVM81TWKGx`%2l zLr4fsQ!7oHrpUw>;x)06?X*Kx|M%V50TTLSbmL(|h=jB6yYIWZoYPgAmYBhGelfeg z94AZVlhl+YUGgO9bZJd#d~UhZRXQyyiEzSJqlfuP!)BCh8@xqiOJ~&Ycc2gFnJN$n zbQD2{d9W_5B1#kGA(~+&tW$b9fXvuZcu)6WO+{C9!GmZn$*_VQ!B_c{A-I!I_6L`mI>8doPxs=fyTMrNJ z)ZqNuMxCG!jA@}UeVc`3R^tt~No)LMF!Y-x?x zC#X9*L_C}tI?oF_`Fc=N?gWkHqX^nXcmnomIpM@{LK12eynhCxMnIn_HR`NGhpO^uO;L z%66RAL3$`si!+ZiZ{E!C;;chwl&zGfN@+>_*GWm zfrKe9tfRFpRkdLdd}~Z89fg&oAl=%Nt>TZ{bWXR@NGCMiHw&!_x>JQTUiRrxI zW1M8^Xf~tqWJ&|NA561kIKLZA>3%-FpUg(!ekSEkh75AN3X$2hh004AgwlQ|@dt>} zBRXBuNdQprLE6xlI0&q zw@I4cjD~jvePK))IvJkOkC#@X^k!>A^s{p+HB(3zXJ^PuxB$~a3%Bh`WIJT#OOF55 z%P!7Hu4~8$MlIBcTjI}v4&yllI+X?u*Xc0aO@zW2Ye#57Rbyf|BhT78ZW7iPxAm?= z(HQ3uW=9$nG-Q%r-2F8hP1A1J)UpQ?5w<;-=iTn3@@k>93Y+c;TtuV8Nw3!|LmT zAw2O-a$jMTRpi44?Ihf?SxXcA+tFfrd>&-^{WM9laaZ&gzp;(-tufiU?G2cz7-_xZ z2^;}?B^7SU53%*pN*8S_ov-58g;R+37L&C7Otlt)gJ^GxE7wO${9ZcS)b!krf8>Xi z72RMPfB$G_05d$n&TUo7TUJZfuWyP%dXHhQH!YzDDbMD^Ay47UeOk{DmEbkqZ>L{l zc#~mI0ntg}+owdkS{{XNP&Mr>#-e*fIq@W6%`F7xvvdv}RG>qzVWZp4$iB}9aDXg) zvj|QUvFCUrg9^mHYBv*mMu*4&oBvCf{kXw4HChwHdooMDVio|Seb}_K@i5!bbc${B z?y4m#F*R1#6Jq6!DtNXdcdYMLG8_k&!!G{A3MWF)jLElt!&}t zckJEW!u17jTrY(y@Mb%TJD$wbUy$GTcv71}HyCy&t?*2xmglRJPUq$1Y(p5JQao(< z0pq(HNyXH!j@jTg8_J)t(8r0 z+ei$C&(W_S>_ctCP1^3>(nGtl5(r47!g3Zl6c9$zD4OkfMwkyLM$!Miq$D?X;-p<* z4H&RB7oRlJ5c39oJzQGO>}Uh4H)tGvncV2o!%@t2N+u~4P-6^D^)3}@9_ z?}W6c&4`X_0_SAhv?}t`VvKVXtegtDK zEe`-whm=0vDzN;V#ddu4qaYL_KgL{zHtDPKy1GYtr5!A2-r$IH+O!` zm9xKY*hRX${=CY+EaPN#F=6v!`m{kf2W#eF(npvBn?r#OI#$aO*b5gdfEj$M1?GzD z=&WByr%m^?Faoo^6b|~w&`Rbgi9V9(u6JjN|L=_UEj+HY-|`cxcSGCm|M!5h>l98~ z-Y*b>w35?Bu)Zw0wY8UW+Y7o^a&{AjQI^5GpJhEFYK8??bGR3-0k3S!OHm6X;+nNs zFIle|VPV6h$F51M!E&>~cH#`WhC{(D2W|{r#S&N9Ioe3jcw)%+@cLnRro>uF`k`lRY-PpYGEu&3in55Y~0+ zqAs??NT?MvWy6niFVdUj3Hif7P6(&8ziYs@tVHEE*eO;>evEV-T_0lp7%(Bu6K<<6 zp)?!1Ayi*H$@dJFX2>{%{fV%{w_6YYj6*`J5yuGovEjyIhgz*=N2Sd`ciKARQCgaR zG^gYJ-{(E*(+_glfAj5b;=i2TmWaKM0eGCPm2GdEND#+ghfguGUz}~ZNuS^JUbMv| zqDmkFT=k@r&;m=?yY(*G2Pan5@7`I!iJdrZPdZDMYF^So@i)$Z$!VZdF4 zS^hb=2%~%v_?H0m&QK*_>3{pdsLDP~GMGTWd0~6rG zN@6;*v*&}I&48|2vvEc}DiGE0f_C%S1&yhwSnYWZx9Ct52(-4~tc2Q%(t)wgRw_d) zsHFnZws_b@1gq(3huMmD5iNbE|6c5GS&&2%vuWvcE7{-P$;kwmvD}QN)9KdQ5e6-P8DOwIQeAeLg5InO$^V!7a^xMX(S80~o$lknF2kKi z$IE{je~UOG#eIi~2EuR2#?25%aJ4Oa2vkk-tJKfG2FY|kcoHb#&TvPYcB`+Y4r(e+(@r#wF25V%_!b zEb;%1lD371mG)bHO!RJO+x`FUx$HWHItx^!*@B z;pKf<4~Uvzfz=#tnQ6cZ-O`fP42igAHP-8_vxaF{6K=6%cX^du0ZM_nH%P+%InU0a)4-Yk2`}evP2!m0 z9p`Wzr{OnTn#ia+wNAaq)dootC-CA`FIFg8Yv2}h71Fq6q9oSNH_(ra%fq!p7XQ%F z0IQye7esLuhYOhOu;JBomtINQ3Fq2vbDVq}p*2++hpLs5cS5-A-5SzHSSP)taN&E)~AyO&(O2DjCZL4VB%zo8O zqXn-XdV{iaNU%tf01{Z%CD=R^w16zPA*T_#& zbe>~ji(VYdzd!7`2sXQdJ!P9+&eCkX_j93W{79!wYVNv1tYPq1MUGMIkFlp_uSIsq zBP0{U2*Bu^)T4DRVbg8H_P&QnD?>=qi{MgBEaTovcbE4+y@GYaCFA&tu75D+H#|9qj zO9r`#xw&1lrzS=>lch&ey|0&#D`YTa<`z(RoNH!%$}%B%V(vQ5_z<69jm*3f&CME& z(To6bR|qh%kO6p{#Z^sD8!-^Q=U0r#0f^Gjo}*T@5D-$DLj`JYkz>zhU9$Gd_7bA1 z|GhKb&8`U$ii*_BCOh`LdGqFD`#LiUGq{?aO>fR8^Q8`RO_uw4KA-pcbfgVFbK2`` zBUhC|IFPm|tQqA8iOp)ohTh3w(1QV-W_pD{2qzI?lt<&jX^MWS14Jv7!g+0$AdG@S z7+qE?5wtbnY!!%#k6uJ;NrnemHe&a%DUsFm!BsLO?Am|hmoOt3kcp19fskVzWH0`_zQ6NM zv9{u$ITQg2-QYTr$}WB);RsJB#Z#2nmsl~2&MPt`ZijWOQiS|)L^q?3q`oMiJBhya zAKPWqVkqrzqo2c2xg_6)+Zbjy(<$gIIgz$nDKIv`0zt;iR9n5tkL$^|*-N^KgAS<4vIuaUYY&nE{G)6* z<67r2hc`>~P*gr9Laka+j16O~oemV1C1Zggvyn{^H59i*BFmb1yP`8Eyw^VP2&A!h z6}qGOOr?pGQ{CcEBFcqBd=~vpsbmysACsF>aW_AxPhE{C!*!~&^MZR^D87_ATSOG< z1QnHjZ5nOgz6Y9LUrCAH55W?sTWeqIeUyvadDAUfjON%SL;W^Z_sbHOJnL}v_n=@YO zJB({9?wn?Ww!7=~>DCt`*mjF~8WfqQVzhhU(?=49mQ`jeqlWPAL#NCOTF`g)aq)+c zuBx3S^;xNAp<_{oP4mr2x9mS<%PnF=fwi=#7@1~gy8<`KeILXUn`g7Ck~?qMFhc!} zMnm9Uh;$mc;PiJ3JUg$y?R_*#XT3kooB%?+)dF~&?O083+c*$C*S~^j4s`;@*>=AU zZi_mx8+hT`fa75ICQuR;F_lGwq~f|o|NG96l1RyNnl2VSHHRjZXNEKH&Ag#}!jn8^ z37IXf=C_k+aL08Z;xI^qpmzcv@SJsi);r;Oloc@}&m*zfh!YY957>LoU}`6A|9CNRyaq8dAlG6orOdlre+6?%=_e zlo@^7gXh)(49)+)z`qy0>)ATEoLTScTxk-eRFX5V-c!fc zRVHj|UG)2KLC`i02y}%0LqcYW#XJ|ltYMHVqUlGLA7uRiW8%^_0bJg3SSCjmxqAV{qhbTLHjgW0|WuU`h9&x$D~A6RUfIVqqC7%3EMdR{F*e3-4lwLH&wjtL4zGu_%_ zy_!zJ{#7HtG0~Di?RD#sj4PP!yVK4Xm-FQ%#Q3!p!^n+f4_qN9orjOF!SA=quXMx_ zhTfwZiq-V4(-R?j1-`$3H$=<#Hy}Rq^%%VW7}UweEYoyAOpgICcl-f*GTfW?OcKRf z=dY&k>nMMIJ4)HyCDC7P2V%>NoCaDGlqr%(v1yESmkL6YVLLwiLxbvjAj|Nz{FvRcoNAjo)$6#?bwe6Jj;nlfp{C%_HnG5YDGF2V;jTMdaDu=%&#E z^^;HM^Z)Z{2o3C(`VqXAi?Ou)$?uQh*P#Ai>HXVYe{-+MF1`IGICzcLEPn+2UCIG_ z&qbx8$YK(*E@v#|kn@w^e)UIvIci61WIDfM$#NY%%q((c!&+jjnL$!Q})!`*lJ9%`=zX z8y%ZnVcGsW0q>W4g)7_=d%gvtCYTkaaQSRCC?r@;k`c{Jm1>2N;ZWuoqn_!9E^G^pno+@#F@Hu2*eOYNfbayc~|K8 zn&kKvHhThZLFGGf`-I^kId0jy`_m!FI3|ORU29UcCT1Q6ZXh0Avg{LATJ@iFksuC29bQ1qpd2Xvi$)_l~6(4aF22 zf_R*jRnL#xL=@Jt+og>Fi38#{Jf%YF2D8hhmD)w9jx$LHC3fl`yUnSZ*t46dY)@oQ zvRXkE4&1naeB;2CKVT2sxu8mwIC6l00P#=oW}I}>Ry`2O(Rk*)?|t7lGtYmw{@hz0 zv>MO?J58Ywr&Coz!Ao8&c(RZ4ddcUBC{-aQb0uUBEKguwau7L`a$dyT%uGbiigP%T zMOIpHCe##Up|kZ+&J|=b5ho&M8p8rsaG3ET6Kbh=0<%IcM1lh~WeWc|0;Q=u6Zxse zh-ID#omiU0jH^29#xnawi3TjQ}NN>evx!^h*E;;>wHZ{N{C0L0~ zWIWG!uGo6x4rBomR|?3O;)P&oxqNDVjbgUWByVWB)aY_y@^wVcGOnrVaZf1d@C8rh zOjiU)X4yO!>KxUW=o($8m^~7B&`^>pmb!#2N@R2n6RwXIs*}L;1ZNSy&;&E7RtU9y zn4KVhJf(1gtF=|7JW*%*fUM74IpeWDbeJUS(}?;Cp%l;S(^r;ad8sb!(*Odm8y?#} z0UVEf?}&Ct2ijv?B;a_Xu}^#b5c=MrL;L`2x1%#1&kcRrjzSOTns$K6O}&QC7|8vR zPl5nEALwv2pooVBeA^8v39O~gr>--II@Il1fFR&{Aq?n{h8P-pmZ|+>s!sH}FeJXy z#~Hg#2Q(a;vRxXwx?~q?+Ay;HkUG)8_F)wHBQGH4#-qj#4VKQprbE)%M-o^V$PsZv z2>SM5@SJAv*d;!yctLQRAX~dVAay;I+@U^kLJJ`;M-DoPEC-g(4@ShHI0mx3Pf(fd zk1cHw;s)eign_sU9eZf^NB}pU^+y9dZxL>l6ZvGQ$)hPj)DA)#Mj?To=XH$v0r8Kh zLxMw{Kk)R9bRk*>#KJ&{>9?p;#6z4L1~nOL_y^Bd$aAs;7~T zX+ZYsJ*0t-p>_3R8%syV0KIict{!e2Ys+jf(5^}E98pUvSS8@m2 z?)T-_jcYg$Bc^+fG>xPwCl5K^?Nu79o2r{)HcL5v6svUG+D2m4Pus)l-|f$q zH-4=a+i$+3i9Im7>oWKXE&QwQyw&^ncz|3{t6>FxZ-$>nr5znF}#d^U8W{*lyEnu3*+MW0Mef~;5`1xgFMA`XPDb@>c& zJ-wK}{o&V}-{{rxCqNSUfnsAb;hc<~!ufgf4miCw?0{bNOW-@L{$5CwC$&><<$?98 zuDZu;D>o!(r5sX_ngHL$eSgHE+$xu>Cg@*a@yE^!Mnq{;m9|N)%Fqd-z_upT2MoX0Diu!s{gK=qG@{Zxt5CjIDSc6|$?$!Lm&N`0=sg@^%5D_YcCRZ}r)Ht18O=pwd10pqx z#OA$4wv9T#vVI5t&SVzms~#2}o~vlcv4>RPY?`tG&McT&-vqa zZDv-koabt~LL7}oqwbKFiA3J`z02cVd8{l8wKNRCqfG80NO z`nTU#3UD4@oxM)}7xrQ|e5S>srp2^ef&-*#Lc#A|c({9Q@bcOgdopc45WeukTKU=C z)fE$fYt7)f1_|;*B0w8hAR3nhF^vuOD3WzHl}o&%mkREW(IxcyJIs_EY`F3JJvpCq z=z>KYBP~(1dV)4F)!Cbt$EDhV@`|ji$t6O!JEU(;hP+lc9v^@)2#2o0QD&O5r@*o< z1wl^w@Wj6pB82;jQ56;vz@d!54ORIg80>-*RQ=2L(=^9c<4h`gZ&{R z_{>CkLOFfIr$=Tv8n(@iQc5iGEER?;bX6@p${^?l7HoTdrk7$>_%m-AG1|H)IH@La zO#CuYVbZi&6}7xjnszKX2vJQZ658nkSeFSJkdi*&L!+@&|<3^?>N z-4S;>`+B4G7|{22MHsKXe4;ZNn=I!W9IsqE#iCh&sNTXSyT<@;5z>nGt*E?nh7*OK z^JBj11f3E7h7o+e{O36ZJ3O>H;V{d$FDkJ^Mc|330x}=iBuWy378jz;1ig7&du?`6 z{?&LOb)@3Xzvj*8)v?I}c%02xK~v+n5jTC_sHh~fh4 z^eGmFY>k##XQZkbuM5_-g2|e-s?)i!E19gheq*K5n|8`xrCBqjNtzy2XV^v+vXnU| z9aF}&V2#ilX^bdXqt%Nn@L<;5;6DL9Ri$2K{X{BqRTq-vS}V5^=I0*T`2o0=sd7M- zs{(tw*1#ddftK|0Ouf*j=FK`wIvA^!k-3;+gKSv^b);o%v@Z5RG1$y2E;mA7e24@V zN2Cl$;A+tU-4=|4utoIu!8ipwM67qUP%5LCENNAq|_07g4E(46>QpY`R*SH#lQ=_cTMq21p{w;E}VSbPGIh zEEAMf@J%sM7g&XQP53s-^a>nz5H5fo3Cc=*bwstQG_RB#L%Ow%$SL0-BwZrHJx%FW zyTohTk#Ffukgz1WPVc?gXL!Dgqi@07pR=n6eDv8Yx_gL&#ZAg?qUGF=6Xu0;lAJ|h z8V6UaG{V{^FM;qU`i6fG%>VT+_LGD~F$-?*mI3s^K zixS@+b+|YWlG)M=ZvFWMFu*SJzxiRxk{fTiJn%TW5B(TE9Jzbt1FUzo^qo04JP%@j zmQJB^_cQ~K0J*gOCU^cUz%!`v;g=UbOo<(+P5fV0*oTj7?%jF|KVhf)?2!B+L5S0A z75le@9h4-it0WE5RqC@v6wNL3i64IpW`1%>^2>mf zOJNYEejKmv(jW@Y5cYd8-R4MezgaB|dC4rtJR4$9hckTGl+!VJQHC zvvj-@R>5aF@|T7FVi_#_aOTt3h!ouiiGSwe7bLVNaK`UFSYBE8DQ>{#9!D8Hwb5n4 zwH2R#3kZL|A6bzEeFj+uXE%KS=x}^FIr%Khx)5cbs{Z4XG>=-myz=V#asBvs@);jx zEk67X1$AC^D8`@YQ;y<*gSY;4u&#>ic#$?sL+dABCibL$EoCLx$i~ImE@xT-BUK`- zOFG-kX#OH}%hA|S5dg8ZI|26z3(Z)`4+)~yS~={s?|)i;7D4)Wdxl2uAw@kop+U?uC=#?p=zS?*XTBI6jit3D2dn=u9i!Z#nKJ~**rZP)P6-r?KGMS ztHtYq+6+6NFI>TOKctXJ+bU3?$!y(rC2F&zX0Z_)rQa^LT>8J_*oCJD?oZAR2yuvB zlq}A6)Fgn_xYpVr+;GMng(IQ@#6kXH(bcLx|3heH^=R?mPP8eHl3*(Q=&w#&K@Pgs#rF;jUlQGk|Q{{GhY89vtxIsA`m~F)ZwG z?rSA*s_823dh{{%R!Q6Ne&i{o#zbS?8vy{ehNI(K7_jHKcPE7Nk(6W;iSQDSdBKR8z4gcrYIhP)UFSUiV`NhvG!F5kxZR6RPF zg6C_>#$B39n|}Eo$2JNho0b&SkUG>2)Q&3S`SV^z?6}_zfA;5nst_NLz0KIsrje*i zp;w7(3MNG&-v*Y>ZASv4_^vQbnKX9NT|gt8m>r+E&iIo!sy?=^99EpBAfE<^V@>N&XS$lZY$Rbs|wYhFLOX4{v5eQ92z z5{*QLL(I!k6dCf~HnF2|<}j0DD#I4v z4%-F=X?tS^SDmYn15fry9C|`**pmLeB)6MJuCNK|8zH*o`k7`b7cbI_VyMl?;$h$% zprKx8f)d(x`XPK<(XmwD^G5A&{5V)0Z2gr>P1mmTBbTQ8qsPQO9XUE!Jf+4)H*zZc zEnUaY7%uPB^zlkA4c=fDZaVXCB4CYi>mLxX=rgYtznj5s|EC1;PEGsRV>kVb;qOwU zKY=3~m&cQEtr(8qnA)R*H~29=dZhH&@8c#i+-@3jN_8zN-F9aEp_7$YsvY-dRNFNL zS><`B+wX;EzoqP>WMBWc6%Oa_?(|vIg)C404`^MzmbGwroV8TRZreZ%z56SO`jQxh z@&UP|OqC$Ly$O_tvZj${gjtdpMgP5|7F(|3v_149TNKIn__)k?$*ZUcKIFEptx3ucBb!y(sX?4{5Zml(v6#UE zZVFuyaNesvZ&J4A%xUJe(gE16y|xB|!)J0HD{wXjrsZ2trnqB610!;O6{t-Y$G+|R z4}MRtrB(>?}w5gx2Dj$=rD+%_H1Z0 zDNxZdGGLdGza;>-C7NAFD_97VXep$&S^fp0+z!jOm^>ZYPVekk{*L5DS{to2hEFhfsZv+vB# z13F?_s2I%FNgL3yY~4l9qlzqqs^}WFkDCqX0&1$Q+lzekT4MBpRC4Ik^4r7metXe3 zUKD`ErObhA(pIeY6Hg&5RCalNXy!e6>Qp-d*O-^uAY&EQG2Q4X8P(P%|DC2Z%So;Y zrDvVcU;MnH1BCqYDNF7#i}1UL$6_ABdWK?={-4LJol`z&A6z^UX3u0tHc4k zh`dS00x#8A<;gk?RSXqN!gojbi`)@};r=#Kkd2-%OnBi#Hvgl_M;+de0wbTRt{qbXf`^a1P`X0wncHg0LFjuw0sF)Szb z?WDl3-;-yoJ$ChL_~&?>YvpU;+rY#!`8)I9$v>ElH=DDbV*~(F4F}=BxdC{b%~nlQ z>oyeK^DFK=HjqgJyiQka2qDSKObARq=9N`OvE^9Bkvx)2$aMPOd#-FJhCpd|T?M53 zaqhYI9{HkmLM@u7%2A>+N&IW2Bxe%86;@u;&J+|0O;*Ord8<~1hnXj#;|pVHV`7!; zI0()P9ZO3-mE@(}I5J82XE<5VP-44eMR{4|+oGs`tfM$^7Yh&#iosWhjLL6(VEotk8akdf5BEKkfa1OZRp(9?hQ!WDG|0Nq;t@!NZig z^w^!wN4>?kJEh0P^zmWV2lq26>oMdYA9o=zyD^yZSbCu{SC9A;hS33C7E>xPoK{8> zLmCIN^4-^a7KqIZ1|-a1n2KuruE|x{0lbd+WuX7C=U1PKS3F*eNkt#O`h@4IyQ{p#xSm#beduiCVjb-CD!lao`GKt&Q7 zO?u5qFn<$B;kznFCk@9dtAKHcA;Y;Ug~1Be0B~0jlXdo6#KNKzwJvPAtC$B&5|4Xa zSQZjd24tNj>ZL-jOIVe{zV#Lf^uFQ3^1-Vuk_3`bN;1-yD&q^QYjx*kE_76c%1jK`!B+DPo{j_H%HsVE$zsI%`=|Mz)+IytKvpSRBI z8OWD`t8jxsq*lB-zuxz9DxEAzJLKJnD8(~?RICwJLee^o(wN;Nl-w)Jv5pYE7!^0b z1fxAnYH_p%o_k@Rq2Co>9MySYeIwt2xF(#c>rh}GsDgXP;NKM1^eVTnepuiCS!bcWF1sMg+`3o?a+x>Sl)?(CPl6lM4zD<8&y8w!_lb4?T#)_v6$RCc z*U4R}>!(uVOX}or6G`a$@&e)q-h~W-D%uYLmJ~Q5=Jo>mwj+UlEdS*${!Do09DF4*zrP;5nswOsm+DN$-u2lBjM6_E-sOw1=FlNlDBV(UyG7> zoOP4Wi_<_9$0;h-c-M=<0}pn?{;EfJ5p)SlVQrVTNN;75Op}phrp!#X^pt-=40!Y( z*kdn(2X7v{`JebF_};|EmTgNYW%Azpe!ky%{q*$9lhx<@eybcQZNa7-G{2cEl|iJW z<6{*T-ihy%Ms2*@S>&j!V+=D$HTo0}Wm%WR(SBTw( z^K-bvz6(8El3XsV)46+7gtp05HejxF!*zqWkFfWCBUne+{ZH7lTr*L1`}sW~ zZS|x5`!%lQLSz}~ibUdV#}F5^{Z7tmM%XNKilh`w#=)@Pq4w{O{eib& zwhS#&EWNKAWNT})Uz#Sb>P`FI5zU#_skk`Ye~ePtusfMdV3x7OROgSMb^j@M z5@Dz7EAZ+25DIC~99lzcXeL*`yq|vo5JX@#zfO3Zg;ZUSn=lZ3=U1#0>3U6dL2cji z#t{^vawH0gs!AtW94uhPv61aGSLuFyZJ_xmxoSsggmT2rw zRHJL=l{n$3ZP_}RRC>=0&2>&&%@-RIdI_$Z-r(737dV5-HeRil#Qy-kg}<`wrt~ZG zTYndO+RaIKqJ5`}coRg#Up}oCQLwhuOZev^{{F3*bzLHUU|aiRa?F@A=Xl@FYnskk zT|{mGWC{mGI&*O3(dGYL4Mg!)Dy<10(_iNZ*g^%l_T(Knw)IfC^ zK>Kf4^HOnq?okB`?1!3vlNldgrj>K5D@JMIu|bcnMqnB{o-DUQa$;j$YdPj}jJ6@mc%0o-O>fgc5Ix7gVt`8<+>d}bg(8_K z36@G4C620`sWw7=m*e;q>vVJSqh+E zBLrBTyDc+f2s_9fq9Lz#Z4Ym**(w#?7NYAp<0~3vxFo%$H1P~@x zz&Mw51WtQMjkilnycVQ-Ndu8k3u|1VjfIW87k=zUm9ml!r5p(9ic+d?9+By)M%Oqo z><95PKia9V9lKJgyk-kq=?c&YHc%VAF|4xf;ia)`+A@6s%59-XQKzQtv zYJ4;i{)Bm&JH2RwTthps!QA-)^>O~ zPEQ;@4Knj`_uHr2LqFf+a8%tELV?oGyNMQ)Ro;khWIPhzMbk;J3bb+mx_YB9fAj?w$25c?Ps z$@5$A&Q=;z&V^&LwEKv!F^m?~l^hC&;WQ!>7*g)ds&_AcXWrOSV?ccVd@8#54Z(KW zyse{~`8u9WQF5HqdP3M5Nomyk&*X34V+bDxSY+xOZWNXd+YmjGIbJv^wKhKIpS5+= z`!#~gcZ0#@+2H-C|Lg)vH>7oQGCuQ$?NU_2`P`is{=fSJLs z)!pT|b#>yOXof!SF+^vSb&wUzK)+_L2q|KamuzECgP%c<-V9uU$F>b^afr1XP7Hj6 z%hRCOGr~1S!Px){M2#4OkKOS!PVSbg(Fg-D3?7a&8Nv8LQ_k_fPD>8`w8=xT@`t!X zb;@}yt;!Ucv5MT=f-omk1}yh%*H3yqFVUr;$7B1EUf=HDy?t<;@Ea2BKIGjY& zD4x-5y&l@+q-q4wJQ=n3&=J2f9czb&@jRZ7pYKOOaMt?MOW|$%^zgD-K4kyGt(N%z zuQnyhi;d3O}t#>z8LvSs(-MC3OW>GPUE981Y)7I>VEQo(B5KoGt3 z(!Jyh3PXI6+#=fzq=yERI#!K9RiM~C^s-3S$Xbwgg?2>~CqX~azbJ)%VrN%&nuZ<< zVkNzqH}l@?{5<(_^6UGHzK}T<5G7afW*PFGFnnK$jF+6V5k-W=e+St}$Zgf-2&aTk zwyLg`49e3#_=U|4$~j|`@tDCFE(=j1*z6%tiRh=OL z+L1}jj(`S^GX8@jJ7F7ZvD_-;EN|U>iKm0;5b?L4|T>N>GI}p;gyzaTvTOBxJV+ zwI6^Z4*sD|Z$#bI&zMi_TefXA>D_HaNgO4iXNSU#|F@$(9~3qRrEg$J1MRar_VUot z)9@NRcfRvsK8G{^5ja0{$hk#kGygq%U?Y^dC}=ZZjY;*xaVx@PNw-fcafts0_z?nk zv@v*`jZ$4}+b|S;o_@upd9kzMBr9|eD80;041$)v-QApKK2gi z;pE^08ZLswF^BIbw@%19+t6jY&I-CpZ*m`^hLEy~idzT%%ztcBy1d;Ms~Dc2;Xcon z^mlq!Y=6NuOdn=nr_)m=Cv2I)rL>{~g~lqOfeEmEj|$2GcD77|XPa1o<_Aoi+;`YC zT!VWUXk$yLt=Ji##CqbN1_cahD~TF}G@xDU_R)8IKR=3rcYTW;3d4pT+-Pj;)1*bu z6zkj=h3@4o9k;#Y!k|jtlE6sAT4+)1O#`wHd}-AV!>LDHK>27;$3YjuL&qL?XS;X8 zH`%>7Isb^P$g?7i{DDvt{~PB(gTMah^9uwT=$Jf_Psf3ghR+ZU>$e!@bGVGpz}4k| zTzOGD1=DdbpFYcsbcfi&eM{$MRpydHamLr~-JLomWwB;y4g~Cck3#PO1V+ zTe_=zS+14X9_@0XPyxMFpQ4bM#@7%>w$qlo?SH=+I|)gkDtppuf$_}enQy+a-P4W( z9auzM!HUNW=u!c!q(EkeH95D40`BxDkF z#6UB-Rv=d9$Mxh6u35sQAH!|7jClZK9nAD&Wa`IS>fB_?eD`RPex`m?=9;V!q}Y zQ`rL27BNpAO++BpDY6z4LQ#mRxui2ecl28F#N@2tnd=Ay21`h#c#!^D*~*iUper0> zGK%d6i;TG6U_Zz+paqIYKb|~b^TgVumSJo)l@kDWK|Ji`fDkHx3PJ&Xn#LQV&t{9u zDGRjf!wTEZUi@_$WB+h%gPUXZgkjXc1CwsiecHWi>MM(*)#r#MkO*zqM2d+jLquLO zn%D~qGVL!h`*z;!no_r9g+-eqkrH#hCOJOyIEJO+VwJ^RKu^N>K3aU6-YsA-xrgtA z*=#Ub-1kdv*%Px+91G-#jIxt{qBmF%Mc)i(m)|gC@O3mEE$#uyxEd`c!}%PprZX78 z?O?VTUEYlcGq}B*-A?C2K=FqJ-3V z$JB*F|9A1GRQw^ar#O(Ghc^K;0-|9cr{fC(#rW+|&~|nyhsGY2!B!c#EnYl0FlH`H zMzn=pNi!Ag%cjb_{VX%d&F8k&@Z$$q3#PzWQkhq3%y2SYTutvLe^8>^=z^~kvnQ&? zd?M5vWm>G+Y&t7&J`_MpU-7_8eW{q09Tmr<#CzZzs**A;o^j8!FwHV(*8g`L5o&zC zr!n?z?@v2U3y@tK#&;<{WFFB-%)?h!u5mPiVECK;Y|8~h^a zrbc^~V4{p(3|MK`xTA-Cd*Q8sMOYvObVq0*PRQr9&SDLOa<3LldwDgFYTX3WJU2)U z$WZX;9@$2iqobQ=(k=+9_xEOaLwLEd*AQ65L-vybJ4geE7Fq;XaAE`NK%lN!1j8V^DhUi~3+eAE@VQCJ1|Gjx7vv^Ni6}xa5|Ti1}e3iuL@Y z-x|(~Z^svOA=tD_Qvt>kFJupRK7RaYhObgrg?&qSBlz&*4w80phn7k>Oxcyg+)E{+ z96gfiu42l&zorO#y&J0O5QWN|<|bq7MNAZPcn(K9eHN){ zGfIKQ_-g-&F#N+W(c23(KY;9XyxPZZG5@v==Hc^R-=RZp<%I7XZu_*9-_+a37eSO_ zsg$zAXyXZHwj}>OS4E*~n_hm)!9ifm|mgvv$WT**hu<#;>G@^xl*2l z`NFI7<~zQ5V3{|6Q>6BI`VXn|B&D~c0(hLQS8Z?FND%&vf5o&XMTU}uw7M_lQie$W{4d8GDKMVs@?FbrSBH|9&&OHrR$J>FK1Z!0fy}^UUn#xZ^)d6Pk75fhoI_c8z6D*srl4 zq#4lx*`pp8ci23+vZ>{0TTSH%z@HNidodsn6^9yP31OC{Yl6>Zi^my@jPAn{+s>ZC zRhDA^@NA92v3l}h*}x;4ZrOc`-nI2@ilfuVgb5JRSTqr0g31C>l#C+w#G>4U3(US< zG`q&sEm(2c=0s+MTxf`nk33CbVX;`|X%|qFe0(3xzfErDFc{y$_rY{J7|(C}8*JGF zbFMfR$k8*>PKCm(u^zI%8cxr?p~>Lu=yEi_1q9=KG#>zcK!U#yXEQjTOkn`mgXw&9 zc5^wH!u8GcdNLa#_A|yx8j_R!U9iZmB(gkaCgiCuDSnG&)RG`3)6 z>(}SZ0-H)Ch~=MUMM1wl=pr`@>)GV`b~L`glt)WyPZu5)CpOA*OkSGDF8q3ehoQK~ zj>62K8d{(8B?dfCrBs&ZU!^vrdo_UG$CH!Z;mN1oNf&Nr11k2|^M2tXO7ob(d*s0i z$2@u8ka1I&DfaLfruQWDw82~=L`7&rltLtzVV;`6(kRgUZw9CE>0{sX?zjoiG?Oxg z4*pPC5T>b&d^(Wv0y^=c?fv7mYKjyIJ&-I|Iel^}m%cq}xBFg;FTsCje|fEzVkTDt z#y6Lj7__xwE6t2gr(Nhh^}0})SE7&;uSF_{U*zI1nz|xnp-@y4DHa;$@0M7x$2v|S zUSL*5A|&p6&z|=nc?_;@TKWD?na$z@mkV_8vtK{4p*am5MWz$ir~p?veotAb`~%-* zgltlwk*baLxBIVYD=CdGRQJXVxZuXGfz^crZX5;)aoYFsU>}0`Td*hNlX@H8o!Tz7 z0n2V_9F!;lvON4^))^x)%A*kH^kOs*CSU&u&L&q^qxokPSF3Pv`dbNf+USOAZM7EI zGsK@<6@9bj)}*P_YCU`SZ%^4SM6GCB??&8iwpdGL@Pep!nf~wMHK+NVa4Q%{FTgd< zZ1;)Dq;&X&oTB}f(G<=d6|NEBjj?MhhQ(V0*=|W~GoldgB+GTOFPkcC?sJn#AwG3| zf*(J?NiYS*L}l2hKg024em=Pw|4xZ+txLR)Y)ovq{X|zUl<9m;r;};v=UwS23zcTE zqYKr=l*0XeTB#tgDgk>!UK995J=9t9&25GjtgY{H`Z z&#(&b@qL!7@}66kPZ4x&)f0S0Ef5gY6gjS_HGWZa#iBeHm?@*H9`os1b<}W=CS2!O zg>$5Vmb;Pih;)wY2-ciX?p5+rte~c`E!(+i4m>d-ScK8Nf8d&6XTDox(k=n2_x5Ud zMg9t5uR*Sa$LuG`^``#6wb0VILUotGMx&N)zy#I&GZ~kBt1nQ2vxk-C1bj7b&Bxk_}0Y5*EgND9?)>y%n66-wwafDtC!*M5Qw> zf|%Xma{TatLRKrQ!0!-m7{9%^H*veX{Wes18?`H&JjfKI90TI&E@d{ic8wD5VzyAz z28GI?6$qnv1Flse+$^MSz;|$>^TuS??}Gzd(DZsXna+dx=xW$l6&4`FSBwmr_`J#I z9F+l*9TDZaOV!VLdp6J~px z78}S-$FqB;mJ7hO!9H1D>pOHvZF6VsY`1+}Dz546vx!`6$Wkd~2hqmk$%Z8TJ$FUP zYnNVe&B0i1E}oPv4gD$XoHKj-?0HPoAJ+8|af+`)z)8t?$xazak^*(0H6XuChyc!$MZp znDE`(4QR1R;mORDJj-bP|GaQwC3XCEYHZyNmbC$fJi9VDojolRGZAo zF2b8ul$r_^*0i3yfL$44+~yPP6`UlPGkLdQ4*=U^FAVxdj(BE3hF;|ICd`3CA_2lJ z#3Gndyv7h1qN{v!%$$yVc$|e(F>ljA6c$SDI8JQGN+JZQ%o&iHREbhREtO0=AO(q` zP!)+0%itqD)wPX%EvZli3ljrK#|9$#Vz;UeeZqm z-sk5p7v7!!5DIgEF7im|GVn%t&cLSF&w)YSiV8cdmd6ZyEH_#pTM@*2k#EUz%KRv| zjRcGkjzT+vF~prP2)wQ(AIkE6fLtO-%S^?RE}o!rAYDFzIg*-<6g`pi0Q3-a$mgoL z0Iq?h?&O-!P4FR87!1ftr6*<(7Vve&WY79qX-l~PIg&d9t1QZc=A?`gV|0H#hR`p%o6_gQs6Y%| zu(rl~!IepQ8;%kAR@JiBPSqN$gI4X9HsdbYt{LSVzp5=%IWMUvCMhX8SyrwXGj&)y z2&w0Rc&UbAi=GjgU6$JFmVANd&4LB~_+ z#Ww;;-0TRRski6l%(2=3BrUp8Ut!fvv1#VkMsPogv9WXCg9wAd-B0xa3;!wJ*qM1O zKR|$vh4l}EgD|jN=s5?+^T?;{D1xw{^9k4#Pm`B=^K5dMa*~D8u)iJJ5FWmb0eGC1 zRZVXqIS{?`D@v2YCWwV(R(s+yBmoAAA&3vn=7dbUpuOp~Tedq18ts4Is_F(BZAPQb zA%N|Ae)Z~Axz}z%8&;_aurnC~e|kg+ZWrH_$37ff35l}cQJWCG*_M%xMNn4voQK?L zvpX;dt(8`zhnONn^mzcclON;R8pdeRs|@DlHZuuKO@cOH2VT(!<1BpcFop_H@PUw` zhV4P3N6cqg^MR40OH`zgE(LJR#Ddb=@DfBPAqCxT0^z&KbL>;<;R?l@!~g(gnC)u?`<5zp?j=8-`nATdUh)oi$2!suxM z1DFpMtI5N9I#|Gby_i2Ohot=y@n}N^`M3(AZ0^YA8ly5ewv4mjCft94~|G(~nW znLSL`kHgL0#0@!u`f!tOHmxh#BXj(0o5F39l^Wp_uhNuAKQ-2z(Y(;=wMEx2k}^T` zDu`|>t6Oh~z?d9VEkmKGx9z^e1j1j1@(Fg>zX~m{Mvgm*3Uol`l@lk92sQdM{B)%4yeQlf`bt z8){%p*_e1TbA2<9TSo&0D@XE9l^_iO2B`n&fl`+2s(2PewQsh6ftc}gqLP>61JPvQ zF_zvomisVUPp4omcxZ<~#udKP)Tzf!gMeiITM%KL-gbB{Tp~!zNzHf=UD79B4sw;T zKTsY5=3SLKlu3di&;-j4-IFhdf31d#+4Z@O?VCnXHxetmR5K|`oBwx+j15)!sTZJa z^v&4-V~o}0(@jG)>r|(rIFnc7%0MqfP4fdukA*r`mdD$r`WLxeP`gaW=tic{u0Ct# z@a3Nq(Co2ll`FLL5VigVL$36-^g~k25*}%L>xu)$W~a{cCsRydlk9oJr8}$5UX8C? z>rQx_jZ#lb!!Q)Tcxi6Cdw4pKZ0n|;HwQ8lg`tBv5JXCsrZ!m9(WFxp>4(q{;ztp@ z`&rEE=3LiKy(GN6_xtzAXXU-}_PX)%v9Xy3t_oVgHX&8vgU5X#xkm?so-;f-+^>-; z2+6|4=z)NXu_pZA;MZg7g35YQ;x$lVz*6XU80tr z@Ci{mPMC%pp&j(-F#P~e#4;LA@8S|zn>@D($+hc?O7eSrq0>lsHDX}-IXn(B>eRV& z!!Tl0iANs!6kD~LA+}6Dx`h?7teER0mT)%e_pyaJol_|^-7y2rF3SM(A@gFa5rWb` z?){ka%+ZRG6a|bw>{C=L!3tC=1jt~nQasjkV5zSHTQc!n&A<85A3_^gB$bA2yl#eE z8*nR*hLFp3a-$jDT+oIY4gqCb5Yi1Z=}aR^bZW!DlO1Ph18R1KXTvWU$BCa)SsyK3 zWLx@J`Art1=2NaQSLSQV*@~|eOJf&XP&db7=LJ{RydlaA`cVv2m`}ae1_2$A=4v$X z@2*-m8du`FHA^t1v+D08U&#np2)rbCoRyN#PQ)M(#?L!XG1*>}G}{O0Q9YO#Z=Oko z!ICs|vmMrd@!cKJbW`x+g}{8@?;DuVDL{qeu#AUMb{#a{1xpU^A8#I>ZtrxG^r$s7 zQuTpqL6BgkXbJZ(p1axG!?*|F_amjCg-_8iiu8jRe%l=S%K8brv!tN10}nmy7XLw- zaiY+}S7x81(`Pb*ZerDX3iO&PS1ISZha9(x?nIQ;Ei8*z3$G8JOJ5Zjk8)EgZ7rHP zER2`8w0L<+eJdY^DQ9H=9J$51aRJF73gllsWrlxr{GBc;Synv3&`_}6VW+BJkiO10 zmb}U`xXcK6oYg#SQ`<qnO$2Xf2z)BXT(X%XPt1OD=cZdYWHfh9jRxUX!dA=%GHm8SIm)GnS zPkA0D?A_)jiD&FhJmYD>JM0_Ji#SW!^A6$&3${jpV#y|hnLU5i&h}x1d5L58_ z;%tMmzXN?B84K6zfh4=iz{(?DhH+9T6aN6lSO9fN z#Fil#XU=CFj5H!)t?wQ_XC&Ap0|O!ZBdd_+*JFjGjl_C(_3p#)@)eLgoTGX=>^6_l z8Z&iFn$BZ~{p}bg!}Kd?l#NROgVh)D95%d2vMeV%f0-2}!oKaZ?(^g0?&0w--Qy0s z9`}*iXFEGT$LTEDM4Y`S$|&OVqvfeJ_!lsa6`cL$U#zhh+|GA*Xc-nucVrQl&$8$S z2X}r3ykKFBr)7ROU8DO*7eRTq218AF+GfE&*&z#pY(6h|na$l1HN!Z*Wu-VP5l!LTJY^w2~o}P#Xmq;uX=8E{gxgcLKwv{LN{ZHiU zfBxa;ijY~f(DPIHc^H9@6Yy;DDoiXK%&_6xo|pmzMG2NUgENvAC7Uh7oDDC}2fs~U z5BleW(R4g~_3<-1VgKGc-|MiwA^sTQkF&k|UgP4yZi>7lx&uP{5s#iE2AE5-8APy%&yp~gnGa0LV_;YZSC|*v*jS*a z*gpO0*oSxjW;37jyrYhjcqGQ!y=LU74TD%bv;7EiC58PP3S>KWJc~8d7$9fiY{~x& z-CoS%I0wEX-bi@^u0KOt6(J=O9)vi8Mh0sC%J%Uu&*Ge~AjzDrv%-VHae4qkmw`G* zkkNuYHnLRHGW`NHBqs|`0iLLa1!=ATqK2nayiW!0Alt{Eu%bF#T`P28OMKr|K!;UP zARRjvab`YDK*A0(F;3BP$96Vy1~9eaISULJJ2_#O*KgjmcUrBSgBwrjkpOAo3DGlM ziM`MeAVh1tZ6MBI+=6VyR}kF;sh;llt}wAGF1hRBsi2TNl^|1)0Vg2ZtS$PT{XNSh zLFjo~q&KD73WcqE*c&|6*^-0J0!G1*x|l$U3)f`^VGph-Um^3(;q=|16QkXMws{7A z3$8Ck11W8!rHhi0^AH#b7sPzzTT&y{bYC;QS;E7-ZlkDW=di@U3*I_{7%+ExEM_m5 z+|iEg?BF17J2DaTF)u#GpO2(ywK}Y&gjP=^VNp)SB@qa4rtnbF81d&lL=sY-otE{; zPNZV$l5mfoEeH=Y7Fs!?F+1Q@Z8_6zBBSDb&;tBqNH>jHoDh9c5*3gN<#fr#wbK%5rx_zI)Ysl(zZzi*7_;iA||EG zT7;EOPV9RGcj-_+;5A57DiKJx&~&1za_JfF(LzxKipRFpjpT&zlj*va>kr#HVCcw= zfAkv6*)>9O)Z31@L{Qa{ROv>e2e7ydc11Di0o^njje`(>D1_a|t#uL^sW-w}98dbM z2IJSmi%Huo@}x%&=W@Gx)~w83CB^kf+mILg^tq0|Wh%nA`n9^Ox~%zX0b1-dOeX`k2sb3u;#3iF)YQKJld0O0+VoXT;9cfw35Zh4O4zQm0&1A z>0fYER6JlzJ%AJfJ9lmeo^9AZJ3ji`TqH(7Vqk4hxg2S{`;E$I+o_%72`;a|1NAI@ zTl-Y)u;a<-w`|(;=lL=b@vwYi$*T$>Cyj{FxP+Ers&*o4bbfXdayfc%Al*K4F0g?` zTh_JJzN@y~?QIWZKT>W3crfe;Oa%LKtA8+?E!&x6DHDdk-9HPK2}&c#gqUt1Eye9Muu>bL?q|b4Kxj# zqW4#UM&AxvFoC9F`3<%6J(F2UOUM{e98}Xe>0~AsSJ#*4RIr5yMo(0zeR8eKS9uWn z6ZiM(71jy)vM_;=ho>_TP?YnuQkw9R;;w**Pr9+DWZu*AKs&=C;dxxS4v29ocCsoO zr@q=LoTR8;!~;a2;ffbA(xfAAFd-9|{Nt;yeRIF1_#>+$+p2PexDssq^*97<%C7|y zpiD?naKJFx#Xk^?^AbA-HlOhVEOVU>(IW)%1qp5 z=@Oo9)-s_0fJ1Cd!F~#`LJ|$qLJ5Vjhe~>Es8!X&g9Aw+q=JT;ty{lL!t|@Xd4GI1 z9O63;e6z{Y&FTj5WpkbBP(MRl2qF!ACaeN=WtM2!1k%{rx`1)qRrE>`V~J!B{(~FF zQ#l|9plMVmMD-mAvw%3C#3{F#G<3U%_Q%Qpl>QL?K>qRHyN5S%$;PkyhsV@uVdRU= zDRH@17|v9RDYrRrU(kYQe$1}&ZP|47H4krtT_Fh=Kz7}iwSxP$smrK+Yj1{$mv`uA zG_k*GYQ3^PRhN&t`>iOa;wQY=Jn4gc@1S$uDpD(j^~>oAj$YiNYHr=BtJ%I-o0IKr zr9-DGT8&=9W|8cr8Sh#YE{*qMC%Uw#yr*#0JI>l)8*1CCsO>o3dMavO9sc;6IgBd) zK%{v9gSS>#m3=FmJW|*sNW++2#K#kj)0pHapYNP!_8*V|{VMBSFaLFRH5y&Nn+(oL zGXIyaY^g3^t2K43u9f=RZaCwWxJ*meWv+)k4Gr>AtYTliH{`(A{&MP4YnR)BaKebm zZ1b+|K>M1V7K#QA0G9fW3J!}Ry0?|tG6@8-$}H;BUX+Guwtb-mVHU5p?zr;rxO#BM z8iZLK@ozP77&8EIn$-Yc%-TMSczs70G$0$gNw^R&W&jo*fQ1d9TP|u~dZul?-KYK}zL9fv_+Laa7klZOC1>nmG7vG63T|7cRKotfHzr38R8!ZMv-tz133Z z0@DDw2opw84Q=VuRG}4t+`bZuII7-dk*)!-IPFV%vI-L!MKoMA(+3hfR} z5GcQ2TwDlM)I1KbPJ&bqCXrS=S5j$ZPi7-pRWCht4PGrC4S&cie|P@`gHi=@W%1R1 zL2JKurKYZy)S49CHO;>Du|8Gs;VGUgp6&XF9VMDV_z(5yn8@v2r%zZz1aP4}AwW0h zS%<=I1VkyKDXrG(yy@9at+lel{@TU}Uw?DuL~^ya>YuNAJUOl|11>P2_w_hFZb!FE z!QIuGvyzwY_Qd1QH=;Et*tAhvI`#t~Yo@|jW+fyJDu>%@7SVx%NI%i~kXzCOk7S{JQSZC09&&Ku*&3^);F2wIJTsPO zB=E8O884rE{XNWH>vJz)?)N?6p#d+YyVUJR`0SHZm25+oF&!tnP*`~>ZQTr7}frH4RnmgAQhMo{zu1-}DI**pXd(U&1u z{MnNqRfukG{i#M#0=h64Rf1~2h`K>p_S@h||J-4#HADGarTAsFzs|7jtJtijvoM)$ z60CJ}%pm`cAIf0ct7)R={Oc5MxwpV?0MyPP>=*b>ihUBsrN^v_hEUR{ZN3a=O{qX5 zvBu>|uqQw5+>_2^%@^=ma4z$FLqX64Dw~KCU;A6ds9mczt1Yok z&_?&LQx?C`E7svmeEn8rD?6n8L`29}Vh@PYm15;{5)@@MDcO?1IT6$^Mf_?Ggagr0 zev${m#P2eNZ1s1TZXO}TSs~;HL|RRtT0W1iljEnkZ?{m6cTxGRD>-cC$3?`YhUXhT z$8Q$t>Z@Gvk#^5k0lXF=A1;I&k4uFPym)xMd>!|r?jAqm7t3=eJU`G2@Pv;TM00QT zBQm^GPhWnR494QSv2KTX{@n}D@ALqB3ivwy%}O98iWegLS9uCeK>`vcPJ@-Y+T)uP z(xCPH6Am1n#s&39+D%yXrs62mVPlGkP(f#FC7{J{5BBFC?< zMw4J#Ec4P(Nd;iF8mAIHhdIoFo8v zup=yIJ8wWOU~wK5HeJUyDa)fO*^S8DGILAXid&ylA7fWalva<8S?2pZyjrI8i9z)J zRClleO-RuuEpq}H-;D6x5nAI8ksREii#PpOW0|&HonQSb|BnDBOOri3RNiRQNBqW* zQ1pSTk^Z~Ggilc~FuY#LfO{>V{>{Sw0-QCnXuDr{oUK%`Zrd;rovp7R;w3SR7S3pm zZHE9sx6TAZo}@!0QXna(ZjpcQon*-tC2w79@!jL`-g}g`SXcvvc=`G5_1E_w5^42Y zR#IkLg3-cCCEKFab!R|46j+06!5b*)j6qyZQhu@F@W$LIdJ zRk4ya*fLhf!!x!06h*Dd-U(ePFLunxv(J3R`se|8z=3F0)5}<=Q6EoH<#+2lU14pA z!xVCale-{NyNs_~~gW(?jDnPdcoKRe496KXXd@&gumHU_pYw|zSm^Y0I8ME6pI75vstJLzpY*3-HH`l^)1F2ThOj?jily2aEob1^7Y;gq>#&%N9fN zM5-(Iv}riM5zM5g&t2I|y0@iUo`{mH~z#1^l`0(MDu<(?(X(BdR=v1Y)DyR#{L63dTKzl zE_j@ElHYHFFc8O|?O$<`mr2b0vAy|3luZ(cgt6(K8k82AKrv8^ZrT67D;USd#zS-M z_j}h*k23_95#!*v^VQ43rdfEP38loqLm^q`oESpx(<)-n-{)DD%iE++2pO3W3q@&$ zzMBCYid?}lOewvmz*9I7$#$Cy`t%a5*U1{SxfsN9%E7@CnuCwmj zC=Clw!?^qh=E?HtgR?>wOztSpOUt(rX3|kS-+8r=W!h1KH?OI7;(y$<)#dc##)PQz zf$7eds;Kq~J^+wBV_9CD0m)H>UBx*oFaxoB$6Q2UMxhF4wN*#3J1czE_0zsmyfdmG zWwPbNU96I}&k$VSuGuz@dp9M$rR6TL6+BCtL@rWRlL#3@63Pg-I+4jpaPnDq8RZ!v z?4(#BK}gk_f{P4hUa28`Qw?jMo{%Q0|Ia0ihLCfPK3q$t2D5JIO8zL03%V{)n)=tk zYT_@Vli@nL5O|z*k3kB;Knz9qbBe%hv>*i?dI1$FXm{c=RGUb!ofak{-rkP26hSxt z!+QxNR@hg>kQeLyakIrn{PlsCw&_YmG`4r*>7O=M7>1E*hIq(}-D$N%oEwuSa1R6} zWNvX51(uqiWe%jE&yFBTjs5IKjv6y_s1vRO(GBojlDSC)Efp~47v_QUD2ydv36Bl^ zO}`(B$GiY*z*Y>fK6spsliN;%KoExSd5TF$6q;zY5@OVP(}QWWHlZFaH!IAxn-*x8 zMeEzU%b_P}^oH5Y|NX=4FxXNg5egVR_nuz+0~XU~$ig&UamAQrYe^<}M73-wpd=!P zji){KHV9nHYPW!gArd(*#A$@E;u()oVFpz}0)STAvMV^lVMCI z%J+=ydraMK-=Z^2)%k6DNr($zMUcL?6-aRf%sh9qqD+e_Z+bJwo3g2*@uDS#q+~LK zn1@+Pd)J+^(X>AboY>WKbsQ5E)eteKPps|Wn&UaQAe}ojX$Uv z?GFTiJhHwkc$|e&O>5jR6uj@R7}!f=8t*#mrlBN+&G%x zDjSTRHugKkFj0nv$Z%>;GJ2=(y+)!x0|hMr%OoN9G4R`Lnf1Ft0=EQ1Oq$6^^occY zV&l-y%M@Z<2-AoADezu(17(XG?pbm+^CggW6FCR$y7)JL(cz(|lza>y<_dtp2i}}C zjKZoA2gU`;vYb6-J)>CV^wHWxjCDSpl!2q`-b||7_1zK9UqaR0(L5!$HYSF4F;S4d z`>{Cu__+Pn++1%VJEcK8nL9V7+PEJ#)GFj!r6%r&Nu}n0Q;iXGoYm9Scye4HtbJeC z_H=_)f#Zs=b>{u&s^r&;yYkBW=jB)Nez&fxdQ-RAJHw;(l7jJe@egIL-1fQZ0eGCP zSN%`pI1v4r{1vmDbhNZ=6TVRasmr!dsasG#w8wE(l_pMOk=Rkzqi z(+0^ZwP&8+yf=2z+O`4PFz|T-9uFAMXUrHR(o=IgW_4J|6dYSX%v_$Rm`_rLVG3;F z)?^H!bh)=65S&Ye%VJPI1I6Mn0qN;4m)#*;GQnayfSYs@a0fcvVIpBwn6WtFQowGN zFzf^(3P^nB!epVdTg0cI@qw1aO>BiJpD}@Q+5&9XXZm~=Lz8^z{Srv5D10X zsq$rbVXu>AO4={b4~leXf$}kqiz%8XLrpEk+;u9S0ZIeX;Y|$) zVGS?=SArcy!Gh#lvc=_yIV!1xhqki^JB$MK57!pBIaW^?x*NEo>8{+T-K)C3yf|8& z`%Hk4N~?(ylT=!WtYn;G56nrGJwf*6%T0o~#m~=~7B-OBAiDo_S7hy1ha}^sWxcq*xovkZk#gH3 zd#W&xId!949h3LYV-*f8T(reKItqP-VVK?G9&XqQq>Oc+f02oz*l!ImcP-1@vGz=> z3d4Sbime&OZ(KM*>N42GJ_zxc`7J^v^|C!N#QKcOe#ptjoMn^>f9Tx?3QWTI~6wst7Ag3rGwSXpV$+}W!`4pFz_*nFDPn^m*6X$ zdR6gxAQH8N+Q!wg@x$0i_}^@-AgUW1^n@uz2yWIPf>WR+>6I{b=bXD`oUBx;fQe8! zgWWRTmm3?jer5O@2DRCoa zDvbqPwg=;8_j+*M{z@?!ySs=~`4`j-1D=fa#QyN&0-wfpE%-^FmAnDF z!%hcR)_q&Cq73Ta7f{rgTYs5bul;|?8yjZ%vXTj}k8Gx}c-I0Q`+84uM02Ot*2hN> zaE5(C|9#S#c{Q7Kacqd4ojT}C9;KK=Eb*5D8ALzT^e+s2JH)#6OPIzLaE`}PUjgq4 zk;lDYrjIhRc{xkrAq$;oQCgNwIHIi2uR&-0PCUz)>xlDO$A18H>G_bY2zZ<`G%zqT zF;OVaNHo+-X2^Oc%^r8`<~O@z|JgcU@caId-K)c+y|JoI{rZOlW!JxkNUAd!q!xMC z?VZSPxvcEdnbm!>DnEKS9pVmsEAjY_X7%kgiz<;+7ZfDx1v5AonT3_vn?){tFl9yU zr6Tj!0KQN=T)ta)oQ+fOZ<{a>{S1G_t&=85Nd_dLt(u^< zX`}VSq)F?fNmUgY;s&c=kZt-yYyS70F=I5QVQ-yg$wQs?lEr1w+^B4JYDy_R1jDH1X$#VT%}US~|g z0~Hd>0gg)4X0%m`Jr`e|0;EA7Xc;>N#)Dfmy((P$hF{or(q1O~aB&o0i+ zk54*CXpocR^RtWD{IY`#4HEdna6CGSI>^W%v*AT}8O(iyhR355#U*B&CQ6+|9I^A+wyW7>y!h=ms4+2wX*MG}e<7W*tm$W0E zLmWfY;Qy)HQHC!jlc`D9)j0I0#&oMPQt`NcYu0myKc%xboR;VBect&QOe-6on>n@~ za&>rUHt|?@+RO`+V;D!B31Xy~TssFzRd)`}5PYv4CRa_v?{s==^4jijA-nw+)i~Nx zwP=2GbZeT#6~*xT1hiZAikU;`yL-RgA2>#&GQT2toMn(-OT#b}#h;r`abYiAsofv9 zA#@C-Ao?H(DhNeNnr3aVy$#K+Fl67|)H!Lpx14)^H#sLWkAVj-4|i7!P?auaC6PF( z8Ut%|UR3Ktqw<2lji#`i&)4wG+Y+9*_>@h<4Q#d5t+_S4N_kK>`Ofam*hHZy+f2gN zP^OTAV#gRAw9Mol3^lDF_-0OPt?Ok%P;gVk>yNNE5=eh?v$C?3*h#eMx=njBDo2@t zD0l;DyjgYIJwCqa21iKSeaMcWwMcB$Bzk=h8MD-RvPd3Lk=ygZ6Vq^ryy=XS96>&a z8V$i$tupYm5C56U8gsz$CHD$>=?;T?U2`8UUS|{gQwk;Iiq4MHqsIQJg)``M$((99 zqgt2TZ&GI%oc#ci__Fu+1FgEac$z3Fy0fk(y5^RF1y}4y@g?PcCgNKnr}K5CQFxqN z&$57J!%{|$U=PQ5=a2}_$r~6&C!b_gnEaMeMG7cr81I&umzcv@P>>vt;Bo-~`YsXQ zv(W>1oW)sbZ`()`{Ve^8#stZTHl>J^EX(oE>^ioS36kA0a=;&Qp-Hx+UQ?vN!;0qD z@2l$OA;}67V1P9sOX}lQb=9k*si#L>aU|aTanbjLUan%bR7oKVohD+IX5uDYtL)}- zfJLS|%eYkec`eDJd9-;%vM!;YQvF=sE9{x; z93pdG6la)zYhYv)L3r-gIJ_b(veqH2;oe#hQRZ^4gib`U(7DLcve1cY9lkm92;VB* zMbDmF6sb57>okjUkDAdzonC0346a2_hDFJ+*Mq@@ zz%f*2fjkdL{sc%@q-&rEj0CAj++`yF^%#1 zyC?)ae6=%n?72b$Ax|+eu%gSnEtPBllag>E$v}wS+j`PJ#Vic4NMmL^DZHvoVR$`o z_-KzJ1v4n|_M%rfon8R@Qlsi9qH$w0X|>a8@QE z`$Xp)f7jypH}Uq*_iuU^?ujFg#f#o^_tL$hkGCK7XS}^W7vj0FtDd`~p=03_7T%Cu zW^~X*E>-kQ0FQy(YX^IK*RK8UR9W@z34g2n62Zz7U4oBb7fTT zH=8LAX2V|KhHgaSehG9T)*6Nn#6LwSo{8ue42#~E0QoSY!}aJ>=sX1EH9*0a@JmGc z2VWxROZd=gzgfMM|4lPpY?_f?@We=CfF~_^%ap9OFVtEG=7siTQ6vtLhe!xzY+arx znf23Ep_d5vmC7)-lu4*4=%jc#9#rmsIVP$|G3x6)FEL*h{dCsn1O#Qn1(9v7i-j18 zi#H$OgP=tG7N}GSz~T)79g+Dpb{tXC%?ip;kDZ(yDnU@NlWBC6dvp-G9_6JR8}aW6Qi*~VWk0nyU^i6ER}>% zPWZ8s_myraf~(RNbi@0?oD-7-)1HR{w;zk+@#jHfdZf|}XY(eNhbV^YNR3k&!4;9t zR9GOZ&$4t0P2kauE7l7x;zmxUmJ&q;T201`VG)dcawlyq7HQsyq_c5$BQXRru66}# zMx?2{;8Hq;pv>^3SY%2GR3k$uqqq%}){%UaBQR<V z9XU!Pu~GqD$&4C@cp#=nv!M%eAI&`T=DRo$zO`^-2`$D}3C|HxDw4FIH<@gZ`C%*e z)NRWh86OfMERBdhkaC3F>{`z~{8%tP(-+v?b)fiqIqaO7i9QBaw9}vTqNUW0(`Q-{NjcOD1 zC07GZCbN=SjCPEhqD#SyvSPekIZNkDf(SNqeaV70qnnL?w!sgUAm z4r{LrF=Fa;B9|y1saS3lHJ_>t%>cbuvwFT*r#qreYUBcFJZ;ZFHsu^jT(Q*26{;Mp zLAAx9P$&t2Agd-81eSM7oSN!}+0o#{e&(XbR2gjbpnGZPQ;!K&AZX-h?jfCW(kWum zgk)Y75{Opo)Nt+mAtY>Ux>3WFSl=mb%q$sDAhtUQ@bC}Zm+vWi*-nJ&6sH+Wl)4RJ zCi_(zF=}FNnIbP}w-xVLW-21zUJ`Lu`*B?R@#$e7HaXj+5V#u*20!o4Z=iE!x!WH8 z_q|E=Y4jbZS{5+g1EBw5}3!?cVe(^GF%oBEn;E+Qzj zQA&k6Q4ng1#;%j8nttkv1Aiuo{kXF~bq|?kAIZ46h17PjHT&L{;rT&Fg7^7~8u>g% zKYaAGI>RBP$}Qe_r|z}Ol5Oj%i)s7%51Zqb%-xEu%jjrqPs`h|q+Oml*-GK{ThdJR zb-6*PZjL2&5!5d3ue04ik?HxIo`u-L{D5EmpU${{TksCIz4{%z9}C`AG9Wd7BpLi@ z@a}QwP^#VL(hnws?v_hTA2a4grqe;gx!c{G?~V3~V~=|Tyq)h)I>$aw`VUWzcyi=y ztMTDx+?yfu;35F3*UYG8KYBDv9zANar={5TBtOP8>bZ>y`)jP0-(6#sHB{YG*&jZr zvqjrFQcK%voF8H0EvL6eiT3o=OivF?d%l_X{6h;ScEQBzha+?b^EeIS&T18Y%@@-9 z8lrjbZhd>!?c~L}>^#mqw?7@C5%e4yTCQnme5E?b7xtEMTW7HZr200x!w!`iTeNzyTflMa_VDY)&YHoMBkBDEhO1Aab+il=If>T z>Yr8Xe5^w@WIzLYdUke3I=&wEy))L0Ha@o-r`5)h6>woEPP@jERcPQ!g-h4g5d1dX z8G^4o-)VesHKYN0P~z^6PUtC$OSd6m6rHH(j10A{z6zwr>ifg~$mn15?#eS5{RlU*EWIHm(`;e>MH@8g7CG+~^{uz%Xd8M8VQz)Z$lhxK?wOs0FI zu-2)+JBkr;%H~2kBgtczUX!uSB3|!w;xwO6Tc4+`&u5mJ7s!d3%FDRmrxZBMoPSAa z9?X-R4sneM=Q8)|!6B2)W!_bT{uxuwW%kvBQ>K&4%&G@ZnMy9R3ijvP3F55#KL=7a^S{pm zc$~FXZExC05dIu~#avH{fIt({7q#*ciM}L7N|OkPs$7*r#$MvR*t?crLTIo5{btr{ zdyP%VeYkuGusbt5^E}VY?qRnDU6^@1h9&nI&}YOL#B!Oe?1)*gmMJ*4fQY#~P9nZY z6EsV}7Ve>pAdoI!t|5#H1E&%Xu@iK8i4Np57GS$BrzJ?FatZNt9#h;H zxY(5g1tAkVO*|RJaK|5*DmxWE4|sy9lmY1opNo6t;m9CF)Le>?7out|;1p<%Rtqjv z&M~Zb;(I?IZ1565@~0Tb`bi=AMUO3aIBtUC^c|LrJJ)) zr}tESMRByd@|XZ26NM&1Oi(Exbji5H9+{IS_5!o-XtFCxEx~egnmrj3a&|&;Tyfur zg~DQ)`aM8Pit%kc0K7m$zx#4|J%iE34SX9-CZmhlja6XF9#|HNV}TqaqwFGEBx|gP zyuW^)eEfngqYvZr@$3c=jMMS#;`4M0r$Tu(<->|v|*I~R_hx(r^R4gzd*?}f1zu?M;M8+Ay_EeEBV zz|xn2X5kLl`}Y`L+t3!BdHfnr+^cwa%476y^y(AZ1OCw}M?3mX zl(#vVSis>AI2+IAm*Y?K$>`hkPdJ3v791S#j8=movOtLJ0p||?&k;~wf)hZ2*b%J;=Vo4ea@T?Yk)i8!` z9d;*TcEYN;;{=<>{0AfKDT9VU>Z6WgwmVcF^T76f>9i@5T(;F#r=tz|6585$2p8Aq z=NYo}r)!`^ZG3nL5y>0U5GWcAXvfE?jD&}Bg+mb=?^v1UsrUO<?RPuQeruxDKcRI5D<&1?c9v=2VDX8PrnyRumhZHS_y;iP&;?NK!s>xSx-8yc zsTM)gW^zw{DC`=CMMRUzp9P`xkkRy8%`9t~H}s)_NZEgzrC^J}&=iagu0@KGn@0}E zi5w;EZSw9_T(WTo-R!feH8ObUe^ybYr#L>z9(zDT?%6HSAJmb~7)Oraq$Y$iK)qIc zHXw)v4a!m_+}Ny}Wpy-jlt|{aD`hHF$8MVQ`x%UCLgr%x0U{|Y&;43+m`V3fG#f+6 zzF5YVJ~>0WTo&w+?5nz=GjAK3L+_w{NvBD`!9i7NN40^Q%cTwgUcvWi_=M^j@4)|E zY)1R+;O@UrX2@(i@+*&CJejb5Yn~yw@N#-Heqnz<$7${aA!gQteN!MxUu1n$)@#&k zn(ADPgiGC2CR7D4Tzepvwl>^0nzwV>6>O!x#tqEU9>whyS8l#SJk%}}J`+os`P z#Mm+R3nt1q&1%x;1uTeJQkwVh0d~}b=N{L5A#4^|d6+c~K;0_k-Ba%sgM2Nts8X z5tmD3Lx>H}m8QHKo+k$3wTB6&w5^3yn!6fklfz6e8e!6m`npXwwD}C};Qtm%SiV= zPju5abh`E`ACyU{Jrhu?*mcq{rHsiD{*cD)Z--vy1a9g?WbpD$mwvw{BluOvWJZYu8 zcz?D21xWpWm$A75c$}?RU2oz>6n%zYal4fe5VL`_yQ)NkL{~``DIpOMt)f+g9D4}U z*fW-A975au@4a_CHpVtdD)j~M%>6v)%pE7k-6nKlvE~X^JYYcIF=L?QN^jhl4Ph%2 z@LT~g^SRP7e@HZ%X>f&qEMo|z&sSRtf@_KJSqys3K(jbhAXnz$VtNY~Ot9Du;3jzp zxCfWqV?r?po>{E86ma5D3|B!!25QZGc-R{6bE;=<>w$BLNnDLCAJKt)CIVdF=d=V` z8kY#Ob476#aPd|R6ogFNM6YG6;E_Kw({>^P9&(MP>;h7XfQu*N;mI&U)O?DNHDY?s z;S^|&Ru5d5niXugUV}vE7@}A{#%`$6&V^5*3m9WDidCIuLfCJS53=-VgZ$Bsi$^3+ zhNiRxeT$`h1ZXb^hgu9MLLs06UxFJ&!It1ltHtezd0Gu&g|xF5H;e-05BIj19J{9& zMh)CEcg?Wi~AF%q4C3{b)JFxtW=CzCn zIaiY$H#`X7!CTLGqE4qyTm|RX4cYt7=PZra&`5ex#XE27F@oX{qa(g+R!OiXL=6ZgH*v}cu zWJp2kSun_k5>@Uq?eain62C(+Dy%N>VeO(gW9Bgwsc*oFwr`&^18g8sAVz;i6;^&j zP_{M$>zC`ByUFwdOP;KV9tSotCpF6Km>fEf4tyHmrYoM1QJ8BqL+^9G!i496l(EtI zA5v+uy&6ORWH9LW2EX(N4&2Vi)a-Gy`7;+@koXKfpbkPj=IalIwU|B2hd)t=wA@r0 zGkb`EP#PtREi(w+mt`Pbf4Oo!jd-3y|KsOR!`wI#ia&}}aCp@95<^B(21_Hf<#O$+ zbvunnyOR6R<$kC6ceAnQ8V{R|kcD2fZMR|vxZfLb-vPz{Vsh1vJ00AQnNDIsrazj^ zN-pSD(|a*!h^k}u%?EZDCTQeDvx8wjnv@OG_nlcAdp_$7MOZbmCXiULED<1 z!u0m?veRs2wbLWn9OHl>sv(I?k2I{j04EgU6v+(^2o&K7G1$oJ?e&Jc2l(eSZv;jo z7`(D~^2*+?uk8KyTE5RYAiWVSA|C1qc1FW|*TX(F>1MY?qRN){$mz7(d6pv>bZ7?d z3$RnjE2Pg2IIJ28ysjBc{zwcfjHILjQ1d z#EJM~@bCN{PIC>|XjX3+t^Npc95}IVA5yBb=aQag=%(KliKm^@XGP%nuJPgk9oM%s zd@)%p&t|jhSqZ!h)n}+*(kUd0uL7Wbrv|UDH zOH~o!qoaa&`juIjDWKXbUK&qH^oo$`$MpZMpG^O6kn(OWGSwUacC)67IMvBd#lxMc zCu1w63tFuVf~6NmZMub8MY4@b$huEGWla?=C~H>Kj(R&W_CUaeXTtj6(Ktlb0cN^_ zZOl(q=7%;YqLW@_*&`uanc{YGo@9n~b2bm~#)M5#-UTVEfpXxzubAFhInaOUJMi8V zHB-3UQaX(d>oszw(Owm^VbO}GEh_rD@9e9oX3&eA_(rZ{Vb#`x9fUo^+Zc&_NaR@L zLZyW@rwXe#%o|2Snize}H zejehSHV^WSpALQ@;>&cT?T&5jENL8`C5=2v`OMpw2yw+^reMhh-kZXJNYR;Q=v2RU!C#hn+!*t6_;+TmX5Bt7U+=-;JuY|N}CsExX zdjI`~&xC1R(RrUWB1q3$b|+bat4)+Ij&d`jQ^-0gUJF^=I#_ZLzn6j?9o^f@!d6#y zu7|n2lu0nZbLeq*NBu`!@y}V!;zQ`B@{)Q>|1ZFg3fhGiQ>w_921$IXdjrU*MAirh zu&j`^J#}|IxQJiR6@mH-X34ypPr>Ye1LMUI5Z$@ zDOu)|NRZ643`sS834C`%_n>s!YPzp?GhAc20G5XUGV4sQ9QTkkaPG8jCL8|EZUXAr z9LszRrcbyC&k57+vjZL;Is3^M6-j$rua`Cx}ywxUm)AUp62B!-BVO!TU_LnSStkGrc%;hsNNVLH$+ikQ?Ao?o(j#3 zm9a3RaNbfDb0A-1OoNM|Rn|C@2>G9biT@m4U*+{(5dmGHlLm&O#WIkSrLt zUoaS!yOne7HJ6gHN2B$r?^ZmNCOZ}vE~3EFOP|AQtYsjylhjHRD+8-EwyhZ-hx-^S z`Pm8FyeE@Pg^dG~5*s)F@7I%T&c{f&b&A*JvJ9xiiv0ovC>UzL9eA8=kwI(2Fbsvy z^{)`kB{gMX*X6kFFetn2Y?4?>)umE!oNh4o-)F5Egf16@^t~tP;fz}L*uu-}&DoQAq2yAW{KmW>Ie(SQkwOK(Vj`N`T0vD^gN3c?# zuu*6>6OYs}deAh)-NSvkXc9*lCBy_u^PTh;A+MRj;M@>!r~*25=F6N`-*l6@XDzax z^Ix@xWzIQZ+LIxBYN4=ee+0HLKL8Y_1-U|aoSlS;SeR5w zL6x?oYCvdDRu-QdONm{@&O*od?wr##qFaOz50QL#|NH0i^JS!TUN!>ZEH_nU^rSdr zqdw<~8Z+^_ajLYwLM16s0{^~>-@Roc0E(1G=wg1ooX30~f8sZE@YSQy`&MaTTJpGJ zBP^AC>JwqHYkoxV_}C{nf0^nsCw_Ksr#tI1cW~4~NyerZ3@+f~9)wYP3$9R>I>5CC ztizp!79r0xWDZKqtb;8&-{A@b+34IULuvze2-Z~C79`9~fi-G32E0e@)va>H!CNT1 zZLIU}(nxkj!hw&SkZ|f@>5f*q;PHBsES71SY*L=Y*9SWCq}u0uszZ$f`agko<;7-x z%j3oR+rPP;$PX-!NR=i^%5kGhvf%lyvEjW@B4R)LT^RbhpfsL}*Ux&h)8z@$+w|-5 zhOgq!30;#kGZuV7m+tAVsujiIxz9#3#sd1jFr--`pP7g@ZmK)16S=NUj@Fvm!WF!U zSP<0cnp(r(#k2ok!oa$^$sN%0ak1A~rE)rpUhHk2tECX{*l~h84fi>(Gaj__jRmY&e$*Z z8??q%p|y$uc$~GCQE%En49B0FPvHrvB2XxM&Q=w*Y>P(O)KY2MOB627I5o*dcbBcK z>UW>-l0X7U-&P?N%-=ry7u&~x$616i_^X@cAm;TSi{lSN#P>_IUTn|H+eA>s9_6t}&E|>0!S0dO`mse#!(HB|m z(bn(nCmyjx>^dPrrKQ*z7xL-AH-ESb=Id{F{*4I=JYz`_A$$l`dKqewayH#w?b()= z3aZ4IW!i9UBqLdaQ6*Ps+05JyDJzw=lnfMC7cwiWY|A4&l9M3_vnbG1W|zYO%ka10 zkvlUKFj2U#i0~9l!%N*JU3G+`aW!zg#17w4?mZs+;r%4Fqw&KbR}(t?jL z^PE?kjsqqmCNafKPwA5}%q^lYNp|L`mftD3&SA5I_muFwBi}Gl!uXbX!vNyFMB_(g?F=wcNQP9mQiAbNQ`vvG z-r7>D;C4(pCpdRod+wYJ)v;|i&FQvY?)r#M^?eTt6F*I7)@k{k4`^dbFg z?I8D5TQBLBc04{&9@hDAGHJ){3f#5Kt7nhT@F(Yh!Yk z*j-vy1ONBVEDupfk{0L-NzKmj%{RyDtm8okrVC+UE)ov()|`V;bGu}k_h6-Rh?oS; zV_~coVQx{)0+aEX(vYfH%vaF6;e=TYsj>E&@44Y<}xPN4UQ3v;k(8vC+=5R57Lb2fb3CE$OkN*N*%NuZJSU| z0a{byVJ`>dq2bU#tbk=%vLgBlw0NBH$eJF^vF!YrrCEaY!?P6z$Lz_6>jn`yxK;Hj zy6^I!~%%j}05Ye~GVsCWnnyk1g^Fn3B9JADpOOYfH zIxgmU;sa`ukI$p&$J^Ny`ZxFRxj!EFZ>IOXnp^(F3s(XY6zCb-PBUp&m=9Th8jLSL zqDlY#=z2802P9)Sn%)d16Byo(p$~Wc@pN=KyY7$SZZ^KVoeYrs3FlQCl9T;aaLlF( zyFBKWiNsVbevi#)5M2_(f?;!N9&v2a*pZd3emrN6*hFE2xc+lpQMO+XOo`3WdU<$fG%x$A_gB)QzedlW)zV4{y%#kjY1^C`>G>q4iMAG2k#!O1nOPuZ$(#PkrdV zK0oiCod422_hB~aQ?h5C_p^{ulE)lgVIQP8=8IQbGGRAmnm;XB^0+Ca@Fek`l!$Sp zZ9tMBpzYSGenN+yZSSjh;NW?F7kq%roZ*v1dvp(4nUfTVX})+;2vNcW^VizV3P6ftW+fnZGM!ZSSDMQmK>{ z4b<&M+`vs&1&AaSeB%Q~?-ene;ZHj;NZg1)euI=HiHcfA{LR(8j@oWla0}gU!cBQ< zxOG}Sbf3FE?Dcd;YadrWOYjsjY(#0H08UMGP%;=q*{Zc&l`63falsg~;T^`cRyv3h&SakLn)E9F`?1S#dIoR>a0|>j0;?z*(<4B3Qe}aNLw6Tvq*n6C0&jtIDmx z9bO1++8Rw5G(`g(qs!azcy>1(d}u&Aeg|)=b#ihMt}G8|_z??U^HwEwjKk{Vyj$;; zlGEeke-&}Lpu4Vgh)k_BZ^KvW!lHt?t977dUa#;IIk+X4!EOTu802^ z_n=W`jD*g%Jr^OX)tx?Swrm}iI*RsotC-PT8u362p_r<64Y(P?t?SW;VBG&a`NKKh zARiHzHFcD14#|u64+TX(7Q7sIoNZ6RPQx$^JI*%aHIN}$;YLK1}LLONZE7fRV<(evDS#wKLy;B0R zF0jXROwue*D}_GPz;|Nk*ip{2O#J&bSMHLpX=94eh0xkL2hP{DpFhbe?nfn?-zSH^ zz2u9jH~#`oUF*UiC#T08>nyf)syAmJWv;gdvhu>|s@N}(pdj&F!w<_0p$>ZX=ONFWaZQWc5yarNEn%J$HW3OlFtOS^#e|5qh&f zc$}S6O;5r=6g+o-#RC)4nu^>jBn=jAQlTjy>ZxgDfhM#i-R(hz|L)t5N>QTG1Iu>$ z-puUVDY;1Vmu|?x$}RFv4Dlip<dJxh$D2B!CJ>?7Lr`a4q?`3qMcyFsPl zdQ@L&M*b7Z|NmBG2F2CbDs-7joOEE&^EtTr9(HH(#dV{L^f<{Oq4+BHHfa1X@v% z=Y<$-TF2Uz(lM9!gUxlbmK9X;_eB;%=RVV6nDgznh?vSAl2C&P{72ujpCwGdeHFpj z_p%h&nGAf-lZoC*0n}e=875K|l99&gVmY7A3G5(p>_0c?q6QuBfqPoNAa*zetpATY z+HmQ(m6q|YWKkiM23uE#);<%hgQx?i`Uqzxv;l`{u9+Ra-la#cyEIe}J*W#oWDf>| zfsKKO+YCSLImy6bIM!5^=2Ejgrh<4wi<FfeZ5>ruMR%ND42eKeMfU^lSa0>cRBKEnVRPECDD77%7v^rCJ8QVkA%Xs2cr-l;f!qP~|W z`C+D2kKHsGE4TP~hm+brFWZE5{U)b+>T9l&TI}@t@!YBV&EOlMTE3I1dM*lka;CGI z_`banl4ev9p8A_NbvP2Qk=EY}CW}Vg1YK6kZtmInI=yJ>?H`xy{zi4F|Jb(MPQ6;|cwmU=J6A(P(lSw83{!InO84&&iqhL8how zmX?P5DrqJ(Pi?V9P7t}{tR1+7Qa)I7nTdQ)@7rVqcE86N_q6E&ZTbwYpAC!Wrw`nq-orlLU zyxS|gBV21NYm=@XN{dB4?X#+YIZladSS!rL zGhi0xTexOguzA6uv+00wm7-nXV3~xaDl$icmVz^!c1P+C?l`LjH~orJma92(VprY_ zX{j}S7h9+@Gfd?;gn>?F=)_POAs1D+u}o%6XRy%f#u;;#TBYkyDs@Qk{H0oTk;1W@ zO<+8k!PVsunA`&2;Lb5dCEwI3i9zDtse%an4qBOlTla3E(qSkyfsc*1wpWf_67Tu|4oYf3 ztCr@Zvh`~lFAP8M9&mWz20a^HtLv)wwc(8X#T}uMc=Vln-oedMpwQtFUgz}<0KMqZ zUxS;`KZ|evO{)laoHH~qFf%bxNXabHOJce; zbsMT7H?aVy*hi!L3(JX@78&b8wyb<opiu>CM1WC^RIDyGmp;R#L?&Y=4$#Sp3SfP10mCV#W-}CD2L0g?^h~O zA_XB8enQ2W$Q3VxbeWXUH=6-e;wO(4$N{87-a5M(wFwpDKpIclWkM5u|fy0wS%0Q?@ZBX5l zE}@!#`(0gtr5la?weNq&21y6#>s9fEKxDx#5LYsAs0o(Ej zDhfiph~hAPeFMXa7j;__IG|Ncnxh=E!MXWFgy7AXJp)j21$ULgxaD=l_o!&NRIp&V zfVan7F&BIRr(lPsL`II_WICO?9&iLvt>Cal?uoXTdgu-@16oLVsN`%z0Znqz7(=32RQw=E-v7HCQq>vX?|@l7H{auCIwfMMB1&Ju`du%w?4?LG&2z zJqBl6cXzQlQwqZmmLySpu^A|el5&>^k1)EQ+ap*r?(Ez(bJE~1Q=j6%)09`GRl^kP zJ*BmHSS-yO$C{1jkiMinMQH^-sO&>YexPW_D=c_CAMkB;y`5ro$j zEHOUva)<$9t_tf@z@9%_iBA|mf3j@?$ZV3a+=sgfubbpaC>d^=vV^ND>H+OO%vRH> z2AvM5C<+YVO4IU`2}nPOyuC>X8W1CLC`tymH?7&7F{Sin37J?+$F%Lao#hDwoew;h zyC9?WGLwiW+0&=L-4p;xf#mLk2ycxXDZ7IoEAs<`U&d&BgaE}7ns&s}tvz2l_qMe( zHS{U-@YaW0V`4hCX^g}&y0b84(Bw~`!|wCh^da{?Nvoq&%i_Sj#ukckW86A9)nhE1 zJ!!SjnmQnJrM0p3+Z>&k=(7B%O=Qu*B~*I9TN@UY+C+!!<-AtK*|93XHdP?J0$g@; zm+d~~@Q2}l$b((T&@O_AhKKIu$;B#5ahNcdvvClz8+W%0qBRzzE(%mHyH|%R@e^&5 zWuaXJ!L}&_9xG)$OiuBqWc;Zo4pPo~nhqQLs%U$ScKfbnQ$UUmRm=@dE#=MEaf~!A z!(ag4zG}UC2cs5uSWR=Egi&*rdO5lDY&7Zl*wSg@*0rHnhYmgr7JSvgOmVxY7isiGp0m_;D#Svp~}dYpeO!|@TbSIVn8kn#bafZ zEsy%iuWDlv;XK3eTD9%u;EFme0bIr+J&9( zd${6RHX&@E(F@TWe%FXzRPxu;LI42pIF>-b3ZMKw+QZ?Lkw01R~%Bte9w?5LWoLJExkr)U}h+kMf##bgVpbt2)icAf`_s=^J`9 zNv%RCA`TJ?L_&}Yvr;|DYnkGrRSwlcx#+T2_Ufk7Lxh>U(;+r&D#g#z;;%bK zM<#QA*St{?{ymloDOxOhMAEq2nU);=Zwwz~!o>E%aCW+9Wu1o=UK5zhyAzC#_qA%+ znLGG%+BbzbO9H@QvpD)hC=NI!h1gd)%MCX-ab2QU6{$ zD+0lYD)#k)nVy+8G?A}y;p3i zt2lx|_uZWe!#h-lm={|qPs$W?2uS<}zAjtduU}wRdqHE_QIeAHe?~f*)azi}3HSsy z*tw0LS3@FvS+M{Vs?cw>Iz&l>f*OH#tHj;-D<$ZJ^JZqn)`=^p7A@tZMiAA=0Y(XQ z!RI6>=t1?GJdhJ%A<8W`_(@e618GF-()cT`jUdHRWj2*mLeDt$5lNhjP5F*Bo3PC3eJvL%1`Eswdvw` zE$_q9ADc&mxpi7nKL>bw0oXXIR)oP}MGGNRnErY9`-@p&sWX9_a&B+YDk+^NM_hB4 zRWm3xs0uB z0~Jb)$=k+m!wIM%r)BnuEowzal-1}!@#^_bBmhu%a`rShDSnrzBp=UOOcoF4WsV)JPm1e&Q&ZFaY5VM} zbc7+OH{#WRUz155kA21kP3}sOxHyZev)0QU7K#+0Zh&M_69U114Zc8C=uGG%_p#7B zCpJfoVe;@*&bu+sOdop-E{XH7xl`v#{pJk|64KZ#ZURf78m;)(B?GO594vYJwTm>5 z%G8m@cWq8iU8a!~dD-I)<#zw4*r*qnnc~1yn}g+@tH^pvLeRK{wWTummFTpJTnH-kpwYAxvZa%+tT3q$-SSJ|EYF7fK8{|Yv$!1Nh=d68q! zRs+%#RHvN*-!!0vUD-Aj>18K*2s)kD@p6LHDD4(BvQR znyX3p5afpQm%}&9DzxpB_vF3)4wmaL8MJ0=L5bE3$zj_~R(PD7#rue7!UO{o10YZ+ zN-fSWElN%;X4u8t%6aNbu8^qv0@3hWih)&YUIwMV%X;d){kC}7?+De66K*ppG;WzZ z-`nt^K$XQD&ys!TzU59r+sg=B!^E158Z>Ak{-fwP6ugMxLIhk;cWnz{xzVFA3%;l~(yQgw}yqk1gY&+k5<5qs-&4#R*i~uxsZZ6KJ)C%0P~}$R%5K!f;t#g$1xdO#QscpL#UA?oroxcbOIKKeXRj2 zg_AGGfp|QQ7pVLB69k_qh}Awi%PR(TKpqmlt+69HE;?%aVN2jIMnpJWVN z#i1N85wG;{Z7V#dPrT=W{9A>y>gV7Vt?-643^>o$h~B<O`vN-i+#&0%Rfxz=w41 zbHN;Ex17C)>&VYSmCR5gxC|wS>h?Q# zN2_v8tkWIVv2#vOSY?gpL*lD$td7{5|BPk`0;@~G1>J^v)6UJ%XXvHe!~s}<+eJ~A(?D?;f##h!;$AU zf7JozewHpC(hT-&eza$+qk9IczqJI}?;ovS{@8k02R27)bj0@8_I5;t5yi7W9?P7i z@!+PvZA^xHcCv^|a|~FT-!^)?%^&?})4bRKTH?63?Lni{esy8)N19Zw9@lz+y!x)^ zUbp+hVQiWmn1r_>7Jz*hK=WZ*MX9G~;xAy+0LWQm_nEUjNU{K*)tlC7vn zYIOUavtc>&Wo#qQh*jT6EpJwxpKwz5n{2J^YOl3yM>`>d8|_pB zEu$A_m2o2G&}?@Q4w+E-UySoZR+&8lzJVy%$cYnBxc*H7Uqi}ERokcvac!;Ef9_dQ z`)|B8FT3m7w_4g~lJ)J zVr-J0wub@0NIMln28SIm4N;-$)dMmljDtCSFQ{o}l7P z=^O%p{<69smKrs4?P3V)M2*0&AqyZ3hK7{KtPnX-2kwwl(XNtDRAAWQUfkdicbq z2KtuZJ`dYt{vwmpcp0Z-pMz}4>ZIl`F-aG~%Y{CZg!@~Ca5}xepW%fqos#>8ZF4fs z)uQcDC;`{9*<%+iiZx+N$LyVj?Pa$Y6KFgnLRGV6F<3_QMQwAJBTx~uz|fXzCSSX; zyTYlp$~(!7rEoO4rw7;djFKZvC_Da$MDCyxCDUePlflX!v3<#^w)xPMQZp&o7uRhD zo%QjXmHQ8h3XL!UM*EdKrPI@Y18d6`$LP%;-u#VCT#d^ujLF|4&$CC3is3Jw1LA3- z33!|{G%zqTF;Pg*ECC|D%)FG;3I=wiaM>gN1*T=UKHPCOXAOV$@`icKPFJ59%T@9g zKUh7{5TXa7SY!!z;_p|2|NpM33rx&AzFf_(V`0_=#VwD5t~giv23#^R00M>L#N2|M zRNefPB!(!yHIBE0Q=@8r`Mb7V3}Tr*?}v5FZpT9t9tX{8&8goH0Pp=iIlt&Zc$|!# z2|Sct7r>vfZ`qfST`7z`X-5eam4u=gV=$PdS!`LN6onFrNFtS_XisTh2&t%0NhwQF zDG5pMjBU()=Xu8ay}zI8{raDK&pqedbGP#>w|80wK@blF@gK2EskdkR8XErzL4P4s zM#Vb_ia8FU*8PAWnRvz@ng(WX-K_D#j<`{1>19DV-_yhz2Wv>&zzio}DNBYMxne z`R%1!_pV0Ssx)R2KiWqxI|T_D5HR>40){;D_pxIfEQ|Aa4$#kv^mXSdj%*1%T%O&1 zddN;5cQ3Ml}GrNOr613SkaOX`nU;gg}d?2xx>O2y}e*F81E@*%-xYu0YG zceI7;S0)q>v`6Y~iIGgC^S7lXUr~+JE|0IP&Y!;k%~(#t(g`>sL-%+R(eVGH0LxDR z`0fqejeG*0Hx;-1Xg=UQL0@8~pW`v3XkqXNU-!_JkW_szcZ^U4*0ffsStysSPQ zFV(x7ME~iUo}XV5 z1IEtwq`QsVJ<*fcU)FYY=QIi^#PvyWX4>dEl8f_L>_KlP>#{S;Qc-7H10T62es z9J49N+0QPA2lKUSG4-jE_)*L|-@xKMcE@|QmhIspXYLf_qyYW-cw1er*z>jG`eLQT zUnSkIzD4l;Im1Pc`4r?F0OWk|6RFdS^Gi(KEqpOz-pj{lu5YM|HQ4(B)0yLRK!} z`dNn__O4UFL;XDWVkh+Pivs&|II)t8>1$hCMjG+;!GdUd+Rb3PY2Q}LS&b~*g% zB}K^>wpN#{UlFQ`ebBXPYtz-6W?bY<#cwhJIo~$?JR{S3*ZR!;>&m-LD6bm+Irckn zkuw#)Im|A{w4Ie;8ZdTlSg&)J9PjoGgIOGJru*R$TLT;xo} zo{s`@ayw?vpyXaV)G1b`e^}pYeZN=uwqP!Dree>z>~dz5VGeHH{AkatCx`DlmHWhL zZ}<}?6M<-FCWv-+42b_LqJOP;wCute13HF}`Z2w6$?_AgI}!U~Iwd>HW0xbicU5`o zH0-FNw?0%<8@|jHcKikVYRy^k-XDW79z%FN+QFPCXr_Z1vtfo+J)#a@T zUANpik8_bT6+1ft#LWzW!+QDyoj>*%<}k)6L@R&q%w9SdIa7(7C&9R8h!>ErFo{mw zWgC_;H@W4l!q*kiT;xn8-#7)>frR+dUwc;ktk%nj&Nh+%xN}vJmO=p+ITllpQ^+pI z{K->`v}?0$e!QI)anYx)NRhvx%DWrUKTQ$+^E8leiq(HywO9C+LXb>kEMapif4RSA zhc{wB%%LRG2Y*bBOeox_=P zT;xo}KTFu&TCa~bV{-!E%;sr>%B;TfJ)n>}?z zO?&$@>Ji7^9C7?_u=BO9%(Sju|NNt=A5vrIucvzx@H85p=(iR_!}^bGFv9R}0^_j3vVLLc*CRm| zIyd@^@ARrUKW%+?15#$^W2jg>-iL%Wz>Bb!?Df__rDS?n(YvQD)8GVx&7OeDjH$zxaN(<&@k%P52+5 zjt}xdGdkddBO8!$lpuKi9U%YK2ryUDFyA&@f7WEJ{RWajZ2SAyA0Z`nJ{A)cM55EE z2BFj-F7|nsz5P6t*LO^77O5$|T}zg=jq<-*d@{Lc3#flAhK8o$Lh<8mN8sOM=ku5G z4IBz>Q2A!v`F_s%U*}6UD2WA2{EtuYK?mWfv?=iKv+L)YJmy|7e}shILCISrWxX%f z194f=E5LnqrrF^A5bgc}J6HOtrP%d_Go(dRb#_wxlH1F#hSLVzAr*G658l@o?MtE% zFtmx#0KRK3Z@x@-TtC!(9Gc02?}sDeC>RN~DxlHRoD-ZXS5vw;*j z@<+@chWi*;&$NEZsA;mP6+O5>lHj*1*xgkAL$y5USGZstCCmpCHifuf1?&Tm>SV$^ zU*A`6oxkag_1T-TgXOvN>cP0+i(`!F)Z$JxyI-N^{)-IlQ_uIj9Ax`R%<)OrKj`wZ z3!q>5;zOtEw>9kT*ZizU2-@YmO}}g2G_z8N<{wTzmUag~z5C&5XpE1~NXuckPuRIK z&G$XlcWLuc)~C5FI9g`;b4HzP@p;f+N4Nw;f2{@9kI>#gmxATOZ{56XkDaLLkxAZL z(!LF}^ARqQNMigJ$HmT{vh!7ghcBr~udFyF(6-sCPiM7Tv(NKPHBjFpd@?y`vcbUc zpRw~Ll^>mG?cx`W_}Ud#?|1Gi%` zDEXQuvKy`zRBhifbT<(6(+Pesj$53m1MJ1(QHJVJ<5ln7*FPV5b8dQgR()c~7x4U) z$pCpkhQIg5Q*l^UxP;@^v-1^?{>i7kbfOqz?)fiP?o1Rab2W0U=A{3TxtzQHUjT7Z z2gCc)u=P#eqR>)8`E~a^;}aLMesgR;1w)(^hT-@x+4*t_%DzRkMLvz&k1ya!a(!%w z<8KVL;mD^GeS&aY`LEddq5^eW_V5kQE;)F~a?^*FlAHw>?QUT?**|kGXP(t^vHu3Z zzpC|O)pS+JgOZ6K!el&O@a$ZlyQYzoeKOKNY#^F>N{(osjX)mwnAcjXdef7bx1!jl z<*$xh>R6y+uM5qB<5O_p#0w**2^fc7?*=>btGTZtbcqFKE~Neydg2$tA#E5rjHC*U zC;H$*xsJzcb~#G9n@(hlOP`>VUjELOA`9hH``inDaU72^Ib8bj2FPnAcSM)$4cmI^ zn%&z--mIdPiwv9}KY}zk@+p)sG#QT#M2gdIf%(gr_H4CdbVV}Rz&7T*!PRb$7CSK# zCwm>`bJb5XU{7cL#7gvnZqNPrr&dW)zArF5uEvq0zhUt-5-Er)AGk-u9~fD!T##rH zRwesHd%?=@qK|Xp1T#6s3v3V$L*yPWTG;v1uh06cETxdKLOEq^kCmUs=@k;H1v5GG zNyI6{BjBEmi1%=po297FLyvvwKc4Ndl(+Fnh|S?Rz9a%;?S-aMa5$v#1@6u0V#H@& z-=)L%^<$plC$nt6*u}D+v&%T@e}vCf|E=u&S*o+&?~+VA=AZqV58YS#D&AY-?++Qy zd{%Cb!2byBdrYIBYMN0faQ0($K&05xo(%7+EklNo7AHQPNJEpnnYW6l+{fV)FmINk zPr2<|^RoM@bz!VkjJ*3&z9kjgz&w3KPB0Z0%AA$~g~7;a1J(o3l~Z>_cMD4<&e$_e zwhwbB?C!-M`e42|CTH^W565q3=NlfpTUR+vN60aQVfa)Wg^~Co z^E-g?KE3Mr6%VOd4H0&!TY?X@cusSYEJkx0ZyyYfKq7J-?@nMnwln%|?y9q9VdCe_ zoORxwT+wk$I6{e2JoUj*u@t;FxB2Ze5HEImB&r-dl_l3{9z(JVh>@*&7`pEor}=Gk z&BvHPsfhF27oh#OW*wNe23w=Cv?u(0Qqt4cpVRC#Y+?D6<{TJ)7du}zC2`-}D<{3{ z(Ti;U9d-OV;{tlV!evh5JHnrc7O?zoAa4(Ou%v85q=>few7B(+F4-ODzw9zq2G>jD z{3)!Lz5?fekFU`_NV%hWqD3l%FQ=6K=>1ryf#($Od@)oSdeqa9;@vlPezEY~-W{i& zpKW-9iZ-Tvc=50I=JWe&Vfm9h42J(5$iG}{mnY>Je7&`9*lo_%$RBUE&M7R7;xxXa zYd$h&Y&wSH_W<@OStq~RBmQ+@4$txFLGzOp@6WuUzKYX)Gs5Q{=YFvBjpVi!HeG7F zeZlZRq;~UmafK^N0#{dYil+?Ir{O67OM~I$`~>>ZG($U#;QQk2*{<4WP7kx+mMO0P z8^lo#frcjFD1JCJf$GOyPA_1u<&?;sZB%E4vQvibMgQFKHhnLj^n&}lBXUR-G!DZU z5=Kfn1-tzPtQ)dX({h$+8uuzG?ALl{5QpL4afwn3BZrZ#0-HGSa{7St3ZwK*v0-;g zBm4gJ8?L!gTt3s%{^Sdea;S{-`2W)#oSff4oI3g9qz^?gV2j@kqPLaG{&`XNE)o}T z@^hw~De(J&anU93`g(GuMTxnL1m?B5-dXj-0$Xf3t^fV7i2gAEKbN(6I>eV^LKYt9>f6RW6_;B~ug4Sy z)g0lZ7k^yPRP-_owEs@~qjWjXw<0f>H`i{yAOG;x_Pl34oZ_oLjYggv1Y!990KLne z{kfy1)VkbjVTiX_F-1%gO}>AH)BHKYC)26^h<1a5fc86IXlOG1>O&PwiVPyfx5JT}k0cG|ZOd1mLE-=EA3=d^!>Co+=&Z!Y;SiWl&!-CJqd!ga#Ek3TdW zice47_}rUEyO5LpF!|i=2gL{617E7yq*1WO+hduve41N=bkyA)bx)6S${+DWDh(5Y z^G41eQT)Jq?E-(*8J9EN0nek&hq3*?%-hq#)*R*Jw?QO71iwNF0PAo|FTJGA4jsRJ zvacrlYDy-e4DIYqIgM)&iOQU0=;MY1!xsencG1zem!h7RU!GNVNHoBmkeP8)!$y>o zUV^BTvtC%f5OAJbSk!*&=)jl5i(e~hrzW**og=3n7S74;8GH(3Wk5sDOHsl=-c`Pu z;@wjd`#34*#7%6HR%udJ**ptQcFEvR%6eh>BH(>K_UlJGnhywZ0DvwIX2aC@cx&DgCoWJAcM(6q7MO~cq!{k%RL3reKA4&|E z7f&liRrUW&jVXC_zG>a!!C9Z5-0|q+WIv<1mN$lqL$sf1fM0dbutp3mBOgyD+=eue)hl;|$}hDQrI^fpG|VU26#Rbo= z@C=?M$Fco^Gz|Ck07@1ZXY4t}@5EOY?k2vNTalFo@&@ZduAb17;FQ-Af)U469*94Y#E>GH_3Kanmbq+kQV_K@vXmV3 zzxQ2CE|GbKfr1O>5`PqcbFG-fxvT2Qvay@nrI)=jcDr1%z3akSPU{M0#xV7D1!_8= zA9c^Pxu3G^hwrpT;CgPovA8*p@BSxFel{Y9g7aZaWEdjXeMgicpsyVT+75Gjk4j!S z=&-Lq!^d~YV)@8boa}T=jxX}LD@qCIhg;1ufehM>hcb{a+SrD~y*Hcw{*aW*FAYepY2~$75k;KFePlt&TE@WfX8`<1v9Sdmdc=hA z2dHoSm9a0{(&WsSa*C^D94>HjH(>ZG0AKLZkD#wIvoxnWyEe|${FAE1(_Hz#_kAOL z3Y~}>84aAz6!fGDjCZ(mPt%2@&K8xOPV@y2dE)8UR6GMY#f=d;+~bBCu+RUF9_qd1 zb>WA%53~%GGL)<4Y>mYxamq`{^q`vwz%m7)$rZwYd=eVXS69o63EZRjMOu}G zir%(%rC!ed^!X>0Re#e(zH{<73J&ALecutK1?)?8ZM;*WapJz@d*R3*Dg;~eOj>N89=;&fhi2$xbOaEDj%xo3wI5lrt09 z-xO;+VE*30$)eKS$Z}4(-M5Eljy%=o+z;RJB?1zE7BGM6&-}OVNL9;gC%^R;J=QrX zcz(U?9?pD5ni|NJufxt4AH1F!BmRh#`ftXYji+mV9eB80k*vg-&mQq$__Klg4?`Ab zywbKkyk9l6=PbFp&prY${5in-Rr*u;rS(fN{-LyD^E!UB^JjA0UR81O z0|uWo`A`amuM6ZCR}@V>-=5VY2fd1$xhIjQV55hViyvn@+DgY!ryMWzfc?fD2|qP1 z%4+Ct@Klv3`6t%aduRJ!0nU12{*SAk^nr8h6#-?R?gtz^6gkanj8tayP9XBUW&qslub89J zWHL=}=Q{_vE*+b;M$6QhIj#Zk+G77SwiU zbL}k7?PtuulV$)IzBxNz0aN$GZP(Gw%auRNUnFcd`r^}d zR#z6)pd>Wm~HSR0|#@B@|bo(P(|Aoi{&7tl2r+lrHx2=1?aeQeMJekUHVC4OY#lXB` zG56coKSnNR@U=YtNA6i1#9DTKtK=9T=-vd94?T!WTwcP?cQgNCB)uu7tmvrBt(~pT z3$a5Xr#f^v?Y~lkiAZ+86tEk*hD0;(G5uGr!AE20j-iKjH=2F_U;U5~ZWzIv6oki4 z?Hmzh$u38&hA-fPvtE&<-LPQAiLFW4fts9oDV*9rzWV{gwF35S>I)h-Bt83FzO}=G z$4}#x;Des7dw5QM#XJ+6yz>FWw+7~`z(OD1s>CbmufM021Wdbq(MXn(F~rI4nOj2K z@86)70e0z;x%t{~abHs34|Katqu~ByHqyziNxiwS~7w=Lx5Mi822Fc0gd{*s#knFjYAcbCTz|p8#KY+vhnKAA5iKl;*|B zj_70`=4F52)*-B%6+nI!mOlSC|G9HTq*}4(O3(4;Iz`rf1WtZDCTGH0VfePdx?W`N z^KD|$;;X_{gx1LlyS1wom9*V}X2bGF?-HR|JL52N?0|9ax&8`6-z~IC%=d4y=uz)Q zXV%`-=jAvqr+OB1^6Ov>1&O-~Xm?!&M&9Jv3)G9KE6}u- zu0;#YV??)eYBxjsc;7It?OqM&U$SgRWbX~%4_9Xo)n}*u+~|6js`-wS9gXoPHf3S> z4nW)(Ha}OK6FU3695}T<1m}%rJ+T?qvx;%-f8*bsk&m~(qeZ1hB;zO12aWaz`Aw} zejt~8XcG|c&-FjkJatX%WR<;oaAMxl#ymRh-#ZR@`e=^JJ&$k)_J1-9@fZHw`&OC# zalegwYQ?Q<(wUA19NtMVx3Q>rh8u*TgD_!S-xr`ffPEByUtvD~AROr_6na_*EqZv9 zV)ArT4sl}K)zBu$abhz&-&w-$na#@mwQ1`=wN?(IF1)^nFW9HX!9M@z$}s#b?0kni zSu5ArbV7we4$bFfWBfyYW$3xY?agzjkv@I>?6C&O6hV$Jg+yTJj)tQU8D=)cd#5NL zz~4XEJ*4~BS?xvp3jOr%y+Y*avJtrf8NtXMd9OVpcr1-&hB3tX3J2VCEHPQQZpqV@ zCwpn>lwS$?bioDuqKBZloaJFj%p92!<|%YC4d;XQ4kCF^zJrI*PhVgi3AIn#W87Y{ zC3%Sauz+NX)fU+7dIHktESI@MIi}I6o}c&u>y5jFC0Dzl_aQk$9Yr5dbrFgG1iR)y z#+>9)abyg0z9jlF7K3EQN_kZBSP+Df=MU^-;w(*QyM$KWo=qG4NB%1*iaFeGA`6*t zmPezL(W85gBa4s`Ei>=$O~KFc!2VhlJ~AafPW-U{TAL>Ky3pk%b3*B8NRN};NhX8F zg<=Tgpef8x0l7{|H}#(Ie~y*Toqnl zAc{8?JcJLaP+BdDQG4<3;(nNZQJF(GdOw9q_h!E)0VgjAybtzgT4X`seock`p5FQ! zanlKb-`}hT=Uu$91-E_>fH+(~x7Ttv@mXxMaTZ~zXl#1vvF;B?z<57$w=XD&S&4yp z-pN=IjYnfxIYdCtkjC6oU)9#QoO+bGEX=+v_>~jJ=QcPmj>}=JT^OQ9g~0Ghz`E;~ zB`!ZN+~OuxM(^m_92Kl{;L^9>!2KEmhDgRRM#0!%p2>L42N*sX*oRiNdqRuoZF+Iw zr8U*f<%=9K^<}Nm|M(+g%>FV9hQAe9cdduQgijf^Q)hk*at=EJy$Q8nU^@WnXY4N3 z6yCj~C_wv{NeB146@SR;vfN5gtaTYCTEq^`1jl*IMrq8l34VCoRPs+MaGr7ej*7kO zR)_OExzg%6+Vifptj*ig0fi@jVcV2CUzE2)>V2-%<6|Oi;)4n4n9 zB?m*sqnX85up|Eg?MESnFoNV1`WFuPO?6bWs?Vo-@rvKpozN?t#iVq3{tsaO#V*%- zwqnEjOu=BG>txM1W(0rO?kkwc#gn>%y9MfnQquU=RC&j`An522CdaoSCR z?O!x7UaL=JSEM_*ZN8|iD0u2g#MP&T>r{Ur>yiEC35=ZWfE=SoJL|fuX3o31>d)p2 zO&bQ!*<`NUfGo$K?H~(AP7IL$+jed^v_D@XuC)Hlp7z->y?slCW?CTY&z~_$%+d0r zV94C+-=JcFeUQrH@>`qf4ez5Y-j|7+r(OJ~A>o>dERV5*8rel+--3scw*!!O{anP| z)`LCsGmHj4S39lP5qw_$&n`$8SswF61~m{jmHn!nKt6)aUTS50)y+rfOoNK5SBl;` z|2TR#^0-ZD9U2GNeaYJd%VlTx^3BRxkSDn>y(-m7VY&)(++ak-K(6<_cLDly;k_60&1!N^Gf z=Kt4%3pLAkl)c_md^}1(`FxJui-8T(!Sw^X9QK=AFmizJPYCm85^~orsLgN9?UryY zT=(?PowX8I!F4q#Cm2s<&XysVpumaQ5=I{IJqo#D`svN~T8{VpT~Ag#|G6JRo%6WS z46auId355)Yd;Lphx>X3_)Z0MaSb-tA+n_XQs@KT)w5m74xaqxIv;tw*sh**WkT^MKVd-Xd;?`eL`vXlM z>wM*JwLYkUtUu<7KV#uH`7#!~Jm7m3(52S51JXOCGhP~p`|HlBI_I6dtH%Z0k6@R_ zTv)Q(27)}`yA{x0@AR%>72GN1<#F zh#F`l78N!Pz>nLA9Df|0!pv~6Q#f}AzGJ~l%C6sQw=p^^D%S8`gR1BQmzP*&9%v4t zJTiquBVos0e!$2{W0#}R82FBN)q-ChN%3l5Q`WzznXc_CZ~%V(qF}ILQ`+AIzGoqL z#9wvTT2UfzUvgkY&li`hp&qa9RgeLkoQYd%XfmEW^3fbFeg=HkLP&hW0qi+DPnjb@ zrj4;T8_jf&ONp-q-?>kc=g(Y4gm51x;JX%*>Dm=mP)V5R2Q8x&j;PPOiJOgv4#STV z!#N>0~0^hGd9Wl)^O34Xo3{&#BCz?8cQ~aMT zN7Db-ZYqv~X3P(COwdG$Q5Zh^_bYhPGN7431rd*Imh|Sn=|tfLlRJqA|5yKTG9PhX z$f#%q^1HiL5%rfWbO!y^J66d|cSWP*E|f+?61MivXcrr&_4aEV(Y7{@@I0Vyjn{nWlqL5dL3_vb&Q_~eGynbpm95aEpQD`HzLl^|?JP)$^(82n_5gKngs9Fj*7tNygh}+rs`%ags`@V+7w7~DIN4Y& zcd&ur+p`2>enNs3_tmczEHabNRQ7#e=b?AYccGn`C}af*jaR;9{QZo_A4WK1KSw$D zf%mq;iPK!9SF{wmHJ+TkT)1?d&(FiBAA$n4KfclC2 zh1I2!iD}Ec=00uOt3nd$-*`DTEgurZ1mQ7M1MEnDu)7QONhpZAkbUYW@WVwS@l`TM@pp-Df-I6!?EMKu|obj43yW@Y!wFeiqDwu@XK ztyG4lja{2z-u^PcBH1OtQ<1Kny>@x4D*>f*Ps5{hrrENWbcHu8UO1kN%meDns7~)U zyYx$K^{=`si#6Ugrer++wotL3q4%+CJyZdYKUa&oI{jA` zBtFjbWca75a|9DbQeqg^(Ye3s46dPSKthLjogp{ICcdpbieNQO{l8 zy~0{`GQ#t|4&Zz#e5bIEgfWgk0tcvfBf9%)EO|g^xv=}C^D)mSdzQ@4P!SlX+>%kO1?94Y6N9-5S)q&zp0O?#15J zC)+*C`Ly(lKuMU#_Aw4pzj}fBI-&H_QH}I#rbS!v`Qk&HRm>#zWqUCCHF~TG-!Gu< z4DXzyV!HZjMTdgLe0uXTYNKBoJn+lwZO@C>%^*UW~bCwSx4SCRcEqk_F| z49a?wrhM+Lh!+dq7@LuN^RI;lsQB+Kh9oAqBUM+i@I0VijL1FB<(sO8oWg#loCz3= zbJq}Xd|)#dlA7Rgi#tGFn7{PBfx@Mt`;OG)UeR1*T;X+n`+S@4toDsoB}Hf-PzPr5 zveLZb@W6#~VogcBO1tOkI-GrD`5BU&;Bm7Tp#F;ThssDg{ao+Pv_Y~vJ+fZbx|xL7pU)oQX1yF8B%DhFEz+-cj!Te;fY79lD9xg z?A%FJMY*)Q5(4Hgp{-wv2KFy(6pbv%w(YqcljS+{fdw?3jnAqk3ajTzpstI>4XYUs zWFESoa@JIOfqr@R^qEMFMMoy-dAxckxAp?{TqIlUZq4Zx*&^`QZLisV|Mgq=ifYvZ zS@t?w6%*cGD}nkg^T{o{j*D8wh#4LKrI~cv(IPJL?9LaHdCV%92t1%(i@0+5VWX@T z=fx+VM}&4jM#qPwewxf1IYWi#0rgl!uclnGqlIQB z&%eIsV?mWK)vLB&|1hM$;!Un*iJ(s*cCJ=Um*wgmSvc$Fi|;-1t^Y0(`E&EF0n3gi zswQ%?BViz}L}vAfUWhVu>C%%X5~!swA zgOUgH)x25uKe-AbqWuH)R7}3nyo#cq=sE^Oq1G&qSCkdkd58L{HZXrV6zKLF~aXnudkQx^XBrJTJM=2$}bk?xm8T8q+I{>5H(5P>Vr&fO5Q zeC_=A+4PTvNIakpijw=_U8tpGhnM%Jp_r06GSZ1zyL)#*V&gnNESK>C>Ymt#VWsB0 z{VOpnFrXNZ)~vms*0^EmT2}i;&LWZ82h=+evRojbz5C?n8dP`esuhLO4t2|F47^x& zG^x59ayx-KCkD=C-=7}7|9PICrCeR6i-^oZOXUsKtbA|0Y8hOXs}p>v-Y+^;HpB^q$4JeQrk#F&%0qi&*h_ zqWTuM_zcu55#DoGd8cZ`mL#1MZNzADC?VwZiuIRR@s3q>i%Yx%>W4_BK6mvy_WO&- zUYi@L-GPS-H@EDJp3c(ec(pB9eFF7D*6kgjU3-_FNPF-S?RGvlEw!!aqRFKBX`;Fo zxBdh5K@@Yh{=9INrn=Vip;OzV)$~J#iW+KLS^Z~K)#B2Bpe_hMk7;bFg>Gcki0;>g1M5~2zW-eQ^WLoNp5{d$cXDP8!v*UT zeB0+<*2~kP-YV37F1!26J7t3hc~?L#iB91*PXqM`4!AA*P<|1I(RZlYnzceeOWkrstMjhT z#^FOOd!4Ap#LZrT`T{L~(8XQyMt6O$pR?|;ll;w}^Wy$ORn|Ph_689tt^#!hcx=qH z3B6ru-qglk1Co$k2|7;l=4X~4u&N<(@dKc)fFMn>DyiQl`o)j3tTuxhiPW7RW-P%@ zYVYLgK1l5~0rLO2w8)OynTgbfe4TF#RL<5bl&xQ?%o_jEYCZ_#57ZBsR(7Y`ztN(P zy6jx>(jcHBwy%seM4b00kk+iDo0ic*>rhh))k5W-M~@JNK}UrB7D1 z8!q|;>I7JZiJ7&AD(?5`2+z$vCy|?HhBfWNv(^)1)nVY*6F^;n}=XSP4mubliZdQRa>u_K01uvyMD4hN2-Xx>l1j#uW0@?*0v<^so?L$oBs{Eh~x~L z*6Cbh#W@OrOPmAFc^28zpOqYTGDNQM0EH5P?=f(_%@V3`hN6d zJ!^e4x%vfSer5^ydt~u5FTNfbdTFuVp@Gs{GrB#NMaQtUH-wejBXEKD`GUJ{pO-tOyBC>ShiC52WvkL zc+C&*U%>nN)sV%P_0?s1hjNE%*S;(hrD+eNm8)2KWqZAkq*vfwy@0PvZs~>W-upxA zUf=rRqAjrDhIy_9%MK>J)QBwa+*U+i_)O_`(z_Sf_9 zdawuPQ-j_!8(j{T{_8Q0{{76c&^lzhN%&`$pG|&sj%W|SdwJo0%3-X)cR9>6JDz7kDQ> zW9iSeXrnD_aGm7njw=>@tJ*#ujot|fkKfIPId9CU1m45Xd|Cv{ z#v1}phlD^v-1g-wfp_mb)DLIhdc7=`jlE7dMy*)iR%XXv@oIttdoEN7ylKmIF0)Lcv}qNcteckxFy zodTQQAEbnY9*Ot9T+g~nQ_Z1Qx;fwdU-JFVgH1zqpPbDGUoiSP zdcJ_chH=rGGkg0`TaVqp*U@0p(Vp_^otVt-_vdHnZK)mOd3rPA44#6>1KypBKNu3F z6mKkDvZ?_~`P8Aj#!@WvIgz0^QV@xPlxG3&%XzYbepT!_mn3fSA#MrjxpZsI%RAev z#yJT32i}nfI2_%6>_O{s%(-WZzTO)W{2egU!=xZ_EQ!GA9FF_GDe!JwrFrg-{3V?N zwhe8~PiHOrLZ{F3YFqARb=6bLrJ_F8P5?OiHsv6jAth5IACWef$R;Nk4GKz z|5`Y2=Jby-hgriVM6fXHeCaQp)D|4xLdB)77)w<&4GGW~@Nk{lD zkpwXlT!!h|8R9MC8gn3Fsla zX4-D5kDB3|?MZvJ1CpNKc={>E0g@Qw5^w~@zwrK>i8{s3+nf`kU%YPG=2;T&OfUX^ z`7dnXr};MiiE$#}iGCr7<5URb$I5d=a!9f0fv}y|e&g5fDKfXpImZL=;O|LfqE55( zpbWG6iy6~P5(1BuX6ec7?y;`AUavP{mxMqc8je6lu=657e_tx=2@2L5dv%xS8kA6N zH+8V+YiLcYh-z*mE?&Qq&K^}U3lOm7cCF)kjA$Jh!fHa zG(T^ntNsa2qMXYch;GEb7w?LiuxG}iA4d#EvgcAjf2wZ6zMlfjHe5R-8uiUoc9Ckf zYyAwyJU+%Fk|}s1%@=O}F%xwj7~gZV5(r%A&wW^0g5joq{vKAm@KT z9TRg!*EQCIw*O9~&en)JziGIwfAh7CTOeTukI1YJ0jvM3z&hKC|3}K5p1NnKee(sT z$B@#V*0>#1X8JFY`7+UP(tTUbyfVN)><61XI)!&*{QLIARXjet_b#4qPZczMoHugc zDHx9nnIOY(ue0a7;BqH>r$WjsIYh?7f=;4S4YByq!VSp&c^eqdZC8Jt5I(nJ&4T{R+S)-6 zb1uw%67vk2&4Ev5ei&%HdN~$PB+(cvXjnOSfqYtcfBSxMLij(!;(;>0{>E6US*q0x zXwD=#BSl2UHd4Uf!`tUQz@91&O)u&vB-Rm{-hb|>)tcApejsckWC$l`ba2>ZA-<=1 z0K`p!2gZ%NqJuOSzHj>8*F?7%E>-kxVA(H@fWcDPUXjCa9|HZzI38zNsJF5}R%G{z zEb}`97aBeiqak^AF6)*&EcX$x5Bp@zNwH1!(KTBmv&+vfh_UWJpwnjrDY0{zS{c1* zhzo*{?WuyDKh$)mcE*j{vY%ewR+?e@E$>zN!r*uDknI2X6J!`}C9uEmb+zxNhe)5p zpZ53W13N9(Xr4V0V+1L%bAz$y2{a71irtS@?kWW*9N#B+qFb-j<+shP&x*&ymt14T ziLtsXV}>$*NsbD?j;Utn3%x*9ZaLa^DxCQvm*vJD)WYy< z*!jj8&Xn2j7qyAIZWdiBnXlRXukW_EJ}jSkc@CNXgq?4proYnCyTCYNotN7Ehs!Gi zqUrCy=|ifV`J; zoa7F5{#?2RQamW+GXJ<;kA|h>CCnsypUn5eafA&H1a_7o8A&I0H8}=*- zcU0`|{8N+)<7Z<^LY$9Zu=A&zuEDFPv@h&4t<4C`tGrpa_wJ)O3t0Zh;UXgcB{0rV z+3+R(XEMcm1phrt(Mb7mL*eANa2WlJ9yTKD=M_6&Buo5#c|vm4m6^{><1F_&*59}& z^NSZ!gX5Eef^mrTfEw8OQvUYec{R?*o8EQ29{O2>@26!-y^#WpACDatBKmP7J0G*< z*uu-_x(q+HT+%+M)s^Vo@JXRL9@65-rv?+pJ`giH1W0;nVxI@(P+LzoTy(F0@GD!t zl@@eiPKE|0TNlP3SaP`6LwL>JABpRoKl5gvv(-;E4C?aC+w?KJ!Rq{cR^G)Xhk1%H z;czhgH$YtK7Un6qtMtZ7tJUA-_kwC!;rCG`XJGm<>9B&UUpKSM;V&8(?t4A^b(we{ zJ>mP7FR3A3&j)K+<1*1Nu`hc5-VH|Mb@e8**wCzL26_P4{m9%Zh_A za^T}&3mYGWx*5=7osDi@=DDYJeoC=qFJIi*zYke)9ORSDxajFUkjKq9dZ=UPuX~R> zJ5qcqHwteovkOlsXZgqf`HVy!>HX*jcE0?y(tsU1Z~PfHePjAwFv#au9g*I_i^xZQ zp9;M16uYE#_Pp!04H2a)-2DB8R=+<#Eh@YM(&oe;{lPpErA``X7&#x=oq(Z(((-Ewv2yKB6Oxn>Q4l&V(id5fjb zCO%~4dkh_otlq|c!gJe!{i1~-caOC458hap{7yhr+}Et}LFI2%mR|#0?(e8O+1ssp zV;ir!1e8%+5Pz=NN2`mqQ;REj*(b3QL8gDa1 zC8;QFN)I_%elEe~<+@$0JYbYRcFNAIg+?UdeUR)2c&`YpxR#*jm#Y3OLN!AgyEs8N zia!*0nq~K7voYtI*l2;_{$S_MX_i=g=yKFIVm^iEwd8VzQib> z>A53{f%o4*cCM04@5#&hjXn8?r1l;R)91VUTOvgwhoz5EF7vv^$SrFI7={bHE99x0 zKM-(Ct|brBe%>o(@j6g1k+5DJ(i!K{{OLp=9K{1@fWr>UH}T zC7|4%=g?K5o#rj~!UR`*W$kyt%E6GyWTbUJ_)gG2Cp2cbQ0rsFqPaZD*KdnHnZMbR zpShntDkm6En6y_4KdwB$J3d}jQw@!a;@Qs4M>m-3UkdS(@tWWHm*vMyE;Wou!-S3& zu^(BGGyV{k&kM}&K4BX_U*mbc_kvM`^Gw;tt3Be9 zxb|mMda}3Q!Y}k&_x5QHJ_$+7k`C@KQEm~ctuY_jhaS722*dFL=8?ot4svI@=?AMz zWwlD0rB$x+D?R%O31CU&FvN3ypf0ws|CzQm@>^D-{$wT?WF@q}3sZ_-eGC%CQt1Tt zho>++p#C+_V@jo6^qR(@qAff_=!fU(s-m-b119qj*9jSwK%Hyeu&)ANqV0O>I;LOX zrQ$EPxC}?Rw?l$hS{NDe-ZD_Pn()rXvg6&Rt2g%b;p}A{BF`U4mR8JygvM(9!k=>h z^{7|s&n=i4{9wrzS%G@-dP}`{v%IXM;*fyP#9M3_4p3iOP_EH8$zWhL_2bC`FLkMZ zGKGJSBnCht6Ez~a-O~f=N28+Dju&Tr5&B^fAG0cRy4micxOsd3PU0cQ{ftU~;9gp$ zW%aLPou1wembn5tYslJz%hdPIV7Lb^h=xJBmx5>KES5h0A?dg5#T|}YhOGw|T=xl) zN?E)W5*v9RI0{2P#{ud&oA$SV{&(2F`o_ZpPWqWH-4}a@mV`kPBRnE$(gj2q9(!G86vnyghcop-TG3y%J7!eL zq{=&63{~V9_QCD`4S~H~8jIHc+5B3xi>IWQP{cGhm;MjTcR9dB|iS~J1AU) zcd%L5ei4$I;8JkJ(aHocJfJSJM1OVqT|u*3Ryz+#tdFtsomWe=`7ASP$0MI9;pVSE z9pp9l<~(~*X58ExcF=64pWGwG_kDx}qV8Tz6V$Y{39k1)ItfXDy! z#*%}>Vo{jicaIiW85GtR?3XwI2{AvMKti$)p#HIfm!|INd8=amW0Q|K9o{oo6>oIr zZVV)dV@&TzbuTJ``o>abVg#wa+=qjk%g+A{TD7vic~jZSN@yC67>uWoh|H2z$a)9r z7K_L~@w58kueY%no4D<3P`;{R&H5iPkO(dmhxNn~e7M>xP@fp}X5*T4ncdoAnv&|3 zpGB)1@{jf%JUEHR&Axy-!~?nHgtmdU2ZJfrz5bt84o8}vc>eVfG;Pv;2XcRbdc&yd zy^Z%~V%m==I_L~aR%he|1Cg2X1hZ}vxQUledoP=bAT{677xxyg{nU*W}Rhpqe< zIJ-gOzW7i&dE)*l0uQJctR55=WgL1|=jd_=gTbhIZaCei2}!RY0j}?aw*&dhaHe>R z*4(@g_$4M~r}SoKYwcXBn>)rqisLar|H|@G7U}9g>ynFcEzbYYeAzcakGcwy@xu{u z%=sP77}JqEnaKOF8I`f@+$|1G!O87s?i%=P|DNmjURdiOrhdK-q{z%~F+M)%(Q=L$ zERA`qePpWuhPwkePw@*lr8rxBAiJvk>))1nok!0uA)zE8;SnwY;T|whmv_Hh#?S6g zz9*{0_Um`p9{kykb&f^UvHGcU4LqpSP z_#pUu?7P|9r*B3$D*k;SLB>q8Hj$U7ZE=xYVde{H`Uo$WI$E({Y>!JEw5^Y|T7JjWz9^3($T0-sZoxyp%wIWJiue8BUF(jK4yf zsKcC5tuy)O*g6lWUjku#cATGa>ybIi3+=r}-|NVtQ)_b8kG9v3j^|YOo-g+-J6`?8P5kis~ZL%l)HT%ewb{(=p`9(xv?xIos^5>FmpqWv6( z)>gWDpvIl5Cg`eE8!nbFClb7L4J0?tWu)ka81IqKXkmkpxIn!TV(R6O`ZxBq9M3kA znfp8OZklrAiwrV5cl5>v7cNk5gx5AC>Py(2xm)gMzo%Dwm>yf)_i@G{NS=*5_Nk;% zFbo%{J0j%f%S&Ez4BKGzs984jH2T%N`;GOPklO#bo)fn!Mg_p|f%+q|{uT-$%4w_b zVb$GtRjO^XL*04dKLDw4;xjUQ8dtplbx5Wy`KD-eF-0!LCGew*a-zar#~FVHi#hTc z89$CYAE-wndR-o8v3=hPX}aJRJ>Ca|H*%L^mMC%Lk7d?e_&|LUgTF<#)1-Y8Rq9+s ztyIaMHN@^)s4ijo;V7T^F-!`w-lc(igt3nw$L~-k`#zwi(5;`Zbm}m9^Un-Yp3EH| zP)`zhqSdf`piYTIoy+oteEQxuB!f4d^VwM}8FFe_l@Z7%k*GLNUlNhVoe$J4aer#O zJrv{SU0lSEo+g2fj#UT{3Ec!~aNx7Pd^aKmh7Z&+Ss+^xJ3|(`tAFk7Fo)j~ULK7- zNwq&AC64^yNzI4j19eTL#NKFFDe7vpTY38cc|eB0SEt=<3Vr$HYCnlR4q$^Y%=-1n z_5##3(fwk1QgW{Ax*f#O%j-}Z_2?$PzXTt%$APiw7C8<8^-ZL=-;rM7c+W5IH936g z?0-RSd%m@2c(U6emPDkIf^f)o2-GTa^a}Hc~%I?kF!E+?eEa}(th|j-9=i5nKmOH|6mD#z*zn!k+ ztW>iNGU&X#c6VRET-}-7!n^=?ZoX!E>e3!qt|&qi=UR_*<0S@|2Ho# zmA$=V-{C-RuR1V~{qX$ld*IjCFY9hR7Us9`T$jFB6=%#oZb2kJ64!ClVCPP^@IdW$ z=a=EXbWud%Ot_{^-~O0hW%l-t)z(ICuO_f=Tlnw7cZu(X2WHywRr77zgnbfw+P#t8 zk4L{a!NrfY06%^$zU%E7;g~;{=qKMgrM*4-{Ak2{1$OTEcOMYB+Q7X|`$t!0cV#%N zD11|p;dfu))Cb#FSQ$wB|6EVb(=D8wnZSI$&ElS%GXEo!M#Z!x%e}LPL=ul)R$%v& zky-)R@k9iMJByt=lMwoI`S*QhJN0E&1&V84{*q{4`nsGw-c!lAprDaSaSHKX2k^tP zb@dALb=RcsdHmhZmrr_Zz0o{U8{pG0G&O0#-N^w*M7$(xw+y%7^XlWJ zS5>`st{Gkbj`L{@#ZyPmYvJd?IlwuH(W`;Qe4CZ@7RWyTdvSm8A#c5n)Kl#C9fBvC znsBpkp#BhVs8pC%|1Qz1-@mVx_i3nVjpr-KFlNu2M!236qZvRQ<99rm{Bw*C)C=O# ze|r;amgm;=F)+w<@%oJt3lE57|Hs;yz(d`AkN?Biw``H6O(JD5W8W)V){?an*>_{# z+LVx@C@DgP5NWYhBugcgP$;5El&DB5ZTx3GGZS<9%y_=Pf6wblPtWW1KIe1qx#!+{ z?!D&}&9t|#qcbijTy}%Mzp10A-vZhj$RC8dTw1gEm#FXt3Cmq>x`K};0$r`tHqW#- ziEl_eJoO9;M&bf_g#7EnI*)|qyQR9z+kO9Qer_M%B@fSTu zB1>rkF>XNOl8#9ccvwo_{fTi_tGbvKHS0JU5Bgqu({u8olhNIoeIlOc;ws~hL(~t* z_jB)Xd_~8y^E@5b{v1)z{`-U; z;?*TwDZ{r89KW2O59IyfKe+g?VtL&|B?Co)eU3-Iiv>1TMJCQ~my!6rx*t52sMsZt z|EFQ&nozE;aFw>K=~l&}%{<#`S+=g6q!^zbA=JhvkoTufou?_H%Kl;FmkYMdWj2e$ z7_XTc^-}PN&5OiaPswX?TJ!F?xc7GE+niHUuLc5l_qDL+a!~NR9I5euJU{HkH}2JF z_x{#oxLGT*`a`3NZwAW>ecLl+f4vz#Z}HKCf)^A@jR)lSxmNP5A=WLx z`J+jvoZe`=)Y}b;E>c{?I5>$%X+B6?AP*1STZ_Aw^kWaGD(Tw)zGl_4nf|by|A(3R z9>11w!G#6Q8xMT!KKmyzetU0tT-2Y9)q64xOJj=&*<58yMw)1){PPEiS(SrIT+_35;V)6=H;?dayg^ljHF`S z==4>+*d4UjZs1I~COMr+TrZHgex&@9=$G zgxk&5m*Q~*GMAl_D^ZoQWRINBW5%wq@hZikC2RQD%F-Q)_6l?1Ovdp2ulac#lsrKO z&+Y3|sy50g2rQ|_3AEn1R5Ly#L9|z5-M^WaKvebQq~!9egxqz6vL|hCkGpBE)7#~0 z5SNMxf!JYgh>s6V9v9G0i<&Dxi$3hFPmB^&jJ~d$8+Awa>|bIWJODm5{C82GI(HEz zSLw8wym9W*VmWtJaSx_ z(bp|rim{y{o?nqF&{MZ79!eg!?8!Zz`I~GDavIdjgjf0Ru*v*VnnN6?frPqU-sHm@ z1RgKYuJ#_PyRMmf2WxrkmZ@0(>{=g3OB)|qKlpr?x_*4Xy~SP3Y8aC!oxW+gtFK-A zc;8x2b1uOV?J3YTAjCCjf&I@<$@PkT_BTE$^zeDz>Aq)MnRWZv&dNXBNaVsf`QY2# z6z7Zca~A{OAK%@(BCGcObNvLNOd-a*@57H|Jkuw(XOIV}v>`RWCjj`-745sSp8Hw% z>{{6fJ*SVob2oPJv?{~_^MVNlWND0dK}sGrplnf`m-MBnGj^XE#ERBjnsEGdzlb>A zgF>8qaV{Yw*Mz`ZLcyb#ZEf+bx+fVl^);n_PiFvYMFvJUM1!PXsNd{&7W4CjDD~qy zq_Sbt#dG&gbpBrIm-|N#Te!^Oj~H=W;-?HWni#yNJ#K*brqUth>o2@m9&P*j+Vahk zq@E8>>oq3ZAV&9pnTruPKs#uD)(H0e#utndD}VMWjr$p2*gW zntbK^RFu78#IhdyVf`a+EBp#5@P3!JKbEoqaJwtabU%Th9)l_zwO8tEe+arND>nb<`&l0f5+}F-~ zm{?fpobsBz%{zY94Dz-dZGr8Pz=N*`IEH#U&z%Yv$m<5R3S3FFIQZIO%DH@l zs<^q1xmujAA3PtBxp26f1V!codEP{o3b{UJ8^m^Z@XK5NQ7<2QQaT#F9PS?ym#`3a z4hllz*--l1)X1bKX*J1?ii5S6-c;|kKR01zbuS+FkF$6b_bul4YruI5uD#z`J34e^ zH?P0%6BEy4>$JW5%j6+uV$E=8WDanC!fifW_V#7v8D1$(GssTs&YGW>!gQO-94hl3 za9)B<|Gw8h$3bl@QacdIz_|y*0nfK;2Df6D{=Ce4*K+txRN3TI zfend6?fZapj*a3P*HhP|TE{eRyQsYTz@48VF+!YCaP_kPuQYzxomL=}#?1$}f73g$)yAybX z8pp1I)Y~06w@{VkVJR}g(ET>>c+|e4>2EnYE}m@({yXtJs^2LI^j~4p4t=TIuy}tv zzF>zApT38}uX9C69BSoKKt zKF!U`Kcng(4)`pQvJTDsJYc?OIkX>Dop!&%>zB`iUp(15D7qX532TTG-V6ETd}f|L zAn?HRifv)*_qq36+IMqna6^_%u;-ihc6N129@TvYa6ZBNrSYb+y-l-Wc?P}Vwn~#tH&T5|O`P>|^@`ZJ`xP%o&*IVg zUf?`~<@@13I92^aI-c&3bZ*#iUEd*#piK}f`DLLq5(lVP0Co9on$-C8R7<>r`^CmH9K?7Qa1J8syXblEUcXM&;ZGLccd;00iNkqS#SkZ)eiZ(~AnM}_IQL*Z zu=Zp|W~XBQ`xL+Hmd8xKD__ybk%Bnpsh=`G4><2&EeTG(@Ab?A``hS>7xRuWo5-b6 z9Qg4{CHKa`N|5rGC*jlcow5wN%Rz2sp#)0VI7`ylbh@}jy$_uV$8LM(U=NhgGLBanxe=dd=@O-1*u zOv#dA`N3VH>UliBwlhI|zPLzFA0J0Fq2?`RVO|6-ke8R~roebxyGFsCH=j$HWXe82JRdZ$z*>>=}y zgB&+m5A?^8Z>crt^1ky-_8!(ZALYF6yrA&I6ykuh>J#rwP`5YWd_>)U^-W=2yW>~; zYB}CQ2XA!c*Gso7gSbg`XZLsej>Q`84|10I<85(07Gvi192;sj8B<2mlsGMkUsZ|`CBgI`tIvH&$mIG#JBCUAD|-efI08-pA&GiTnui|~FKG-H;53z;{bL3?$9=OCO?elAz zFdm3Jn&S(ISJ4eOK6u2#)@C}&o3qVm@vhRlj50UqX7gx_FCbneE|)oBQ0?1N+`FG~ z%7NX<0GeLD{sqC_g30^Sw4MvIe-h`1S|C3ADz+l zrsdv}2BSK0$<^gQmRIPP-_AMq6>ld59>s+b1RjtVo&E!s-eTlf^2pL;qujTf_o_{} zoIR_G_rtS!GFwa#c|bmNqa>aWPtxf}v|}zU=D=O^UH-tU`YbE780Ps0dWI6-fa$>( zQb}Kq(7!<3khS1jD~og9DieWjdFQ=CQ-4?RhjYc@?b$mRP00H|)1HBP5_EQ%-z~m> zyZU}b9Fy$}R`pjkT5fl)&f-yDU#HOn`2-kG1szkW8(KQLNvx?p&$~X9pZ@%Q2|Ul= znR1ze!~^mP&?VfxFPz&RH$G%Xe{J=iH0V)9?MdiR`z} zS+aG+@}keBqYChLL*n6o%2-fqKOpXE{z-mRA(!V2ue*W7>dl|ERhO3sZSICx`~zKs zgCnTS+d#ZkNXM$cBl4-u;mP6cJ4W<1S9-F1Us8hq&On@dpleVN&3*;qt#p%)%S=o+ zc0Ls_dd2!vqIidN-{EfiSv*?%CLqo#5$d&-#p?OJB_FS=nEkX7;a$gP^yMnV91udT zp^3l&;;JmS?tjkvat!^enpq_1-IhHH^*74jo+ERp%o9NU41p+h(IwMolXkVf(%CbV z{^@3%s2kq*vj-B2%{n^G&Vw;O52&93?Oz|Vgu7z%(V7f4XNAD?qms|Go?e{Iqv3~v zb^DnbY1BtK&)1Jv{IH6gxV-m{lmogY1LA<|;}MIsP+vy?>vcKPb`zm@n z>Y^V4vzz$;agg-^{PfiVC}61M)gP3UdAitVYZT+%-U!1X!$Q74~&RfPRS9M9<<2eqwLui6z_0PF}U*5 z;q5cT4^66(L*3qid@yXcx1uhMTxaL6W{O=~In`Pe^upXolafc(-ra%mv-S9w9z|6s z`mRfY*G>b9^=-@kkj+sPcgPFszEENuMrcO|eDQJysoxk1YLUk881pSn)g` zA6yu6{1V6u!-DnN^qO%xYI4_>0Q;{mZ$@sqR^asz-=7|?K0eg?6UYZcSAUznNothS z!G*0f$-uvqI=S=a>q%~1NGNZ*^{^y76D#M%gPz;z~P zhZ~W2fj~TDx*{x`_wk9kI?vCl<}Mv-95Q~*_;po~r;DqTqaW@4ACL!zZgYXLr{IGN zyB&_4SiL@K*_n2)Y+cMO9M^1v(!4rEsDw5~|Gy;XIr?#S1`QyFRR@$*VhaG+C& z8x=ne`Q*9|!Wla5%i`)JO>Bk^b26Ov$70 zk$xy$%=SS1cnS{m^mCtGLKcAs!K7o8N zj5^!x!-W^W=z6>>BEnWj>ruQn=3@-L{Udw{m)>Ztlhfz{KMskDoW8HWV{eu&!y5sQ zG84Nkk#cAwh&veGwv!_O|)AF@Mi!N98sL>}PBmn$CUZ9hI#Ha(DA zy7!4dv+W>@vW_;yGLxVaf#XGa--~`_N9B#3dvmj@EZ%xN-|ro}-%{|xYDgeh*3lim z!Eh%Q?F2`1mfMc@MdoRjy_V@b8?FTY=X*;=K`VE&7LaeRwB#E0kl`Qd^ISbT2; z2hq4Um_`ryb;eBNS0me&H3@#SSn1OGyhZrwMYCI}5NELLzf5G*@9zM9oo%#WL+{!w zwXEl62a0x|4j;_;6JSzIup2xIO}<5kcpoo~9`Nfdn|cg1e_M1+U;P{ybj0e>xFGh| z=Iam_kw-Y4cA?&mfM2FRX&_kNrtW{$RdVvwvc_Egp+}Scry#*uJXuG7;ywiD=Z4G$ z{4?~{w`g_5l@;^vUHrIH{;btn>q~a$YvVC0 zR`hg)ehQYu|3W)C26;MD>!)B!9>-HB&WoihHe4_Etm&zEsygm(5qohOT14bw@KY4I zpacRhgp$XcX?SOcRJS@SIW?wo-=7v&o8M`!(F=a0* z?w8~9-4f&_>$FrO6_SP)6S?x}8P7(;?!zd#45`j)sNb1`yo1yMLTG_7$T zLCF=nA@W|=H}TvN{W9lq1EYl1)opUR&q)1+l|wrR`nXZ;uSiNBtHANQnPJTh0*O~n zvVZ;&vu*F?exn@H_hT`n+C1ShFRVO~OHA-Yya~4?xUl3@?*TaPp>oQx{`64 zi{VE6GKs)dkV8|RD^MA?`+XP(Tl!H&kgCc^0 zU43cj8wHHtyM7^bU$=ff?d%k#xc8#TmKPc$bSfmS5<%Z!4>*$)t#JnA58LPxwg0Bt zWP=66mzVvY6)P7>vA&vcg+%aN48d>B=Mky)ACN~(iqly44W?x8Sd&-KHg*O(nVY-0 zH*X{JF%*34Lij*Fv2{I#nH^Diw$oivA5-J6Est=qWpW&cmJ<0`3VsNM1Oz^iXN)c* z!PouMOMZ{aMWT^^eEEjecHd!3BI_?di|-$ZUnYgq)E~$}tzuEzDIO ztgBvTxJR*GY!HH-u7r|?{5^z3_;RQ*&uz`g!Q#rwScWr6JuM&}-J_~3SyrDMzp z>lHi~@27)8oLoEu@l-;38*2U<$VbMoW&i%W?h0MLA3W&pr%!N;cc1QYG=-KCxOjz0 zC7_5cJ=?1w@{dyTxj9)2gib0x?oFL6%HL^_vvREE=9(^IJ7e+u;1ImVo{qHMxunr2 zP;%AmU99)tGPTn_6<47nkL7(*8maGinb^+q@c8$~p=Xk~BXbi0Kgit^GgQH5$35t8 z@YGXAMO$#6v_T@7iy_?m2y}IU@zlA;fOhUml-r>b=#cQ8Yu^xkuh6QgTgQe6iTx)J zk9WMj6f+|N_c$>WYT5D45PU|pbE zy3AO(!O!~n?%X3KeD_8(uw(WGu;0cg;MocM%;SE2=TyN!a4?yhf`U?Za)J)~QzTiEc315<)_;Eq` zhLVb&CxLmZFXp95;l8IgZ(q(YS+?>xdWq_@?t>6NfvX7HS156=rT$JSjXnifAJ@nX zB_3fqak#bX`$=AmfDFU)Ysrzs@t}yeFGBux_y!cM@o);TgO_Rk^zHXJJKy=K59ZUo z?K)c|YIBb`pD4oiMbek}JANqBXpdA%KBvklag(zxmah{^ZH?E94XPbtTxy6T`g=uq zJ|Xjo#f@m{e;Tk0`Q#f6Il0a50nAH|*iyv?D6+gzNIXXq1kNuW;pM&}6uY71Zo{J@{6Ue#ENI857skS_*^3wo+Q85aI zV6U6Ayb#y>@o>8oQx57}RTY_!`S1L6z`h6ll|-ZbM6QZR9AJ%BHnA8n9F|4H?T#g^ z699e)&2~Ra$!FsWh&NW&Is5e1gOw?dEAJ?KaLS(6A?q&>@_h-#0jTPqLCF_bs>-LH z5NT}vI54QWfq6KdMR=p%G(5jx3F`!a4;SyI>Q^&?_PJDGvfb~2fo^$wn|GK&vS^tAOq59puvwSMu6xP6j~ zneOnFKdS6_pM>K`hD3>c)mi*t$6)yMgN9$b0E{!kJ+(QuGGD3|pSivBkA*_b9mq#} zJM4e3g#GD1zN4>`r#qqkEDisY4eZyI5087?dXblU9%nbWt8VDiBF)6RIi&W-?@tI3 zC49RO-u60DK0rp`=K%Uk`;GVfJu=lCTlihUT23(iOT>sw7jYb5X68Ghl{z`P!1sly zje}fDKFi5%<-2Nn#ku0ly^5db2+Izc#k8kGD~NmynNPIRKv&{_Qro{>1o~H8s5RbH zf;p}&Qb#B=Qrkx@XD_yp%*RslDMkSTKM&BKQ(hwFeOpxYuct?~ECybWdvutktb!zn ze0fSfF^r4$^$ZFkq^YAip7Q~J`t4h!AM+mdn4Z@?+MD~wb>ABNaIcmtiqMH4Dwr0v$wBLC)Fp;pBO=dFGprdOgZJflJ{IQV|0Nt_hf?Jh0(O~jn@y4L1V_<^0r?#X zBIeHh_R*GYuwRfT%wIl1#H~3R7wq90xB$Oa1oZ0<(JPm)=3nvO;^*XY=2>v}uhn0! zDZ&0zo-ls_e6(x0vrmZ20^)6#f$yk`W4LA}vSEv2WF*}~;rnN=k4sk_gZ+;@VIKP@ z#|1w@&I~SOelhSJYd`WcFe%f09@BU4n64_TZe$bb`g0g+CL%INJ(*try=kjM>Th{DH24mHW>$418wF3X_b>X!0{Dhj%9*JbmUpCR!T zDftxTf06hllzb*NjX}Dq(pX}@b^rCX}x7eyH4!}E+hA)fTF{lh$iiSI*b_=!?r z9g6ewTD>t_k{9yoR|#gyuu4(WsFZ}~8F>tGypf|0!GWI6wBxO10Kd@m#nW|{ore1r z1w4GXnz?#W`%!|#{>2c-8_dVgWwT7a z@2}(u{&Oa|I0CN%n0Mb!;*9T)G;t}tDq|M*8i}#zR{fPn)R*8li9EsvGuYA7Zvp=2 z24F9H_7CKJytZ@f_wR!aRV*v^hX%e0bAZ=}@&vyLpKFtZP-d<{;NJw+x5M?X>l(0Z zi_TivYqTW_n3!q(DPIQfHKHK6#U??3ZQ@v&%03ae<4F{!@VWo#b37 z2)rs_yvPaocJmu_o5<&%<4PZ1`4}3yfd79&L>`8my9K{>3noQj5V*GifBR+kUS^5( zw+_~?=(AUS-ExKV((WrU@O}-?#ge(RDoZ19s{wsSIOQKKEwtL_A(8l7EaJRu|J6s! zUJ%<=0p4fA+#qjH8vBGhfM4~Qe*5b5jqA16otFJ^r`}*R-Z(34CHf5oI9>^J=Sg9M zz^?(;UnYaa?hQKApU+188RBzS#{RmrC15krZz#a=N@9CB`ncf&eHSqA)B^KPf<-b5 ztB&5=zDkoZ?Rqx5yiK@lIdVTL&9rw=kfS>_`=|r<9T}#BTk^2)hFcR-rG{AP27>G? zzS)ucQJKtjbo!Sx2!UG<=-c{6x+8qZO|3H^^5bg^`?ZRTP<=LW9#FvVXUO`7_yl_r zFH+MOe|G`D^xlx?UUc{cWrL+_JKPPLKk>Bk>=-1D6Gh^_J}{8lIp{sW4~_a}^B&x; z8}6oL7*YS5JM5_UZTb$PeJH}?giy|ogoTSP(XfyEz5cE^uQnucqLi z#XgP&L)%p|l%0l{En{92&hvxim5J+o>f`$%5Lf&5!P>d=o$rp6!Qi}G)=myhe-(ro ziSv{)X?_16@>8YJKceI>>u)sgPPnA37SHv1&njkaPtG028(iUYa(NZJzQp&BRMz#6 zfq9ARF!n(A^IDnwk}i}|y;IiJ%b)3Oh<;8L&-28n_>qF|)Z5_+aQ{H?Gv>`{6{(=J zSE_nM&R=v+E-smph2x6^t}F&^WvP!=nOz5Yer_|sb#b1U{IarlN~bOfEgWQ1Atx6Y zU^>IaE|l8>aCI$lYcJDP>{ET3`Ht?J?XJ_MM$xN@NN z*U8?w7~k=)zhJJ4ilQnS^RLeL{M=`hb^xWR)C+s9$3>PLA`1~2q z#Q;ny+%{mm9$V$0yaxLidu4j;Jjdp>wQn-}2Y15zXqXGzm%rnz1vmn?9nklz!&b&8 z^y_ji`Q02G36fgZ+Fno;M;r$PZb-133ONtzyu1!z90*NqF6Z&Ockkd`o3X3fYzi+W zoBNf?{f|Y%?;eozAEwbi2iDi?5;rka*e?0;$7-xL2>04u?Sc8)BV_&LXXO?{;JpCm z1<`xPl2=ML3FPRH6&`xQsDFOCQ++Mm?+S$dH+(yaFr_=v7^j`U{MD8tabm;X8w$GJ zJ^WgpEH{)z-e+zkb1_8jLhdtkQF2v#a$8<|OG)OsI@qH3op{-9eSEh=JlyXJgnc&5 zrP$aZa9;xJUE!n4|@>~N^NC|Q1O&GJ}x@d7j)-%udLiD&7HH&-g{+YPMu#57mm ziF9Xu@=S}$$4Ak@ypiy*$^rEVX6Ks(z%E3@ByyfjJr#`?ZqTiFvr z+oc@D$?dF4(as9g+W8HzK4mP{%-W=9Die6M*#kYs`lRsl*_`_%E`~Jz2=O8~NgWk# zKVWy)8=fkitkf${@i&qAwsXBD*V~`<4)8pI=aR-Bg~1_k-vaBr@{gaE%l$qS5|lo= zbrpM6M2gp<&`#30#*oLKr=KJFm>!8cK*?R|c2fB!w@X#`!254W(d>E&o5XyK1j+i6 z#$Tvopy$8HIs*3{Fs~_wPoCyl*B{8EllPz+)-)IA>jV!<~-rf$9&Mq zPtH{r<+ro1(N0zp+y`m=uks1^+o_Jn55V`|G8|VwvG}fFX8fvT`~HE`O}8!LwnGa4 zP5#VRBg!2H`ulp5UukK_BD53d4<7IDh9`1gZM>lb$y1k$*x1N&M*z96w{ zUxy&)6VQ*Q_K(f@uNW+;lIR|EjjXob)uWee2FK44A&8jdfcvn#s6sjx|YYuO@UXg#t#_yMsd&X17H zm)Zv-$o~S!*L?hHU;>&-9k$-tvZkUexPIkPM+Rua|0JKH0TASmQ_4rJdJ^&F{Pe0^ z)f9nF8|AOOeK%d#sz3${mrvN${}28C74VCe9e3q(!XK`WtP#xgx%+LEMnU-(0cg|z zMUMs9!vrv{UTADN(U7LCXZk>Ot&09Fjk~`LehdQh(gO7Gr_~SN0J#|~C)gTnukGuU z53O!LLBA+0u2{GOQu>c_XPO;J?svfcWKwQ;Pkq^TzO(K)zJ6Wud77RF+>iP|rA_lu~zQLsm1S_}}Eu z9?}SMrvbUVO)syOhRHi}z!5>D$ zLs1Qmoi*r%Ay#kQT0_D-1A5bXJZ`MmiUpDI7o{)Gd z`JpJA?(O3n8D$pIu1JQAAeRAtoH}{tR=MN(DHLAR$v^w`B3quj-Kbzr5LuXz;p z<3a@P?ipG7XsL^{PHq~snz|g?>k1Sv(0cnS)r7Y<#$e9mQg*}=eZ2l<%Zs#cpY>&*hUk^2cbI)xw)s2>jXto`$dXQK69 zx8Lfl7)vhGq{#oa_2)64fX0&K$X&{AsllP@e}{b3dnWd#*=9sb$TC zN!2c=(SzIa1R-f8KC+`jkS7AJXV^W?hH1F>j&f_Bx^MsC)NzsH*iXponRy%>_5KkB z`$y2VQ)9sK#j$NId$-s($Yb&!Foq%bPav)S0qSl*!e!^~E7-^>c$L#_{I*>rF4fY$ zIG%JqIG0a*z6I)WKtfX|BqlGcT6H%EH(p!+H%%pGbx0%WTx>3XmIWj5fjS*@@dd}+ zCIy3SGR#GMI`qFWsAZhCQ<`TUn9~n3GDOFMAZG>e9pbHBUWLh@AAHMu9Id5O)%G!d zwD`>Ya)^hi#3Iu!o`G1xZ-{b$`W}#~mw~N8Sf1Tx_E#>OvFx~~PR=9#|(j}U zdCrCAJB^z6LlNWx^+@RHj&5b-^N;5FaMjb3!VJK< z?0=JQPgOope}!R0grmp=r9V>B8afjIF(5d^(}dM}(q zzPQV(EQSwV-tVv;ILwlt*tRj@4Rw0}_4-ft0Mv(JRa$a^hjY~U&g$A~{}pXJzr~N@ zwjQT$4>aUcw+En}3?u*M)khE8_C|c12r)PI>`gL@?mzbn()_>3x2Gl_s6WH-e#p1k zGbcaMZpyB6g?lgRz_ss+)zs|~Q9d<$#8S#-7D_BK{;5^%pk@DVC@r4T&*EzOEq6$d zn%sY8=!_%e(DZQ)#(%8?+Hd|2K+prIZ^Jxr^zb7?Nw-s1ilOLY!~4pMyVU9l!-lD5A+ghJ5np-g*6aSYC5F*L zKmA(+egp%4dbYfUUMEA657hNxF}jc2;3}?4P}S@!lsx%;GOf}Y*ay$z)4C6b0_y+JEw#t$#0RE4{j=d@-D~ZS zrb9Me-3ldL3)p)~*t2->QtF~875IJ1T>e7V2|%47 zrjE&}sqwq9CzUH1678OMnS1u^YJuSQ9{}HfVfGBv4MK5$=z3qq#?pyO60W5is5!@> zTzqu#zx$Und|Klas2@b1E+(R%-y|()*1-7ani$XP(=~_2xPf>e;SuEA{U!BvJy2JO zK3{qNy4{fq7lzbtkBz^OI^eP0JwY6pN9W2xyyb`}7pOl(AN`yEzTC4{5kaUGmA&JZ z`)WdVv~2<65(sjs&SOAbBKjo>@q9j}hgg^9jNke`{Our*Y|^DlAdW|pLm2``;2Qwr zLw-lc>CiQvx*C6zE00xQnf5zsZeKHhKmDip@Fwv5TwM&iZxipzxU0O~`t&a2%Sfce}EwpReNlM2)$akB->olbi0r?+5`tjW``p=ZLO3%Wt_P zx7|g0r@;|z*)P~KAKocF@;&X@TpE5IsCPs+ZNbK@F7(1)`AW%#73|(}ejcbttmOOD zv$-_l0zlm(25m3>Jxz5_vUk?2PU#IN|IO(h2i7Ij^`JhF0QHm@6#2r>37qvnRR(x4_zUgXQZ9IE zU;x-pEJPly^$<|Mg+tuo^0=kuH9or$wW~c2Q>asAQWGY?{YFZ;|9{p+K;0KMHu~hn zigE08k}DowVYN(aSmq}#y${+*TaW+a`Ut2O!|HSvW%$I({(895&06ahg+ndNiUyT| z`y30>gT{CQ>dSD*aDNZoXLyuz$IDkiO#95nUpdepiwE{~^U3|cu9txNG|br}U&h>) zF;_FOCJL}#%wBiwY~_FwuWp^&Uc~m+-u<64V1Hx^%PM5hB50)qRxs8wxnmz{~DMbN=^Dw!pkuQ#4{=6EO1=~ z)Wty=JyCCx4)md&YuiF&Rv$xXJ-p!!wDY?Rd+54Lsdj>E983W4$lz)dzY%mPSAg?z`@5;hF zJcC^+lKdj`9e{UF3S<6?Mf)DCwz(6@QJIw;d%H3}^AhPDABOb4j93(k>N_peF5rFH zk6o`;@ONC(FDN=^i>Bk=Ai^}WH+MoILylMb=k z;Z1+kG0R=Vj>7LQVQxT(Cn-xS0?&z($G9q5)93adCT)4&(;n#qg9a`3r@TGM>j~0( zHMbBy=YKCG5xCBjT&_^gj4CHbJI<7s;hUY4BI3^+q%6xO@C<<--D-jvSRV3@T9AE%lhxk60|(j%U4OMBoB-8<_jxbisCpA8e zvLt_pCB1hgB--`$jC6$)08q~di}Io5)2Bsh-d>h1`!wD1WxQe0U5`3m<=sN0@r_kP zdxZFTqdi<5U0egHk8fW}F2jq8W#*m}ABMUncV}Jj3+QcGe(URcvK=bnHT5A47zCal zz%#3Ki)a`?t-CI>kx2}9DvVYC<4_Z6AA%+Mp`Z{aUz|&b54HBi0pI^(g>hccW80sM z<6j-V-NdGpWT$9vBHc&Cs!-Y=!SG0pK`Z|c${&z3-PaJd{^Dp%Va}(Ax#p(%(kGhb zJ`(*iAy1T}zrRleyh@_sp96t?>?a4`9`0>hhU?iMJ&uU`RWr62%k_4yzKXQ;-2=44kf?&DUe?V&yyq<1 zE@*Qt`W3-=Ky|LZO0@Ld3+(S$^ChM7c~OZCo2{N&j-;mqXkk4c&ed0mmcIJ{`xWPn z7BEd?6)+KBb6c3@@$}LI=iZCX)mNF8zWXV;vR|1SY_o!YZT~%ewzu=ejk4u&YS50k z`YO}XHwtK9i_bsC-`U;m7m`xERsD7t;?=F_UNTo-6HyYG8Zl_I$d;d*l+sJ*UYtP;Y<6YgKFjrqyTKWQY z9_Yni9=ZM1Wl8t551k)l;zY%_CI7^|B+o+_64ejq=R;#2iUst=aB~+NH;`1;Sn<9{ z-+X(-t+pqrA;kF}&n2!q<=tyU4QWvi)?x4oG0pD-=>otTIcYPzxOD}bG-U9q~e^R4##75ziNIV z?XDk3&F1iszc&HwkNWq^-s-kuKdaPWx1@b?j{Oof9tZHSRK7P6)GyEXT-ycZ5}DrZ zhAjt#{Qtx}jOm)gL$;S=pnlf!jhNT$B^~VtFE?gjt29b8>0iv@A%E|2P(SYLxyyQk zj7Gzz$}UcDe6=l@NGt_-@>ISz3FJLUYglxveb= zy zYSiC9H^}}`k;HWiiHxM-AAx!Zs5O^uS+x7bxmn|)xX#+YeS5g8tZNT3{)3TIC2`^O zhHin5?zH1SXMlO$bZPlC_ZI%sdYR1ql4FuCHeS29-;nJ=RhBsWP_eHxz`nlU-g;sK zZ)Hr_A%SF@w(na;6fa>a=kSp2D;>~}>&aRJhY_);Y-7ea4rt6%^XcndJLd3^$LCpq z=e=~p^1DqVZ?*bjTZV`C42z5~2zwFpDG_+^tT?kdL2kzkfQw7;X6jHn?;DO|-uiKE zcK)w^>39i%i(LRW6TH{`JoWzekhKjWv7S69+I_RF{iM#w0bKb7aI*kzqcO`i*6X{@ zpZxHt?B~*<{h`X^OUePR!UDKJeF1tl)^7)R`^3^W46ofOlQ&eaxq6jUB5538{_R(t z9ck2MLtOyuYI|Ihp;qJh?_(P;_G-w9%Qp<{Ol*VmI1;$BCO zHJJF3PBmk_(%P&5F4Fhoc?-6K9DwW3aC)P`#}j+cuC8I1yBj#*c5>y*R)D(@JIDpN z(Gu0Vl9Mb|OIf9&wIvU|J@j__Ek}U65IeXC>U-{Y272EUnYa&m{w_ktGEDeJ}@r~{VZOhY+HZ)`=)qKk@l*N zG;8S>r%3B&4CQ=7t?mG-0I=Iqw_oPlmfiS#oLjcjPj1j?{H0b7H)+1Xkmnm$KbL=n z1`xPFzJAt8D|ti7qEZ!?iw?&p&b8J)G|~|CB;H5CV94_gPzr!rdjNU+QH<%$Hpd0e zM_#Sn(scFY_R%9o8bxO0_8`wYvlEOVaDjaNOv7SlJ`T}kMvMj=`)*r(IoMEBV#f(G zSLt6n6G}-@jf(^M`Po)|XnN}SIrU<7mGO_g15Cr_FI&oAliOMOA9tp383Gr`%a3aP zDYH7GVch&9F8rM;m&{Rp=usJ2H5ptt9l4K`!yr*#Vr zMGqe@%JLdL)!XAuYG*8Y90qv=(#V&G0`l#1gv5M(x$aEC0he%Ptd`oCa>8JGW;w~8 zvE*?W7K9EYg@KW{K%RY;H|ho=E+W}&lBQ3K;!_UAOeYNVc9Xe^Gu(emKLjq2U!Q@a zxg!5uU*n@45|`d=T4`lHUZ`Mpi`;)ov+bFB{{eaSncJ4fWOlJUmO46_&UaAec-@(U zOib})eaYi5h;Z!SMy+l#3dpaILZe$BIHVeTvW5+?sU1{o!kRW5^ds9bdHl`J2#vr6 z^6HB|_4B&AO-a|fU*!7hm#JLcTTkWlVBmbv3K&JXStU~uctAdV#=U!EpG>=Km9;&h zsTD3dUJ}T%=kH-+-b;)keq8v@&OuIv3*^&Ze6Hfi_2p8F!!ufq8me`a)P_r#lh45U zWfib+K7GPJRQ3~KKK;1$J5KW?hg_)r6>_OtuHkwSv(G&)6m zcbEOSrVHz-NXT0o>=;N<9RraI9=_4%zUjYaxa`RF1{bD^fGZ04IUCeW3UrDmaISynng}@QNIL0WAUrb#Tq{wOn#)#;i(|<9s)e)wQg9^C~Ol~-{Wk{*unh~ zoXdTN=I~Szd5-{IhG4SzGW{OiG!xrW*SD&*C;g3fF@Zb`a{THsz*|uga_LfuXy_XL zPpq|Vc_Z9v7f<@bb-!VrZ;(52cp&kbfOE_EeoMax^6R`Aq9;xXG37ESy>yQ519@0v z9+=1en{dMcy6cJ)h2LL3F>YcHiOtS*Jp}UPk$GVL`jfb$IXC+T8CnY!wDhL`Fc_^A zeeek6DIoKJy!CVyuTq}uKDSkTf16tTvdyo~2H5T2b_3)oBJ;q!^$Y3`C1f6$uU;~s zM1x+by8Bbn@9r})WdI6?8%YQXUmeyOKPSUnNwFp?sMQ= zut30)Gj;hfzZ=PNTr4}$eh2$Rp524<{Znu~{UFjW1nvvq`*&!r_Y{n~Y1Kq0Z*C;S zD1KrjMsp>+&iTjn_i@By5qO>8xoE;0D}lY{ua|iIeWq%Mk=DP}B<(!Ig98Mxhd|(U z{ck)h67S{z#*;_lbyMy<5_emn}u zAI~((tXA9b^OYu(fw9Pe#s?K*JyY+T;qw(mxURX6Cn1D}4)gSL!G%%T4-Hash1{7` z!`9w=)8AmN6`?LrU$^KgQ^*l`f2l~QYYyuRX91zHAACp26@H2-VPE-7V};vaUgPgM zn$->QC+Ym*yjF^Yy5=y~85bBB0vDwx)Z@c%JY4;pY2Al?55&E^&ULl=L-OgNJC3axu= z!<1Yu_s^l3Zl^vc^D+h8i#cH$wVA(>K^%_jC@RdSVz5Se&) zC^)o#Rrkh|zS|BtM5)8)V~T|OaQ=k4?8IW01UBvSv5!E%$sEM0W}E-4Ol5XCd9dSD zw}?+ePYL`^N|8_}4(9(WIy_qh0{;^bkEpI+kFwtBY$G-nBwytweT*AzvnLC#*QH3P z7Z)6eZ)?JUA=V~zrFnnwGZ0TRk1c8t3t;Tu-<{r-r68pBJ1I|G7LGqF66(eM>rcWZ zR!={g_2N*Y;CausAvXJLi(R`X)$V<4i}S?=yOILBK~%>37+{C` zO42_*tYKYL8X~2H*&m+!bj<-eN#b}X)LnyXdQuo70{06Lud@;ue&y}qw&_r`XK3MX z-^b+#cWJPaxr91Ep3dGB1w#?IzxBcW+P|bDPyVeoQrahpSt4efq(U4wgt}<> zap;Eg@gcfAYTU1sT#;{gvOZvO_qK61#o1#jT3l{IdLs9U^NAu{@6VTXHy?pF0rZtq8NlGrym!ltVYpeY2 zTNN;JyDKLh%O(odClSZ7B1VzKB|0J>oIA~WwvC4GJP4wyyQH`J#i9#kG2pw4s$*aNiLA5o4)R& z>V4yV;^^+r4{%nuj$7@tUYi{NzXPKomsAZFNe+;YoBo;igp7E_?ycUJ4c|T~iF>=6 zZzAs=oDX4Pa_0F$s&)e8<)+_YwC?LeyWHRndzW^Y3fJDQT~|Iq55K>rF8@EuWq<&= zQoNTFSNy)vcxnB*6NLf&?;--|&Tk~nlk>~P`B8gM%mC)y-cwduYS-64;U#cwalUcb zvRhnjBgOE04`lv7+oU1~$hS=&FVp<>(8%6{7zSIBsddKB)|VL$_QLrjXvuM){4@l4 zK)!8yT)FWfD3 z{k8_7*rJQn>|&N2hdG^wEEmYLO|P_O`T5LE!f1x@L^}~S_nY55S7_aa^F$)c{V(!> zJliPV{$ClfmM;7BD+@Bkw}>#(vtIdI2fsU_lt(qW`Musqi`Um zFg&DJdZbO9r?Nd(bd}~4`28hS{){Oi$YBBGtg-wazj*l<$kkEq9B$9Ww_CMiCGNp_ zp%);>Vb0ef$_4Ulqd5I}dg~6XFMJ*EdZN+dPNS83ds8EvM}fNBe`;kVEPD73Z@MQ?{fIQkL)|1C9&?WXBdTFJZqOlTD7amOxuY%uKA}I8I(w~DjvY0!>(X2F{RLz5#3KXh!RWR2 zx>cL>o7>8?63yHirqnLeKRJ#bWI1SDO>^)3<{(#qN&xwM)@%l6(r(>;zJ z1n{})!AYPVq|Y&Z_spqB_3*CX3A68t3Mwv&q>iHp$K`P!GdomXIZzLF_o%$kObQc_ zH|#u0(fJS(EK?mn&UXTNx#_{lpdP#!yjDtjL7mkcXWg>!xaV8f*10y1qX$uV#?BCh z7p$v2bIq?dpQ<4D%I`}WJ{`yjCG)F$o*qZ;0eqhM6i{`Em3h3!keVoC@keQ4`%+7dI@jet7lcA>jv^0zQ5pd&kj(qwsmsgVR7g*xFT6 zsVh^E+FDdIF)3i;{R>z<`*HN(7#??EW+;3LpdQRm!r~9vKYF$AzeRTp`QO&filEqy zqX$Rx@uCM6K|NUad`Z<3!=7K~t2V~nyY@>q-tb*Ex;(JyLAIHp@F{_M&?}&L7ggkA zp2^}zpZ5>CeoT?L7K6UO5Ix8X&vZ~v5grAkw0bHx1UE~yC|Ec(IXRaeW5%c0cml~x zEsKT=*4yrla;g&XO^=&;zH<1H`#RoS&r=vbG|f`#3}HRJgG!#qO-DEMHVZ71muF66H|4%ZI84imG|eEN5d zV{+*@{s)Nf&c%NN>uN9R(aP1klKCbAKl^ul>h~GZPkIh-!Yt;A#~oTZ_%EH&|IYBG z5ePcoL=wmP(^#O+Hs;uTg;uqqEB=`YSKJ4S<=j%A$(WMHi35y3j$jHJ4_IGYHnw@8 z)bZNF!R2L{moKf0FESR&wnXaRaN!v>S7t4ElnJAZ1E{yn_gVa;;dX^X1$=U9mme=V znal`p6c9w}Zt^}3_91ZAmq7h(e)9q9!cPM;Rxb=IUcGYG&qkGHm!)*a@&AVT|DSOP z4S>&}b44@5)hX}t=GG>m#op?Ysvfnw#<5Gr^05ROg=aQ+p7EWGZWm9NGPN|Br`+Od zelYb$Vmv1~0v!kx9-t1lfSSd6(x$^pVzH!ht29|-dHL@qMUI^IC+J9^@XP_{(=;RC z*9P7AWhoVeI{QVrg_W;2=yIA5Xb7P2Xo2&|d%sb|USX2&g}lx>rHVVJ!Yn#dIL!w% z2vB%{`q~1rha?||G(}XmhRl+;%vbdje`q6nY$$#_#KXO>F&3zw&G$vZ`Ow7hP4W&3 z&Y4>+F1)h9EvKY`aj4|?D+1S;#xpGYksS!ov~^U7GM?B ztR`*t`fj7-oARw3sY}ZdpS!9@;RotjV-6X2J4RJy3;PAt;#OVdS2~-$ussU2o5tgZ zR6M73Gyvu)p(|_kS2I9U%BF+z{%m!Qla&9lJf#05IuB1O9)%yMTg}(C|5Cz&hgH!f z&Gsrj=j{4UYd-C92K^&+{;{eZg%_w>&2O}MUVti2%g^bBi?5SF-Y^1yQ^YGL)iiQ95I_?Crlu=5p`Dm_WRh_c^!@%PQZ zc`VL+5Tm&{)R>%GHfZ|TMl)-fnkdRV#_@_#dCb9i&{ihqpEgw6lj{>hB<*YBe=y1T z8_GO*vDblm(gFfAk|UGj@h3yz_bD#c|{1nQsB0fBx>Ky10FH z=>1t&V{mDG*i6M!eXl4Z=kOT5;fw_e{z9JcXL7>lDQ;oS6OSHu9?(EW;REYUkI$#Z zk&l(XpKuv3*@PT!v$LG`J#K#j4P-j};X6nts6BUM<(%+oagXTsl>3#@I zq#*C?*m%YsNhtVBc*38>1%H(2q3|r_iN}~Ho^cOc6y9Y#@oI469T7nkp5;98jM4Kv zr?Jp@?RerHv!A)9vC#Nd@WiKp!Z#AWMZ>q}34aC$e3mSt;IHHfUxzC`um1EZp7>Nb z@v*5tG@jM}lN_L@uh96`{7?I8Z2Ag~$Kl`f-&j)?1%K_o=|9x;6&laFf75?Fr?1d> z*ZEHC#|EB*?(^hCaU|sM3pB$j4tOJv_&(6!~4TPl(j^G7r0 zNP)`vbU);sJ{!+)+6oQVohRHe<3~+fq48`6;!<|h!@B40I`j!y9dwPyO zPdw=RlGl50e*fcqc)hpc|3A)$*ZV6Zp5$GYjfaQ+8rT4yaA%H#JAS$fjfc#Weo`2Z zho^iPg(rMv4*2dI<5g6i*2#(sJ`XA$g?|fA^Hb%@Ka{RQ0P;El{TN z>eGIF%M8KREFETj3}XX*XxtC1>Ov3}=nl6Cba z^PRTo@OnVIkw6>$xE>uJs828Ip7`sW4Ox0q>|4^JgzHBe1&xiQRxCk%UkSLy9 z`b}YDf&JockYs<%Fq!YMU4ic6Y4PiOOIyBfX8Pf#!|OspiUV+}H;UZ}j92RO7LB`? z4_Yj<-G4q(quXGzNR~nx^IobcPG1MEv!sJ3A$^=Uz3;{D0`{Ndj}01y3w?EI&v(y^ z@=QA&e|hhj#Ynw8NbK}UL=P@<76**eq(D~jWzB&%g?cOd2P?Jwc2wr|4j|)%@Zk5o zK{_NNouT7H!+SG0j5D4cSLNbfw>L++8wB#)DRIZE>F%`PZ}<{K9w1zU5nK-@Tqu)FSF4SXZ$^YUP_Z4Z zmIBrbb@Sd2t-J9Ez9%J+%xT>d*>NS!lY^Gp7xe9z*{3Ke9e141O!sf?^`Uh)8Np>X zFyg-MNx-`F+3l2mq_Y2~(44Lh9*?Hx$SAqCnId);gl{@(+`f>y4%ML&A;k?_klggi zUUnV>m zwG;ZzG}mM-%@CY5v`*%uzb~Y)cvz=oV4q?N+rrhsFEUB5}{owX;#BPAp zw?6BoxCfrjZQT2T^U|el`W0onLxE4PDka*_a{rMVCKAtlCkx?@+OJ4=O%LekgnNGx zxz@YH0`>X%r83i(HP0@0d~%xRg?YMBnJy=k;g0yLCU74*=J>t5x#9x#`2{x`Dx?b6 zeQFXm-TGeeLs3w&b$Iv{hvo=eA}0|L*?8Y+XA;| z(Sk>+cUrh_QbFpFn85wqnE2fL6<~on{nG1t8RdI&ts?8^x;Wt~eTv>BtkV=^eNO{J z7Vc<4N5MV9jw`W)P;%(^xz9`S^2fGUUOwqs*zhO+3}U~I!eupzBU3zSf!-YJCS#8R z`h7#Bj=0c=*WKxbZ!<;T$6r3OYP#eXmYf^FddxGBMkfZbE`xBF^Atdj$qYEz_(^~2 z>%LOE`B~WU^o=F5KdCG|W?;-3KdW9ahx#DcW5E9TZ^MAm6kq2eY11o>yMGECy?$o7 zeBaP|o3L>43%?;MAM*xF5RKZvv3`hzZ;;j)@ych0Y@#FFb>5y;N*Eu+EvTw@@2n|VCzP$@J|0$lcu>$rh_0obFF^fzUn3(oVsJ3F1GSLRrpEBm94C4Yvv zVfkiBA$R%90PufxReU(FmN8}3NugPpM~!#N(I_q5V$6gS#FTKNC2IIs;#9 z)_GT_ny@hH5ME=Q;H*CBXY*NdXlOXBuSnipa8Cl`_B&T9(`jO;bp7<jDiI!9~H%V#gKPn|#ROyJ9cgp| z>tN%mUrzyczLH)ct?Y`$@jolBSFI!TUY@T?Te*~ZF2ME7y$Ezjd3$h|@6&)DTu{s~ zIykw}DSE}C-pZvfb2cWNun1$W2V7s-J7B2HQvltE(|TmH%BNhk%D%V#qb&xZlsPmaaYSqN%`JNI z{5HOc8FM@FwwW(JBK4(BVY`@HJu>Wh_V^8UPjsyNsg}yJus`c3PPv%beniT;`8gs_ zFrFSY(1QlIWbmQ-aF(YFK%CBL??+klk7A6K8$7?CeqVS#HE&+5+6XQ*Z!b!KJDouA z;*6UIjQ4pXuIBjVPw!=)-Dx=^bs&$gi@xOT2ri^8c^mIVc3eSB?)grSqT4YgzPl+J z?>;>KM0NNoHG<2a1=1N_9^7$(J^>;Jb&}JGpQW)PMJo63vGqkSJ-g(skor=lu%AKj zA~Kjk6%;(6KY-Zl#xwVhIylaLT{YmIb1T}o@k!4aDI_jo3fr}G0)rLmK*1{j&dr-)0rmg+6>7RayxVXur&izAReFxvqww0GZ;KKAZ;C_wOb8FMvuWJU6`=mV zfcY1bPvKYfMZNEo-G4euylRSP(}@p5<22$vPN43;;@e}->y1ywDejm2o8+*(OX3Bt zH;Kg5M{qrPPYRdu0rmc;=V`6E)6kep3vA5iCv>PIc7Q2TcW}s!gMA_*_j+PjpzgoK>Dw|*&7aBo zA**wy7nW=)SsSkNrV2UtOyT;2Blz^dfPi7+4jmt;|1YBSb86Ky`*#YuWq(9Ur@Yqo z2&#>tA$F1}T!(N3pGFw%)uG}8{QxBT8c!r=|K6Udv+&_^BVWziebvv}{h9j|u7@|` z#i8Hnlg;15bjyiWg*eofGFhV#aj^GZ(~?`?(7Y1X>pxUcJ7cD%`7 zzeuZ_7aslfz^tHZfMI2=GwGFF?+~5=cf3+|Jf)XrrxG0RiN(d4)n-mAiLp{z-i2u# z!5azEqu`YR`qU?%DC&I3E3@iihDQF+d((Sw;_Kfr_ZeKLkV+%4#>iW}Ol&zjzEtKC zUx|S4iduJ9sjji(6Wjgy@}E}?L-MOtPc3%i;7*;wC%weDl1 zOQ`tw*zwi6H+>*!X^1?J%I+XNeM8p5T)TETnW;bF{J@B}je=JN=!Y5W&-uG+OrGVc z<#J|~;`#L1Ztv^QGW8pr4`ABHaQ20*NfG*Z?*r%2j)9`tj<(hk4KudPOG|Rts`}u! zU@hWDnZo%2CO+$ColXFr9LnW9c>u`egejNO?<#9eb5qZxEDkn|leGLMu0Di666f#= z^klYDr*pxt2EOOf%{zRys;*M5jw`%AS(3W#Hb3LrZX}KZ;TsM4X^;^`34s2CPRILj zj{iIa)+goDj7;Idl((+wp0hF*Tw9kKMw-RXw5Lt?PW*-+b z*bl;!$rJ`J@s7v9c|h6U{Z=w(NzAPayW1qos7tqPzFEBy**|8mKjc9ga^+F*o&e|f zzQg|c+0)`bdN$vQHB7X$>GM9*7d(V#$Q|z~5RaL3W9oUCZJrbP-iZDpzf?Yt+1Vg( zKZIw*9q$=%PQ@t3MtsjD8>dr6pH^PwODI%KCLciTOmlc0kvhHvxGN5qeNhM4aiK95 zt7Wf~d|W(I8~V(;Ppa&kPU%PF)*SA$;{zvxgUF+-E)?A7z&ZHyyGket*Q8;4O(Ca2 zRMOPM>c))aL%6tMTq=!1<(N0C2lknqM8sRW)akR9(oa$+{)jw;OIUVkBcdnFVf%du z*NZ@)>d*qbh}`0T4FG<^iNP4B&*@IT+$^mJ@!vi6PrcG8hS6r?8xG?m@fXP0fCvbX z(xZhUxzQkk7q|V<2;}(%?GLZix%SZV@PJpc!t*_=^bUt+*C6*r%wao!h>ux3cyzV_ z1^)#QM>^@LD&TWd&f9FIcgxk+_1Q_&I``~F@>J$=3*noLhY#mWJv_MO+nRv=bgS63DcwU@AxF(qgP`W) z>{Zq&cL2GM$;RWwB4Tks`+`O!aI%kH0df2zFRre=u>MjX|MDK+V>V)GB*LqFBgB4z zcua?R0*F2|HnoL@|C$|tLS%2BlAui$@yrZzeuuI;Cbsu)^Ias~1mT+v)Bj+c~qsPK# zjhzE7(C0wlSRFM-<=xKZ`Q-;+%HaP*yZ2)m9}s)O9PUFpEGJ&ZB*>Z=mH9!z2l^dg zwG8 z;9HT~;G!9!b3@v*1Y)_S4SPpM%Ky}4e!hJG_l<7kQ#>%4*M5+JxtRE}~A^evFQ zX{TKk(i{8URlCM*$J)W&nk+fIpOLKVZr=PS<@B-S=Iffe8@uHE1AQ2gyC}qxqpKsv#A7{Cv-UK5a^zG zD%W`ceGK?QQdB31NNwSdrUYtFYRS(I!Cu~!#nMLxBl?JWKaMG%$m!2bAAJGh!;{^U zHA?p5$!CA>ex&#}GK*?jE!WMGQv;mdXk?CZ`W4XsMCpBweuPAk?8uhjYfEb@-lv_L z*M#I*&EdYRL*vH>GJHA4bAkQ?{44Lqh5UNrMDUcxV?)$JN*$xi-|j;hiC+k zKqASD`6XzCU>cD@7~Sm?bsj)}0+FmJ)rx(`DZK|s`47K8zVY8XqvVUWEV(rptB;`h zP}mO!6ds^&fx3g0LB~qcGd0Gf6Gw|;9i;r{DLYaC4$t&UM3>{(sb)?lO3NFyUV3Nk&)a6>a zPX04qF1mNt>_)5yCE3__2p7l1WsaINF3`Wgq}VRGzpmWvg0LHre@`0qT-v2W$F-Q} znbF94K;~2s)2a#@GT>0~e*$^}+Zv|m9(%L;mf zeZEaS9tR`DbWS6FvN?P|5>jp?coJOq(;pxnx58dkX5H=`L7MXC1+QoDEj*N;blL#P z8^XAH3<8~@OC_P>0sRH^sM2>d92FLqYhLLcd=Pj0XPL>wKpP~F03qpcyZVkQNg1kGy8PzQ4htvUMK&-FjT26aAkbd`Gug+v`}WcP9Pz_flK03?$bG#l?gSCq z7lZ&R338O^dhk;Yq7Ruu+WyV|Yda;iEV>@Q4C&wv3tHQIoSCRb+@q+E;YuU^68j4~jy52*|^1 zgvB~2M-!p&hyiwnru@@4eHy-Z1)d*xsNMVY+Nt8*$M_)oYg`^0!IOa81{y_#!ZQJw z&#kqpSN(Tfe?4#eiK2kG{b~x`H#coVn-8-q8Bg<>2*^Rwr7ycmJJ09lSbL^E*q3eT zx=JwKXB;_z6D}jNz+Dc+fprs>Sf-J-Jv?$_$d}?Jn=_u=6N|}sF^(LJBzAa{0|_8M zyRt+3O-QpAJe0~ z>zdAAe80Kfd}V`HMWq9tle%>w|7aK=x#-HKbDq|6hU$!H1xfti5dAuH?2d3@X0 z@q`8E#kqgm);_SP`HowohEKZhqqa5vn2Ah00*Qei0z|>v4xEEcdp^If{kW^@&qV1b z>htpWJkzxv_h6(DJRbs?c^?SIM8S&$@K$7%`|b*P(KNftGI`nk+Ao_^iPz`D=N8Y?$A<10X%;Tz)CDq#Bp4J0FPa@sKrf`BGx|)1YX)J4 zfwhbGl5IbN4Y926P4~s)xP5QneUI=K$q5yY_3W$bBLWtzUEOx>gZX#6->mPA;BmCK zk5;Kpt3Nk>%qw*ef2|~!)M*(8$+s_!fcF}nEIQs!U_S;te0MFp-bPoq zBEIp?D~TN&jCJb60X%d+<7mY$c0BQ}C9*#!Z(O&)ZB2)w)xMZ5DxdakbHfP3c?afR zLBWY*$5~ZME_B^xF_1oJv+anTXJhp0n~C>jq3-|*G#&9%xO|6rK>peuUsYNA_h+%K zk(rOR!R_Ch)xKRC7>&o#KRH^ln;lQr?&c-+0o&Sw-4pI>--*!{zo#-KPzlB(5SZBr zF5^pJ$CF#n-P@6$-fEmh5nPL%oO* zXC;1-kTOTVWFI@;=F8O?=QBLM@>SHh?@IYPReU)`sQn&Bf`vCq=b_*w1NOiD!8RXt zm!H|k^j~juj4>}C)?-~GTjbbnivXqVlh6i3s`{uPN=wr#ENYMP3f#OgoG zia#LHO3wQ806VUg{C(;6iN{WbQ(u-VY`1Uixl(xd=Tc}LN8YD$UdMyL`S$4az{-kW z?|oI(eLa5huUle!xK!mmMmP|;n80EGA7aPR_I+h)Y_cj=!*Y&vYKnc+f{miD%r|0$ z0vXvI&y>->=L{S=_9cd5v`yBkx{yV&oWceXA@1m2Pa8i#W_ z1vm$`?w)j9T4d#?^3@8i+HN!3)G13H+J|w_@()KVjozz?R zedWJ56MQhD!8FLYM+Ss~^BmBxf-5vBBr( zMK#;kDN8}(UDS|*BDq%q@(e!eg zdRa-oiLI3yVsnM+KS`ee@HoUtg@AstlcJuzsIsZFmRP#OGaxvPs`(R>k?%7+Ujpoh za@g-Ff4y0-$dsXG@AwT9u zHecFSS@q|cFGh-m$7-LBy8lxIfxb|}p-Ep2YA?t%2%WpwE_i!#h3z-zEm0Ur7G3}z zeypgA9xoRJ`abEekGkw=74~vZz!!_sQGnTF-`eS!W?bE-PRu0{~F zHeAY%Y0Wt88+-Rj!M48P`LeueRK1xZ2=s5ldhX5lTgzBe{mszj%B}PHKlgVs7MYE~ zLtj6jPm_?vEa|-d#$#8t+PeKV*{b^6`PT?{4bPVmO67RYrw9W5nWoQfIATA|3O`5H zb>i;-nni9z>V{~!4C8UL?^6U-fbsP_Z;smkW>bVod10L6-P)t;-#+aV1MraXt#h!k zf&Tx$7@U!zsS3_ejF|Yi=y7REPvrVzihu9@;XfF9N`!$iF)~xZnTjpA^tj5Q`l8(O z+r1q>I&Dnv%G)eu7@F(rV~kbw#pG_Rz}=ZGdFbB8=Dn}eb?H~Ov#h2S%X^b-WZ|z%R?*{*j!{7{{pIzIs4+UMs1;$hP0=V{QdIDL!>^sBf+TF*NLqvJld2kBoD zUM3ms7TL})hM5iFVGmBSO*{Sm&O)5yw*4L0&v^WMcLk&z3&aeMO!9({TYPm|BEx(tLid<1amZZCW%SItXw->TITOMA2^y9`B#wiKpA_(%U?$$}qXo}6) za%+Az%t3oj&Ti~LF{lMa>?OsBmb zEW6@K$QE*ME1iX;Sdd>WX;bsWsae_Iy_eC~XxsL_*zRFUB6=X@MZ7TZa))m2^YVC6 zzxV8Sqq?mV=473Cv=Oq20+2bG1kU$b->RR)@LE#SS}JW2Tb#;IrFtU2QSi<^YK}3+ zYLot&{Vhz$i~KgB9!?e^^0VFTV$9-;EfaHV|AyPX`ob4X=c`5}7K4NTY+PZl<62o| zWo_}|56Y&8B#aJ5TX<3eAa@^Q0FTK;=F*uB&1*imewh5G?7CC?s)UMp%tRXUmEZmz zlyv>GDPAM@+8@)?hhp=7o)U!b_S1+S7-Mr4oQc>+!lO5vuF%it)aHdKOQqY|S2sup z5d)wJPH2>`)cRMS`;gIx@1G6PgDLY+0O663f-bbZi4D=!SY7Y>VS12c?*~A6DY_q+U>MSEw>qDZ@>3CWw2L1}lA#bmg zJ9tcLuDI{nm9nEm=Dz+(Xis7c;V)oL(7rT#>zoPKPNk>mDr$)G6rS~C0b-{ngVKAc9z%$;5CX)R3@f=2F- zd>u&fi{Tv&Wan<0R}=YT$#%;e8^*guqK?qW;cew=-*$FC{?DYm<|#MROg>0lR$skt zIIN37^#1jW`K#lk-fCCQb0NC5%WS;gMh%vU&$5+G#AJN6c$H9W6TO z-7~dk_a(i>6wg5TO%EQC0RvMb6$7z9(XDzDu|4PZw#SWh%=pm8EOB zra5QMI&>|SOQd8A+0Hhanrf;^3vO91*H+m=#6@M_E8R^MN;-BXwNZ|HU2-3vr(G^_;nk$ zZ>;-)v1a2>AGvN}Y=1HJXVx4rq`g&CTx+u~3uDwH6ARuyA#|A5L|;h z!7aGE1$Pew*Wm8u(@FQe$}r)#V2P@(WPMNf z^g55XAyjjbECphrj;jg@(#2D=>Zu-!R?4q$6NM93Kw*`3Z=XWqUEBFxkEmACU0v<0 z6gO)2>zkOlm$gdYnWk2v$+=#)X*tg9>IXjUIz9*wmg4I@*?nT|ilxl>=r}I%qTzB_d3>E0}b3 z?Q>RVLkfK6!|g$iN-pWE!6pMQs$1eHzW_?r_Hreve{7^OVz7kx!Jh3_-{sszziAYT z{R$N)`HskL=*8Ea+@_U2QMcyEO$Q@&gku&oZj&`kTRr_#mxjyo;Edl|#@ihm_2Rp( zF3&mH4Y01?aq2?jLZ-TV21RjkON4bS#g;P#Mf5Tog#XH$)=7aiXlT-L7E_Q{ z8{JpUDnP6=p2853?#;TC`|>QQDF}1lCzi{den&ZliBcOANcb@p2&dOZ=OwHw&~~?Z zP%eozfO@fp+4cqN@BA}T3Gf}6T;OCO93@J3hEE~n#(>Cj3X_p zy0`<#ujxd^G0EcsA%429#2#!t6V5(5$NQ;#eZU;q(>Us{maK||Ioa{u0&csfQHtyy z$I3nxg82@jGql}0l~lnm6*pvLINb#fUOFxppn4CmE>Bezb7;#tRh@mZ+@iGb%W#jdNf%Rz0? ziRP{UiESG|BLD5xnP|FswN%P#ry|ivxe0^>d*zca{%=1X*K9~-c?Da<)SLQgF_+rx zLO#a2VNPITk<5D?ui&UNm=dGmAqc^;62!3nByBDn=;&>0D|ZF@YEW7=UpoArE>uod zjt}I#_|{nOaiBBPE6@{xl-@Mr^DF)_)am7$X@|-qs+_PvU`6BQ(nRFR9buZ~Wy`8` z>O9R|t$ECvfIX4w6!5X-{q)entczk_d=SWHG`Xc{rXz1juyv7ZJR)^59q;GGsH>1; zl-q^%5s*Z6K&%hVn5oz0B?U6!Xi=MfafJSXU2`@fMP&Qs${{9$D;?|(>Ia-QK_=Ry zmOtd|O$`;n%1=z zZx-CHMe?6&HRG^Z15SOn=2WzccyuAIS}ui1xb6Gl=^8DAzxeh)2yjM|k)vNIoR7PF zxmre94M-7Tx_TB;gPxP^4!cIJcskD{4$a8?4(7W6pM!TSZJTT$&W;z4I#1zG*_IEi zSQoQz)>U)V%dn;J_o4hCk;&+nL=o$*eh(oZuFxnSIy6}2?fr9#_BT06s^})MNvq%c zFT@VL&2tMT=97yEs%56$l|zmDbMH?^eu29JE|+ zDI&3(%$>|+^I5~%3CqADdhK3zs@&bZ`NF1?Dz!an==R5`Feuh(282^MG`yxn=kjPb zPg}F1$+&RZ`X=1|a_&)W4!+%~+aqg@qX3BxUEizSTF>$_b~A=+ihcOSb!&;w^LS|Y zIx2A2Bc8KEU7Y=A@gn@S%)Y17ZN-C-KCh1al(ixzry^%N%E9x>3e{fR@4F^~c)ht5 zbaskog-mr+gmNI@a6@xJIwS1Ubd%z zKaadFo$FTS#00;l52li85BYvnmwG$~db|iYh?rnxdbdJtYJLBF@EWL{Kpe;Q-oES@ zU1`}h!CUpNe&HavecGWAaq6e0J|ZJ_!4&pkkXhkevU*&&|CsDU-S)&nX7T03({4Q7 zoC-6UZy|V$)XJ_q$@&ugCcCVSALM=l+T*`pm05qZ*~xIxl`qbT%q-y7ulJOYy1pc> zq%?P4a`X+$tKu;KqWkHfrd9=$j`Lb1C$LNj$+`c}cOJzXaxbGF?vr@&qaQ)SmcQ)_ z#lGQPKF_%{*CSc}E~%}Q-?^`a2^oOmAgC0QXUy|K{#+h!Do+rRwnZPz%Ijr5#M=3d zdXE`aVql%@o_NRk{9=zRUMv_-F8-t`XAR^|@aw$X%~@mxJq%Qqk!!k@36ES#_u5_d zNEr{$-jtC4Hq^QBm`IH8iMUO=8W{^~O4)9NIJIu`bccTTe>>zxyKC#7q$s+>b6Zby zZZ)p-PY~hE!UTuNLD6`!g(ef5oljcM^`+hUf&5?Hy6L;c-uCGJ#@?@+_fBREy48#@ z>8@EfsujuFg90&ceLI=6jh1RYcy?oM@LZBBEy$^gQ+2iM08jV6wnt3k)bp+7KR^e^9&!vR`gS-bVs^Mm1ZV<2R!K;`x^Uax zm;InbC#fN-vfT?0!ugqispfh{uHEBhr`72Fc&)x4Rawd(bZ$ygnTpPFlu>VaHJ`d(j!##qqoX$CO}JW|`sl4K;-}p- zx-1nQ$v3^jKX+Q!s&pRN?|c^k;rMlb>z8IMTi=XnNjvoXlBwVhGkd(9Ke9tG@}kjN zfLk@cO`5?;d3K_Pm_Zm7>8xe2WV)KW1sg<5-+A@6d%5nBU~{vNTiWzz0Qb>C$dXQD z$__+(L|^v3lYfs)W%YjPFX6WB1F+Qm94?~S$HK?i{Zr({UC^o@g;d)u1Fo3?{~(5_N@u zjM6uU|Nf(kPyA)lvZm};s->o4mI)?R6mdE148adGk<`x%fyb2q)RWW7|D6`2q~DwY`+dA}$$mfpp^c(tWb z9!@bz=y?1vfZtNh#~=K}%bM6zr#h?*hzi7)R*EDR|0MP>C-|)EaT=oV%y{CGAmvl5 zqj$MTRr2Vq)+j9VrSk)Dm_meOwhlg^S#f-ejwY!K83m76PTCOt1N#2L+19Dn!kKlu z^}Dm1(5K%O^*l<{yY8kaY#qVay_wm0CVTq!CXX#jSJMd(LBnkWux@O!u& z=Px>HaDce=mw+5vb(SYOq**=ps)5>FJliRtSXMB%IFLZ-x9HrF{SfE6AXVvTG&La9tPh`q5RWaY3eY>9LjBB;^+FJz z_3XNRZ23UnI7;M`Wxq1xVWnDZ=MzrQU3~DPcNtcc85q>XBsT>{i!UZ-Y!(#HZ>kG? zvftQ04SV2inZJ6u5cqS$`udyVfVh_0v@qGuhZJW69(lTnxEBiSEA<|ifE6cButvfT zkbciWM2GmCZTV}a5uNBt{}^Y^ru_mcDmzo3ACD1j<8S9fh$l__nJtG2_zp;%e1QKU zjGivSX(ff)0vLe}MwNXp_KO}9K933%=qJ^Wc#+?Bmbki!XHR=(PECc}|L7*4N$fomu;}}Es$(SzQyLdY zW#d!hqW=1VGHyyH4r0n7Mf&uKh2e|p@D43cfap*0w->Ceey;(`9<ch4`iabsVH-LWKDYr_#)a-mYN9F?x zK51>8>}K@1Dj~pf%#A*Q=|7xSk9Br942kWwXYFrbb?fqN59o zUsn3YG^^HMw<=9i6>>{CQY_<U?>5CJmic^#sh>wK|_8E;+) zbbI}hzsd07QTM65NcZ}F_*K%ZRwUo`Nc4MIhxSQ@oDvu^+_eJ`I(`a z&Nav2`%tl6&iYQDDd{a76HgJVv`hux>*03r`KC0(iR0DEMNbh^W#?kBLV{m+!R|fm z@ukS{*natPrAX5cMh?O@uOuIllNDg8jpr)oC90=MzTHqz+yHlykB{%$j5k7!Bf_64 zuS+@EEI&nb?&BTtt5+Nk9Ao3U4@ZQR%QcwuL)>>x=&7IE_Kr0%cd|Px+rLb+JxhkF zgw2`tpXX^S{1H-NRlhEboFA#(UCHME<-Lk5kgR9_on*{fV`1@NW>nSW(eM1K<8=)G z?1a(HOXrMur=@b=+vV);T_B;J{KL7c+OLI21Om=)2|))w72|aqb2xQ;?55*8N(<_0 zdlV%lX#{^B^Ld11W;&n?gG@mIth~mBCBCjv+nprAqMznk>XKaoV9HcGK?C7o=Uh4j z6Y&foN6;|+8AjLPU)u+X)?6ee?#ZTHSvuJoyKb*JQ5IVX4`3Rf(h#wZo!iW4R+<={ z1cEGkemZ?}zrU>=el29S?q^h2Rim2a0QU?oAPgLWm~k+r?||-Jra;2sc0f#_x8B*~ zW;t10IZB})#TZ{E+wK#;0i2RWch&Qj*pwS?AK_~+0YpZlzoN5W>2~{ibsO_=MtIl> zvtufV2@Ev7bKY&59l~?s+-p6;k94-wZ0EX6@kM>jct&9i5U6!B4az~qBN?B_oZZgE zbtsd)jeQci&TPpN=zL;T(Y+P3n|Y0wYiKFO4l0yJ4`El-&}pX=U}T(VJy~n73dHet zQ7JPfQWU!VtGy=`9l(bjv|EU-MPK1xk!ld1mL?-JVCm0h(u++nT=NHx{sA6^Li0y10bK zed(%bZGNDs@Dg#y9_!?lc%SFew`OCbkR3ZH$r3#~KFu+$l<;)1@!rpE;{>6d9#g=~ zw%(5`t;?uN+$$p@+6OSuoRX4vk{6bB% z2A9(mB&i~C5|nZ&+UI)kIlbU?+zLf8+luaW zNW@POx+d&VtoInFj9O{WTrqW)A&8zyR`2HWG3#?Z{&)j&SY$^$|PyAgC0G%>OGJz zom#VH{p`cmT?G#f&!e74s>_82@aVGwXZ&GhqDo48$2KYqn%<}AinnW2SOu8sS0DfY z0fXQ3a+`r5U_&z_9&ST!h#|L;sWA^21m-d_-48A}AHn7Afho0L#$^j#H zjkx?1<;}mq000+I2>=E_cmUOMU~Xx!oIFTgRt^LN0J-X+Uxk1+B z2agX^iL|#TS7s;ABOq=wtxc^8_`EWeUw%Rz%}1IY)T4C?bzqeU{0MO_u6HV8dH8r} z#(Anvc!6LpSz0u-ABKcOL(J$aN%6EvBd;4R?TQP4?pQ^~!+=$SiW0Jh$4A`@jD-$m zM3_c+$d4L?H`OS^l)t*evNFras{v|F-bDRJVq`}b=W`cRY`f=#8ecEf-_t$=nHjfZ zkTN~T@OPy&ob@`D`MKXVlJ|ly_J{EnBmqS5-ddFU7reT5xG*@#6rQCHv`#m$FYgaUdzv(?ipyH-BN?u`Kt>IZh&mYU_sCDd%eMI zSQuV=_?bqeH}TwHLjRX|V6f5uluskarufX(_Jd!9ZTe{5v5b!t<(dGZ+IQ82l;jMY z?4;EAQgvmep7oYmkL*QPvYTiDryHAz#g(%nPcdFqOFb(-jUmUWhQM2Ww&b_hHniZi zZpP95&J8`7vJU_k4m&>Pf6(*aR)p5n0Tg7oA+jJI1qh(A3M$>@IwkDaCjjVe1Nkj%PDs|K3)v!tkNkv;|%KrL0%{!SS{vnfMh#8@CXi&iXYNcpt zJSKPI?qcc1%(t zRz>0H-&&9d0YLI{ZyEqeH-N#2asB;-VGNQ<{S0CKgl7HHmi?lp=(x9~Nw@Y|wJ(6= zYx@&G5VrOTU%0^Xvq!3)ye4hKeHb!~Q4tAO$D3oqX2BT#mk$1*zyYx(o)rizMN@~Y zLGNia0to09HPr!Rn#Qk)$6cMhK~7BtbDpP5#7o!m;uEl6i2=LV8NAdD!FWTXt4?8f zXd2;orRGZ}$Nc=5q8fnKPq}W3G?JWQVHsn%%H->zYM!@m^PXB-rw=vx)1Q636FD>N zxmTz{rr)Y7YBKDfKu;|AAN~B4uJ;3KmbN}52b{UWs5g@A`vOEpKU+_#pqFOl>=AuDuSTK_ix zyUnCH(W|&MQGh{F^?!G+|C95VFabIFXocCi7}fqEfo>P`OX1pM$PtCx?$KgaZR>{O zb+AM6bla?BRh)hn*>Dl7q7GTN4)&R)hxgEybF(x|WH#p+?hSAJe?A_VmzU2Fz{6|& zMnPr}ps5Lf*U*UD%#attWoT;1#{~p)fx#v){OB|MQcsfuO?Tb1NTmfLCeid4ubV3T zz8NUJQ_V{*X&{P*|0}iqpQs~QtKuKZsM4u>>$)KtF?GDzLmqQGLvebrZz6&rnWcCQ zQKkPc!~8cbRDrnwJaUjXN|$W_a7(|%mO6mEd>xpF2l&PovUM;Zxlwi!L2EVB70|IMAH@1}UCyss}Ud+ab!G}6P4e<;rv#{VB|M*SByVcxL$=WET7 z9c4hM0m|p9uyYOr4u{5@Q$v&&jCZ{WQ(h`nQxwkS1U5BLoO`yczWF2lI1;`)I=XRV zGlq)^i|xEijSZz>mSuBhWB-xQz7FXvb+;vvz6ggjN}@8b(Zo1ocDH%+ep-1hGYxXP zXg^RPqfIVC?EmsUD3GTCS`X!F1am3AF&|V~L0-NZQ1=$qAkepm=BkFub92j@xL4C$ z`#o;~Xvn8icWd3!u$%4YzL;LpQt({-eXWW_xk6TG#gvz4I8O8YEmH%4PEPgbmE^@th!k+j8X#=Qpy_ke3-`Y=bTZdjcBLQ;M0>-@m(_C_ zL`8n~@LW^}+Y82m_Q=2j+U*VElDO1TPW4$NjuLwdrTl$NnXt(+e8YFe)s5*3 zpJSbMUUU7)VyYf{O~*QHgNA>h1^})H$U@|#W#96gHwSr(lJ6X&*kKVW$`(DvRN_&14Rtt}Fhms1f1eKF=2DR3R(SInd5{bU2;qK96%@D?z}z53 zIUp1)&87H`#h3|A=&r}6f2<(cw?0%uQ0J@=*x-76ycLmuz);(eZJ}|64ATKeX;bqL zRC-{9{tGIyR`1@RQajJ=xu^E=@DKZ2g6Hy?&%bc)f>@9?Z}4^kdk~?9HC$a#=AmJQ zfp?hGsW`wiqP~7GQC5byyv)B{1@*VG>u9$ZVacvi@Clw{*|ui0k^&u6N20!F?5_}H z17Cx?@M1vry(GRPGeIL0VweenSX9V(a6)-fMzYngQ-x1g@)h5PG5fR|uiuD$lTM>! zYp3+uYBxWsjgMr2I-R&v-9TQ+>tdQBg?f-_g6?Nt_TJ1v}Kod0wx9$o;z z`0djM5JQlWDFAHD%>y(BfK9j!ArK%K!Uufgem)};m>a!ry9Kq6i4!X+KMESWNfNsn zYYN>WBOnJH+6kkYaM_CF*VX?dI5{wS{}tT-o!}I8-B&oq+(7{Dv3T3FCkTz0Xucery0Vh`p4Lu*A@Z-%#NXfF z>D?9*42wJh*S|3e05pODbx;r&mo&FDcOw{5BL`NLuLX10%QZl&<+uTmMkvtauBfW~ zl;p7X_;8isg2mzx7)<#LSorW`lr#o2oA0U;@NYxc^g+06s1wGcz6l9{>X6 z;pXDvhHyhnA;zW;ShAFgOf<>9G9cl|n#waFR#CEN}`|{E{XmFOc zpKKOk0b_SZuJHewNSuv0iQPNzgjv(3puq{V$8dUNaPXkO5C>2^shCiw=Ar$s`hp26 zH$E>9RD{UNN!QA8ae*OqP%Z$l4gh>he&3QlD6mTI%|3NtIc_=7+=yI>0qaNA6MUA~)lW~FiWuXCJWrD{QoQHuxP+t{w_VoI4Q7wFHgp6A zw!?;x@-RRJoU+f!^S@>5Yvg95wh4^(x%sW#_dRWP(^kTG;LAMcfjc6G@pwXD>!p^y zEDw>ohlY&L?o+G=XX@+y`H;Tio^{K{q}7LR+rC4CGnvqR^AM!1JRy!UMvZeaE&zbz zT}uQ~s5;!@j;J6?=$yh)y1RMzb7W6J%xZl%fu^+Q<3y|Gnuzb0QceLJ7zfn zd-l`JTr8NDAmfx)%C}O~!TH9_z`y{`sKL^kz-jlU&yfOzZPBd1T;FIoGhxGpP=HGK zisJF7!4z6K8{OJD_#{^PZ6)$0B8SaJqFnawR3n0IxaH1W>|mOQHGHhFfK6DW(NU&Y z!&*x6XWCYE%1^LIA_ZRQqgEk;Vro3yhUtZ~rQ=nvSV!(&9F?8G+1d7UuI`?)Tl<>F zyiefjgp)M6ktrAac#F_2`m-CC;%iZw1;tvBqp?TXCCAWAlYjJK*sc+1+we|*g<$J! z+6&UT{$VGafqPA$qO~Y(HKLR0xi@2P6oZ{% zM^Vg;vI=W@YmF!a2Y&zR>iP|s+#0ofehY}nb?R1h6~B3fSY38e_v4qOI82ju9v$`% zqqquf;Yy^`vz|0dQn6dKd9!Jc4%4<(u0v*L%Rm*j%*PGSqYitKS7T9;1WunH|MtkC zUGVz!Uoztb&cQ;24#WAD_Jo|_K77>9<^n>WOja8+!rUK8^n%WpvVZfOj|V)G1j$mh z>lW2m%jz9uz2d=~Cmt-c;Jat|#0a4U00EZ53)|&x?#JM7zcfC(}{mz{^*_|&{r2_889y?Kq(1B5b{o-7SlaLWqee2 zoLOF4?GuYMJ4e{Wklgghr%mPH2!_4A-Q7L^UriZ0D?-nkVmg6hV9+H%otWDMu=m{@~=zqa4l;LGUyST%For9i|R|%F71Vy|Bm?i?s*!51cD(Pt}b5fvtFF>|y}4~`_o)#CBw&ykN0{`R@c z$)gk&h*A#A8~}a$NkNjCkf@VXQ%Q-OuSUYZ`DCOGsoIqm7b~=QiDvi_y`~r=VqEs2 zbK<_Qu7exC8;foA@97OTq5h@Ei9R#;32Lf^>>@pg#&c6ykh<~PO!_nh`N}?2QNl6x zE7#XK#};qI>WCQw495WkcR4JWm~SS|7(U~oy1QPnC_At*4eMROj31W(4*aRVDyY4( zE7BciJ43V&b?BT_`80)NP(Rye3pdW4@@DI@+3vrq@V~F0CvTJ?)^@M|S{)Vycl^^J z(lBT8vs55l?)M;QVs~x9EUo(7v<+cvTp1*wL@p;@-ZkNEM6}_O>bL)`L2C+}d&Zc$ zt^FSe_KVFks-y&jx!TlCjK@F^&cq^?;BSDT{8w0c>OmR;v?S>dx#^xkua75CnOyw- z^9RGw?_HZKy0bNVtnn9BV4q9x%SgdW3EcU%OCVcN+%TMQvD85a_c{o2MJztH+m1ucv{&wd`G?-(mQs=pSOaHhUM~kMG&@M>fRoqtU)=MOS_O zSt?GDAFwd3F*@%km&=4I1buRXgZF1)Hl(UBu%-{pC&%jwa*8!IMF_6>k%S+~d{2BP zll&`kMwBy{_ci*FiKk9pZ=zk7vyK$s)L=(c4eIIxEEc5g_Tk{dsZ{?I(4}f3XC~6= zffuJg#C9baMU+{Q&G6(U4SpFHsW^R_q{6G^I?|R;PMT}K0bf{pO=|A9p#R+_*Fr+Y zzNhBnpScOv1pm;(MKaBCV=4MuwT$?gQ}aOS5ALKO{zhsswCf8uA5ZznHJ)HbRxmFL zEi$P80}Tm6KC@CEE(tN)ucsNCU`)wF4D`EzK7bM%%o87jz=EWMHnmj(E6&k;JQ}fv z7%O;jJUFU)lSWtRyer#2I#Bt*s&hkPTwR{w@zAbHcOzYw;h~qLa-L%A(Z?!3{?M@Z z0f%4Uhjt#aEryMSR0#MPK-apTO#{%aaVB7GIUFFTfpblhyfc&h6C4oGX~%;4nD#f3 zgSXJwQHSgy!A8_19^M;c20Nqso}tY4OmllSquSUha&xl8`RJ*uJ=4Cp5?(5)eQ4^o zf04wJkx=aL!z3BaPbGEplbk+&Q0CHj6{`N>pD971Ozo(!Z3CZmMcr+%xqs)zkt_-i zP2Movl+Om4SLs)Igw}+T*y`|;Ekp{TypT8?1GE!flKtOzE# zy?34r=eB74)sUvPdShn2VJs`SDfa*)6>X9tFY4yvp=ro~$>SMN*IfJql(OEGXEoI~*p;^>;d`o1Mxx=L0wN82efZpgSRj_eH zR_@^;v=v#l#z_dTw>m$Bs<#Ruus#&!U8ZUJy0k8^_L`JEHt8onb#VQ;vuFaLpaPHT z*G#e7Hmh`k6;6UI$HvZE#Bd+H7m`Hp#HA9ihjWCsv?J}~zxX|UP{TY+N|gBanLIpH zQmepuVvNiNID@FjYi-NX8;^xQzAAA)a;PJv`rP3H!!{q)u=S)boWeTO8T!Uk?drDH zTay3qRCrW$U7YbqN0N1p9UL>!bYSZzPZWHPkl6Y%4UJWT=>z54Gr!K%mBhL@f&p@R zhVJRnqc*|IQK)a?1#cM>ZG}kzdaX0bPn|tATKVb7ur~3WtwGyyCRr$R1WVF4DKf%o zsN{ATmrOGq9U(z7+D9{EWq>Auj_jcOZsew#YAi5o3h^(=DY9>u!NP;~QIKb3jSHTP z7fabrKnhk<;2&mrG(uS=n?zQE`Z1*-4kC-Px`IeLS{XIQNpXL8^4TJwQuhV4qQ^9m z?&qEJ^9khX@Zx6TtanEwn~0*e8s7t1I@W2kX954YIZ9f)SECP;3rE`@Tl6!2?wL`y ztfe3W86Wir>^n^S7y1B1f0p45^40FCkDf}x)CPN;qDk8byfSUd$_|Cwcvb2xOePtg z4~6!7t4>5ag|;&bXyyyjj{9-pqvT&!NNpa2=4D;C^MJ%s)$Y6~A@r4ZOV#wc)p<%bbnf7ssE zc|25CB6A7nEk*TFM(F!`KVREqQX+*x|5Xrw3{MF=W^3iD=Tq__YZI@)7TRh9Ja*uHj(`yyn9F(dbx`xN^jT-F}51%*1JVHL?k{! zZa{>6IJlqmkEZq!p-;b3e6Xi zj;(MW*ll597}c`WJP_bwl(IBhC8K|sJ|!rit?}#E?t9_0BFb&BX_oev8+%Meamhra zT#pS>Kh!SL?gkSUlj54kD-z|PSp6aL5L3ct6P{{2*)(T*5B$oaFl<;ojneei+tZ=( zMGQd{>J&`4UgTYQ8?ft3Q;V+~-m0EY+qLM%LeyYh&DGV`U!;V`h-k?e^bS;qMa_oL zBoBS2nb#DkO}Tv;8Ovf%jz;Db3CJSZxV*i^qfCZWlrm`m`{MnHQ6;?4mC_BxT`w?D zM8^;*jr@V4YYZ|Ao6xC>glOa<05C9c>9V-xpY*3?t1Z^4|1p{+CPC$nN|xvI;af26 z$p+YFUZSj?uS=_8Xvg(yBa%i@G;!!0w~@`g5|egWCMriS?{JMn@2KlQ<5_EZYmB=6 z^~ak-d3)xo`CsL0sJ$bdm1AK-)xJ=T$C>Cyvg!ur;Us_wW5sGNA+0J&pv`1jvQdvg z9S0g4-knli*!)>uF^h%@#YR=;IU-B{n)0jlJfvZQ(eAuvifTRohqFa|fIFe{=aM-1 zYC>3KM}*30nvq||!&Cq%_aaaHK2lMJ^BdTFuDjQJ#vr8M+ImT_o+O{(!ILZnUUrc6 z&{XuMo@NWH{Zqq<-@>gAVYdblkk4eFyTRErE;DxcFt^X+o8&LGW@ zwLjpqMhS1ScUqJbkr&ul4I;Yw9Bb8(Xq47Y6~)q*AoqSq10^2)(wj^cR+hN6f(k)z z{fpxI@~&&FWKR6WBvH;GA4hOlRF7N6`DQ|Jk5_?O8pX2hh>kZWlQZ!MRn=J14~jxw ztX_}xKP7KBVjKEPlvpWL)v+oB()d6D&op^f=Vl9^l>Od=nLQWp_6JAXzl6VP6vl8S z#cs9`rDuiY{?`8Poh69vss6ha_br%*n>$e@sYbGQGQqU+(|YD-pd6kahvD<}!7$xY z#3FpDjrJa#h8_(bRu_&5^_(?q{9;w8Cu7P-cAF1t0%$C1yBfqoCTS7WT!{!HQR=Ft z2;%lJ>7H&sOC#q$wcSf=@sIC=poWx^ZYTU7YZmJ_w3ff^;2w>uhb>8&+lTA~yVB1S zQ1Z?AOX~lY9$0xkes=Bh`|`-EKXJi7s!Id8eM)h!fB8K+cOH4(OCrD{=jY7V3kPki zfBA!RZ(X*xvTWoyE+3+7$dCT_d3RNCqF{H4M}-ts^7Zqn*%x;iNq>bsp}!eF+DNh* z^S6ZCGewR8z$MI?VYu6D{(CeA?6$!6p?B^X$C|c^f1ube8BgJsr3^rnJ_Wc!sX%eG zV`{Yw=i?H4bxmt8`Onv~mE2dV z$BhJpvX_G?hs>lxe5v%ZJ8OLfMCyG-JYH|&A=Wdji%*_6hSBo5b|%~0Ul46wx=PMf zcE;;PT6uTqWKf0-QuMT?Nz2Y0eLrV?@^yMzM(xP8tc~uqEuO2BP*S^VJPTuqwnk8@ zv$SzeMaj;mQNt_-AaF**S--DL%L6DS=Q!V&Oqaf@vJM9p25bp~uMlSsf2{MZidet@ zD#JFTM827)ODe=d8WB*f4u&{ee4pZ2w4l$9511%J5N15$^6juDSF=yXq4!>MM5O6p zt&%PTqhDCv-J@N>UY7q=@Bct{#oDbtvt6d3{>SFB$qU-4L%Hv~Z*|r_Gtz%NYMwoS z(c+p}%^rhx)2Q2UFg0haU9xq@9$+lT^0dr_tUAVvjZ|oP(6CS0Vpe3GqA&p&dybxR z;n)3Q(P}pFC)u++g-HFZSgYJ!NpAW2g9wdXPOaZpp7Nyr#Z9&qv9to|c&nps`c#XL zma61JT$R`={amh0O2vufSt22nbIfSmim@!S#a)T0jcDpaW@G9(-xyCgMU@dZcpXzd zZb?rU*LT;fX6R>V5(+55A%PqMHr%5cO2TcKD*yDw|LzH*W)b_iea>dvj72HXIl+L zOOuDwH4}yL$7>)rME_byd-+!6XP8Bqb#cXcxv%fq!WhD-Ft%FuT+3dhuY9H9{Wyfm zw}Vw3b1xQ&)gOU}QE3?f$DWIEgEfIxm@!zV*?4|Vrg5LTUZz=yj^+%dR$D50UF5sJw|OjlFzqj&_`1-e4au8nk*>wCja>Mk z)Ja2wipf9j;ya~^NQ|>o-@550VY^B<*OQI6y^Bzf&ma~no4whYzcndWDF%N>!{Va zN%%l2KT-ZtTLIR?;RRA4?3fc;yOl5SdhtK>4PSj}GSCVuvw4Y4r=Hj$A?@$rVY2!RL_eHD2}3DkC0 z#eo^Piuhh$Ce#>YDuS~Y;&3#}*m2cBv1jJ!A->e_nemCUTD(A7`m)bC@7M;u72>HT zSOcYWOiMmd@9Z8C#$}*&!Y7NJ?|)~n{Z{qEA5|h;e#pyGEXGq0 zPRz;=tq()#wfw-ApDJc^n4*P9d2hX5$qyGZy}aJos*g|14UC1xUb(DtEGUsllc?#mUvSkes2v<2-It->r*# zyCf?}_+TFZAP%0`QU|#Do7g%1={9i+v*2c93UeK@8|#wP>>@1>d48;y_`$1rMw?~v zAoyH-8u10sK6kq+zp!sVE1nMXbUsPxXGevR??jT(`4~V4d~ODxhtP08k%T)wn02~2 zHVmwo4*Vfj-5~JkQHxD#f1VIvxWQ9$(!fZ`;Qy$w+&$RL%|7x)&j2n!_)BA^5wTnm zWm0r#f#v81gP;`D^DbJssqgxox>nD(Aa*knxml*S^@_=lzfT+k&jTW3V~~_p1iO5k zz#Kk(ffu?AM=<(7k$PKV6ekeE%xLFwWU_0baKHbx%yzVONfvrM^BFk0m2dx4ls8vp zM97p%B(WF6ZB;tRpNppImA0wL$8tHc1Qynv&vk4nmQ~S+sIFkjTUE{9Q71|ydBr>6 zpNW-MiRpcv8B!@qpF8kJR>hgV!{3DE$8{#tJ7mE zc1L`Fu3b890&i5>F~)iOh3ltLVD-PgE$z-ko;Vq5*mUuk@6L3-%3Q-s6Moh%p}#tYAv9 zOS4CMjRjV#7(lq&KCz*VIzA?4$Hx+mM5`ag$7c0fH-WxQql_rbEj8nZ9Bda2Ht`&o zy)>mGEJIq;lc4C4pEAEV2W z+940(+m6NQPqG?J?O*hqdbB)Z2sM&wZp9<%Ej3QR!71dMU8@{OA4J_kKg7t~Zsq-o znrzBPnTRTyw9hr&YC~5X(k^iM1Vc_8#ki?EnNM-oKX4fna74?tzKIka@CD`$Xajdl zZF#c@zx3{Mw-KcdNvjAC;;(2zWrz3jO@pvask?bQ3dVzFR!oKeJV`rgqdj6<$B=6M z>(|6V6IPaZ?fMovjBRQ}P=1=;5QC*-7mAL@8e5FT#5WsUBot98SThU8-JGvwgVVg; zoB-D*RRqye_Vi}L_u)8Jv;akupFzXo;Tjv6yB{l6vVHGuLbWAm1r3ZA;U}=WTn_3D zEQeGKj_^@_z&=QPSNX$;Fo;0Di;aQX3SIE}zN>|XZ7I57#7>tRlg~U_&)h_lbaN$W zkV#*^I~?jTScoLqv>xkza8(FJLh@AEU&~K2C?AA%CbY%IIEhTAsidDYZJ0D> ztXh^P1L)PaCF0#fLH$=5EEj*@RQ*EqYHg!3{Cn5!%U@xlO?TT!B!?&bMI6;=?XLlCPg4fRl zi(F?4E?u|CkPLHN9V%~1h|$2V{j4WzDjj{E&7wO&I<+Y%0l>rKB%V#jeTG~uOBww= zd@%$h&C>7GyBao4wxJ;dpNp?&)Nd#s)Gw($7anX`VoIyjuQqfv;&c4fB3a*XM8<=l zey~naNq#a<=k=|oIaE9#J67lkr<3?dJN+FpoX%9CCG#gER)P#!YxtR(^~*cp9Wh-BwHtH4S)42!TM;J(JCRkWXi}Td<`XuDT<903a=6kipm{3N7>l9oP zqKfV}*FUstkv2Iq4PoR}S1O0m%>v@sFW(WoEp;cxa7<7l81P5{e_7%7AT~E7b<xb&otIw*_UA3$BuG^7?N01njksb>)y5LgtCJj(Rr+k_CYV$E3 z>$W5#ZS+~%vfj$_x%zDVd4T!4<9tcXq_*DG@IX(1`vXg@IZYVF0HfVvZ%=?rnUOK4 z<&G2$4W%rHtKy|S#-sfUjMdu$xnP??p9Tej-Dvi-@^VSYW??`s(=Jp(IBe>>|0szv9V%92U{mVuO*hm%7m$GtNYup)dUW$9*A)lt;nADn#JS#Dz7d18 z|J3iNWD4l9oNOp#9lLXPv%NgMlT$U{fB;r;3oT) zCL3@Q)Z9c*8xl|(3M3B3@UpfI_QK3E0vs>t+e!)dO(GYA1w{%y zTpXUU^MYFPmTAZS?5<>cRs~pSnWhilWdl%`-fnpcaG5Ed79Z{K_l9HjSR1Q7k&8)I z6v0K@cG?!47`U76UkOQU@=C$mS)k7>=niGCVgE87BSmOU7c`CL3)ZkQ9fB&hf~a5^ zW_-yngixH_fXp0^*4mRfw|eU>G@lDQsvQstyrISf=QZ#CxqCact(3uB3w}$JJIgTS zgix!j=dX5&pc)=mArD*nAx?CS5ty(%pWlMyY@8Lek!h8IcPy-R6#CmX#G`r6tQw|uyMH<(HPUV}PiVwcnE`JgChg%)# z9X3CSj&sk+Z|x?Ha=z#-ku1Ls;<3XXBtZ_WqLEtm4V$I(?SrxH(^FeppZ1`vA)k#6 z=M+1=3JT$=yKSSNDDNVddn2|k1oHl`&eE2*WZ7M`E+3a|(P!~@0y4Z^B74^6K3&>S z48$AnPKO!g6-!-vvyhc;ymvnxJToQ)EL}O@!W>%)$|k19>G#O|Zqz*6lwA$C$8*-- z9xncVyd<={vOYH5pT-7EYpyE4l=Z}-juJto#|SeKH7{3+p&>cuJp+S}rV2#6aA{vZ z`yLkBy0pH$yg?ka5aKwC3I}A~&?^@Du@fM<6r|%~4OiMeMAoLFnc0I`XYbEb4Nb5D zAw%N(#|}>AuA8|NKliMdp9wz1;juSF7<3}}bAMfQhQ7S57ZFL?NiWrYU30ByKlqU8 zH|Cc4NiI&d|HKt*zv;ZQzqY&lg*Ec|dOET86n<7lP$f^$IF?EO%s|4yh~^H`k8Mux z)E5UX%~Wh8X)w*DQ(@uVx=*OSarHW&-LaNIoXm-JJd-s5A3pI*JByDZaxk^+EDj#u zdC68jiy4!nZVM^O)nkzn+sNo4mN2&IBN_~)uq_W1{MH-ZRpPR!TXBmA!)l&AIuNoe#FNwrK8zdx zH_MTD55$qz56nG`eG32Z*ah()!a7ZSh)gM$QIH73Z;aJMEmu{V|XARTLKT>jDAEIw+^KnM`;^!yL`6+?J5t7Rzx`; z>d#seCp@Fy8@~{6VxA23g#T9c+}OhL^1r@mR>eGwj(y5hHvBcAcqwN)Xp=ma^!Np! z422g))jrh1vpy;4r^Lw$UCq8`Hsx_WO#|IL0_*^6aq-#P@q$P#ZF?F{n)s zp+$oH%7P+W0amlqD*vqZvO;g-XqI?S^vxXNXOf_U1weYo*1tLEJ0TO{x*4>IxT-7R z-xi}#Gc}@%4LRn)42oiz8U2m)J$1){9v?NY$d(g)H+%rn0kYN3&-jakCS5aYv za+5YlmF9|q>8RI$dQIx{kY?pLh7bX2FO31|g?)P||MN8YPi@{%St@0i>5LPe!y?EN6rLQaN<=b0nL8L%Y)sQT$r_@%0soFPR26c-0;DvkvSX zylAi=8v6b0i2#)*96B2t=1;zOBBzWHrmj36NsclB0>c6+V-oi@h06g+q#{2#}-2-Rw|K-0G(xVa4d~ zOOA@9^$Z~4Gr#Zt5CPgN#t7CMZvp=B0SJNcw+f$75SKnVv%1mSXk8IOM1w4Kj0{%) zVk7Nm`=1GKt1DK%ym38-2Edui^Dye<0&(m7T8K2aD;0~14rq!+tH&O-SHDh$-Z7`7 z2b#8mEu(4;PmVQzti|#>TE}~_x47_jd~oL7oow*U!f;`)xuNZKgex)Mim0lzGQl61gXb7S{hQW_(+=d3g zwti0=Ms#n4%I8V$6?#%foS(;CW^9}JA-!Q)Lvg&%S(!`=ko{Q#a9Ye(H~vGSzUQ5r z`A@gqY0$IGefEUD(I@Y#DdqfdB@>HG2M*syT@r!j;eDmIs4o35uEWI?QTG1s2kv4S z2bW9-ISQM1FP^v%lWphe+*d3Ew$$~r@=+u6H%X9tye8Dp|7?&_+5{7VEIfZCLWX)h zG*l`rZBYwW;P(r%0|`hKI1FynB*Hhmr0rpgH)8*lm1PhmhOU&|@5V2%1u9t%4z=te zMhfQqx5vPwHFy=Th31@Iei8fiGWA5)N$r8hd4!u$!hiVMm2*y8Tl=cC5pjRe)8&l2QeZ!U@KXx3`0{^YgtR%?89<-(^n2a3#R2IG`&7;-f2g!rQBDCQN`e%N?3s z(C&k&x!Tpz2|MMDH{qg^pmlRuI~^BH2(0+y)wF{P{JyGXEyT1qU@q? zC(f99dH(4Yx>(S_)u^if1iD8*&g`phES!I$#8mKIDqNx7fgS~5GY2NX+JWNO-XmJ`pX2P#rjgX!I zPM+t`JiGi^_dYVNZS5QvYG1G- znF(WFjE5i~en(5CVL?1SI8F=Szc_;ENQE=Da_s@<7@e71uxj(?X)aE%+RhXU6J%mlM~R;m7{*tX25WB59kFH{@YOC&-f z9Fbr_sz&RFUR7$fZB9&gp^5EJZMAP`N&iIo7vQ? zS9Nx8pc{Y7=NJ(L*;5SPC)e>_-;QOJ$W8yj{yYriv@==O-#LcV+G&N=7YV5o8z9Q& zgrl98_=zvB(fNlj6gJ!i?xPz(V;C&kbGvxQW#{ z!xhqXOo8VU8S3ylR>6}K`8mRs_(lH+xEs139KFUQPs-23%iD|Q_V5grxlL`%iDg4; z+M;T}pUCcSIytJzw*xPRHIf+bMFb^fmb;><7+K@AYJ4PtXHXNIaMaeZ!r9U-VzJ4v ziL^0gW~+*bO7tsGJ%_h83R7JaEo^Knkb!$yg^1LtwW)?)g6c7!4fRZfM7ww}P6%g{ z5wpBV`hLIyztIL!quZz#%_mUc^n@5{Y{VN@*EvjN9OeFjhvJR`BaY_xcma$0%7dAg z((Iw5pj28m>xqz%;W^NtJiP@vg!lA@OK2)Ctp>-9Bf2R1-mb^+{iK}r!R%VX(&8e$ zAPzp!NOH(z1)XR_=4F)ZdF@h&uem?|Zs_pfhz0-mxo+*HV@7e{+LHVqp?_Wu%ScZQ zf?;RLJ^Dot3OWkfSY@rS=^WBd^T&m>G#E}FKD)J6j({LZ#lccdS_XJuIdm+8SU}-5 zbC|K@GYN|Je&cobQvuSR>twkvVV5YeMLvi*gON!3TWq*_ET4)5sPrHL4EbU(9|p-U z5u8kDbFlKkb+yCQ8am8IupUorMuZq@OOJ-;g9tDsgD}K#8L5C6yXKGVW`P(1-2~e4 zS6ChVKNBOd8c>qRsH*uwiK)tlUipkRh;j1hp0z3B0lTRof10oT?6a$WRKcT@@&@*x zofv9Gqv|LuV(R|ToEPlH?d{}jbz;3EV!e*(UqCRFw#(QOPW|_o9kM02`HhoqaIFO@ zA&mZ@G$5p^=&$@kdJ+X$-HQ@Ne26{EPnsJ_$^K6ci{;VR{|9LUN8Bwo9gx%$om6UI zBv43_ofVcVn?rxt2&^`tp)Z@;RCoc2L*}1GaRX&$o`aHf6{-*kj-Xskp@n4rA!=A) z2Krr3+A>mqE4o;LAnOPfV72x&Rw;nDxW%}fJ_C+VkmC0JaqL3H8as7BXS!MeS(?@fab&x=+x_0^oR?6 zZ!2FyF)0bI=<6wzFm)y7;hy$NfaxDg?-=OC>HlFe1?X{U&TA`B34PEKh3defZc|AX zEw8!JC)uuDZ`XJ)xP9XHTA>pLJvUWl)%!9dE4PdL33_q&L+BU85zoY)0&ovx(bXyz ztt$bUs-j9NiU|d=h;;|e*`2&7nAuTKZbBazY&i`**$wo$VMwxpaQ^pxQ^gTyi{>O+ z#Et|H01om#w|R$HcVqgCpw2$gzN8%3PzMP0Qu2bbL>*?RN$AUplbQ>>Kp>cP%It&d^<9lxj9Z9&^e0Hta&KN36$?3n#cKTNO+XLVZJp{ z90Ixh$yq1K#7y{|#ykQ8^O0c{6!MPjI`wJ(QS*_4Oje)&G#DhK{3n}sL#`XksM`D& z8uF}6zXKErRCEM0+d4FJk$Fc(99$Hdc0{|+P_*;BKbLE(u>Yz%hz-HN31~EM3kB@K zyMr&X#-7F8;l&wJp2k`y{Op&(04&Bn0;2dM;X@Eqtp_~D0=E?8e2|&G^Z95s;c77M zEs>$#xJ_u8TvVyK?UH};zWJj{u)!~YpJLNcU&L{4dU0z?HCK_ajKnC+Xn%ULNbYCS z2|^d7bhAK7VvT(P=L*2s(AfrBe^Xip02h|A-Qtl@LJe#zHGhR82<{n1qE*XuW&GV` zY_Dq<2~wDD5Pko{*I471wXtRubihWm8E@+tAQf}Z#O)Mgi+<2vSkJJJ0~h!_6VqWC&^!bwNH0`oYZ}l{{ioUMgYU27L2*A1f5CG14y9p6Z973izST&4txo(0 zlHFy^Bx!|9_xsWL5O}{rYNO89B1?`EW#@-JQ~&_QqO$g|@IM#@lXK+dZ@Q7Q)U>z@ z^h_PWcLlCd%W!y65Jwa5e}J)1sV7WFQ2z=ebQc|jp>dAc_UuGGX&iq!mgN-PkW6nKe2J>TzKc0y&FQk$%jTi=)E|jpwnaL>siI}`*_?e z_9_}>fk|&1pKG*KSrpBgtff95<&uT_B_^9VC|iVOtOw#K1g(H4TJ9Hy{MUu|6h*{D zx`S)jOr&!&mp(vdaR7&Mk(gO*00A3j0ZOzSt)&^%jo=?bDj`>ok`c==a%_6*GdL&S zKP)#>s$FO5^tJZnLxF8$A33V1u97`EiZPQDNL)3Cc2Y~=@a4?RfU#$opC|*dcTw(f zG%csY!h{Uo{zAz7cmpycaqZ3OK}JZX;z+k5ciJjk$*VHu7bTz9AmXOj{dnIBf#^o z;+?NfA+Rcd0wY>11B?|)KoIHA*bqT3ao8x>V9uwX1!`&c`dIiL*}MkPT`|5|FBPHi z!a6hUX}zPUJf5TSVh?aq(4&S1fNO{8ORsl&9v=Fd*`8DQD|A7jWjfb^NxwDpvQy?7 z9~GQF$6||XU1}z9%`d$goXiq&zYIrZPG6U6n4?tD*I%ZDwBz0^Bb1gBa{?p#AI=DC z2J=rmV*6VVx__VkU8@z!D>&I}j3*HF7#Iy<_p_6Vv|ZB*%M@HTWg6svD3*?8lUV6b zM@4vR$tGZo*5D61yL0qE{LU4om`G#JVxd*37cnCOHo^x$E&CgE=ZO{e0=0yhvRkUX zV;Q)o1r^xPy-qj=K;(CPlnR{&{`#h7<5Rb(qp=h>tHN&TS6w%l1xl&^5WE?j0FAb% z5AKtapmPLQjcac$WANKTp$+2rH77LKz*|+y9HgQ0XvzS zga|iN!z*y`V-YaFwi_xY>L~>tiq7`WNCU8sJXg&yQXUC!6^XS7Z`s&uNm)6DQQlFV zT`V-lK`CdRr7EUK6f6e4RVbPPUaM3a(aR;wMVNeSjfo24UW+6q3$yUIo16eK!w(|x zvyB5BRRJcv;Gb>}?oYc_r9Ta{7aEl#l{srygCvJD+Ti zM<7Bk6-Psre<2VRWEEJnKB7ZTz`=#tpX+pPY zlKudo*ZxFP7_p265m#RL3F9wrkQ>aP;OOHj`tzRR0Xj_XC^rbV=>zwa3p}^qB;47e za53DaHSaxUD~z;loerB61WIz89CJ5WGp{;1uI_pq9wG-9;*&Xu`Xk0;yhu$20Sy1R zN~~{g5A$~=l-Y(cayO`LKR8p@Eot-X3^#b~h+9J+o zEwe?8-_hMV>93aYZ(vZ^#C6tvT*nbGI~XXQauyb?Fib1MXj&A{L#L&_vWaw_5PDpb zJw%-dQEyURJ2L({@t;mjO&oGOYj3Mda6|y>M2Lkt9HCm#aOXB~KEVF4Z^fWJPD}FB z834cyys@Iexr^W&dL}``9Y~MM@wJN_CAXWZNVr)Jy}^jT$F4fhGEJVFK6VffHl{5E z9zge}?{!R(QL$MYg^Keu*y`TAhpOnUNxMp)pnAl-0h>B9k&F#jvsk7ZaYtu*3_p=6*=3NRQym)SHwox`kw;)rUBhj?e7@~FYd}lsl<1Vy? z9K;Bn2%OXi@j*2uiT)3o1OICfUS4ZzA zT{Ci+yJw+Ix0|H+FXbgu8WB}3k`6>ox1@WHJgw(ln0sfUQww~PI?=RsQ(1c&r!^@; z=<@|)(`l87kjR|RWNAiOP^QlgM;J-Kn{$6pTq>X|$A2H}-KxMs4nbPIM(2~yu$$NrquK!*-cz^t8s?519I6p_;;$Fd4LzRTUBx>O7%pRs^6S&IDfHb) z&Iin30xiwKsn9t{BQ7Y#?#{TqFHC7|Nj!d6u+f?WxW0>5u^jT3qoWTc98)tUc<~I2 zkMA5NM5Bx$%|%0->fvvq(BW zsw(2)+^5TIVx!Z8JH}bkLd7B`8EefSgwHo`3~l&t;Vp?bO6s68GbIQ-YX=iyN0QxM zLfAg>M9_NCl)<#d9dUj52r;*yBvBc~@p|Amkz+wC>g=LWxLf#U&7(gZxMmLU|BmNZ zI(1s7Ul6QSc-O9UrhomFE2{j?m$)-Ccj;Cyz6EY3dOSD(RDl!GUo-CPy!EN|$gef@ z1_xH1Q}|!qAKt+U=OS4o12dT^7Gz$P1+6I+643<9OHNQ zw@lC0$U12?eO=y%eKu(AVIbvSbF!@JI`CO-AoO6U?3lrz_Z!aqJYD$(FbO>ecemb9 zT8~&tusYOjEubDCU0;e7E?D;^7x)jvW4@d);lCr0k1aC`%gszUrrtT=UuP*4&E5kv-Nure-Xa;vgqg+ z7t_1=!Ji(Yxl%M;^fP8~vLFn}tmn&Y2lL%-dQtaj#E~Uq^Pr_i_<%Ba z^cHY<{?)#&12M+4)%iN;S@%g}h!qS|_K`F6;q0_r8AJhw6!g`hRbL8TnEV1dDj;Dv z9Ualw*HvTHvGl}y+GqXK(AYO+aC_^R7z~W0o!yoXACte0LOJ`AoijsOA@8wF#zF2lR}AdE5ewCqDKwO}_^`y? zhjr749xm!`!G7|?af7^~vj<_VWrhCwHa{HtHpl*td6fEck$UY0Px1&3p^tvhJz-Wn z!M_`a>HvW(7Bzw_X@1CI-Bm3wPt^;;h^&F{iv%0^0Y6iNV9<}i7shT+xgd35Rsabm zTit#a2#loW@kccnW#ve|C_=_bWJ}l&g5)2THwkOUjqzLrn*4g^gHJj8@Wxa!yXJ%2Q|E-Emse3+VK%Aq#+0W z^Owk$uCG#89s>DIjNo7|e=qevh3Zj7Qxh+Z&-)KMHOt>#XgzDFANDfg-V{lBiFmX- zcG}ohVH-Bo7x3_gx7MfD#rtdWQ-w*-=l;dC4f}H2$gQoSga32>WuU!<-^U^vX>8}R zFYA)oO4!C(Sf;Wn zitqW7%la@;UZqPn*uG27xhpDTJ^8J{{;lDOeQDrPjc-LPbF_`=&HblQgeUK4dmrA= zv)eZWAVYE0>Xr0R5-)056(I8qs$t=CZLGcl-rCrlVo9m8BBH94qYz73O2a0J@u8R` zUG(zcMbEa9Uw@kEEI6S3-1sCX(SxK>-arNm>(73;WTjkTg;A2Z=Uda0cfFW{$%Fh5 zaF-x}f1k6nB+kcFqa-n9{#mE<%s5e_oQ1v}!7xJobl;+hVUZ)Gg7e0TJFp^9utC<( zwe;XjF{yY!K@)1~GMs#`{aweEq7sLUFKS^B`OxV}B#bYMp>~>*ZPEa9Q^N?S>tBvO zJl|b+o(e;>!*8>$WbBC;o+WXXs+oa78W!9~f{75ycynCZWS0(4cBfWunoFIyHn-KW zzZL7rc{Vn0?ps~9ec>U2Qid?VGC7w`KNJ|r#KG;NnN!qAP~+SDxq56gCS2)vFA2fO zvh%Uw2Jp@?WB*1%10`DoCN~mI>@n%-2_|uhv-%41=5*t)$OX~1gn1jKv9~|*sOPml zNbOd5$|JUH;2a3CRZcW2XuXt%jUSr!0OgXlWobC!;iCZ0IvH~!H+F_FGzLhG8@Usf z!NO=msTJgD2bJg69t4<%{$}}O$e7AUpr3sjQp<$ejOI#J&r&F${#NimIu%1vdt|3#s*^n7IrX$l z{8&nZ*1j14w>L`Go0R;gsiUGgZr4O|dv~$tqEhb?_vo^z36dK`R|7)5E1f51#H>h~Llo>d_6u(sMToObJuHW_f zYEF9V?@t)&3n0iwRgM-CGfzH%q)bmp*pR(OX}@_Fz1ezlX8}~U3E_=>IYc@t^ZI<; zGN=&-uq^xSpvd$zv1DR*&8r@x$Jw9r=%%x#WpeZ3yLsL>pN z#NJrbg^m-NRCMK|zJoOS$rOhM2+5rkjPRm=Iv$!QwOruy6jgged1d zM4l>`k1B@5hU73QXuKv=AomjM2zcg%gkrfP>aUW0p140?vQ99<{ap&aU%`?J9pctw zyRY>r4(G9!^rDr$MEuh{FA(ow4R8yDo*`D7cS9i50=(-h<+%vyK(I0nNE$1EBr*9( zQg2_9Mf&kcl5yZpB4Hq8?UayeB2&ffi25RKfd2i#P#xo?`F{Sfa8O$-H3=sum$5?6 zbR;jpp&+kHa6ygQq;k~A<60q~75y8SE4VQFj+H=aCZQLkKt%$GLixMnms)gx3_riP~j#E_HmRg6yGxAeh zauuC8>@KdrZ{Ik=CvX*mVR^qbD5*dR1f{qWp_m~TbCKMw*pX&CIH@RlLI)*1olYS( z-;V72Z!a`typV!yu76MKH)l+$jdGiwQA?MIF6=B(EuiE!p&1144g*K}i&U9J06A#a zKp3lDYcLTFYQdAn5KqEv~>I$Y<(w==|0fQSCKSc;{r*W2l1RK zqV0E2AXYc46Nn?B3YESzx;dwL1rfa`bjS3C8)LY)k#jN#Q|e}5E_qyR*bbPOL9B2b zSD;h;B+??~XR51&PWFtLGY3#wpdSw1wiUFjosistQ1ES%XeK3t4BQKuw<+i+1TGOy z+NIRSaE`k3diC)?UxysG(Rm)+=|h+&;qGVWC2PxhC=OoedJ%ybxL-0LtNFjvn9Y}+ zlk-I-Ddsd1Y(P$lMAo>@0-g5B0uv2{BrlWTf4OU^lpGxg1fMti&($cTD2p}2>m$5G zkDk=d(c%1i{Kd2*)k@rGwf{`K$dVSmBOjiitnuX(inlu>>-^a$7Ez1U4ic>x zRIFzhMuWi!#P0o2yN+B=I82O?HU3%Cqhx!~ly9cvhZLMx zbQt&|)p9Rk0DPvf-4t*bf~cdy-?z16M+sxcSbW@rgKOUEXiB(|{0Tptha%c~<>Kv; zf4>pab~NhdR4Za9C%E&Gl$Lb8sGxZ03Haxo7-wX@vf%*z#2Nu;ZQ;ZuA5U5QpT;lz zeyc?pPw0PZYgq6<4h)F0;o{|r5E0?Zg(B_(`F+5d*zw-T6FOainlAD7Z!m)}uCkaCFQt33gU;g{;YCS<;>%mUhrsSRjJauK1p?r$R`XlW;rk#^%Teh4S_V zvA1nfp&T%fzHxuZ85&SrfotCW_A}ovYlEA2MG6K&aRQ0(3i{uJP7m++n@!n47#G)! zZ`G;Y05C0WZFClRcJJ3T1dwka$@&5P-_#<6iNly3&&fLqqviJfNr!s%VA_M>dGvCf z1+u!hE3nNa{^sTX+h|=T9Qk+44mXCo`|FWcY=ihN(m}h!BGQ2(Bg_*@D?|xYLv&w< zg}6Hh2WDw<8k1s~%oMzV@EA%esf_mDBzCpJqc(i#Gk|J?#CZu)VM}E#l7}VyHogvMbQT+y7?vf4A99351&Kdq(1~|K8a6jndp~p${UQjbn3C*fOc19qf;f z(qgkhN|ekVqBH@)$$Ed{Y&Ub90WvB9$zKp;5Rv`B-1+_lslfTL@!dEBS+Z&ycqc|T z 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

    9=o=@S6W*>`s-(zXqsv0npSQxIwyF$! zAQFx+P`qqSK4xO;iprLWC9{+oqPA2~U##HA11}E7JhVIS^kzZllfhBj7z{o4)Kr3k z6A3`*1Ri|{F;X#s{=iTG_a(GnHS+veci@1*^DY8!2FT%#JSL6L2O5nmp!VOMr_skD zgilhq@g|@sE{Uf81 zPv{*IF7bzC

    Vovz`T)T`;Ya#$Z0SHa|PfeI+1{6}s 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

    =mM5&%b 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 VkO2&l#Yv$+QtYmHNi3Nj{}+t}`m6u| literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/objects/pack/pack-f72bbfa35af982c2a60735152c80b24ee981cf102db76764c383f9b87935d0d3.idx b/tests/resources/testrepo_256/.gitted/objects/pack/pack-f72bbfa35af982c2a60735152c80b24ee981cf102db76764c383f9b87935d0d3.idx new file mode 100644 index 0000000000000000000000000000000000000000..1d197e87085e32a838da41a976b0dbf13938628b GIT binary patch literal 1336 zcmexg;-AdGz`z8=qk!}fU<7KRB?iUIKx1a08>od@fM!t>vjWW|?pt)*BaNFAyuP`%y7il{<)*l^up!FyVBLILX1~6UNj$>y7hv+?ty1Foih&9c8$9gZVTN(b|vv=+n z%vY#cef;}9o3l0T7e94ekq+)qb=qWeh$CyJ*trPpZY`#4Uej*2!>e|k<5Vsvk1x8F z`%9#=a4pwHFQtQVS#mr{Q3uw%)UbRqOEe-N)H^;`N0UujbJgVEHTHi0cWu3Y$MxLK zpUXA3KYsl0)3(#!e%|Q&dsA7I#cSe0dj`fGuHSS0ez(6`_s#Zi{DH~88P9h5PoBX8 za<(VeAqN45_n*7=abMb;A|~*W`QDLge}8v&U#5+p>zV&KtO$0Tx=zVq?E{J0XHvmM z5#?NM6N)^_4mjvcoe{j&?$m`Dv!>6vyUucog_rS`m&K6}??tAyYOlTZaEXcj`nR8E ztk~bb$0vP*UUZ3}2tRvCN80w_@TvAe#gqFFUfn%$QOBLO{Y5s*lYAdr>(2I0yPnUfJA41>o9i!$GHl)_^lURw zGqx${veU9^^TXL&loJDdfzC2AGQx0KM)i`y;->57*SAgA zJ|i7bzI2!Azy7+KBWX(y{>!QC)t>f|L13~N&sIhpE@NT{O=oZWuDyS8)X%0v%h*jt abs9GLy=*)$pu0Ui<#6-Q9hIgRE&~9e7#2MM literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo_256/.gitted/packed-refs b/tests/resources/testrepo_256/.gitted/packed-refs new file mode 100644 index 00000000000..75626adfed4 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/packed-refs @@ -0,0 +1,27 @@ +# pack-refs with: peeled fully-peeled sorted +a4813ef6708e6011e8187224297e83e4a285f58bf5eabb1db270351388603c95 refs/remotes/origin/br2 +a4813ef6708e6011e8187224297e83e4a285f58bf5eabb1db270351388603c95 refs/remotes/origin/cannot-fetch +4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744 refs/remotes/origin/chomped +7e9424c06052ca33bfc599bccadee60065d8664a9af7648a1455100c4f772e1c refs/remotes/origin/haacked +decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f refs/remotes/origin/master +decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f refs/remotes/origin/not-good +66fe8385c6378bfa5ca5573bd0fdd773e4eadb0e86416b483f2c50c839859ecb refs/remotes/origin/packed +43e084a4599ca42c476919917e3db8fde0045ee66305fd5e634b0c793c536a1b refs/remotes/origin/packed-test +0118010feb81fe41b9df646d13866742a9070b56fd0ba9ab8dff828fc36c1f78 refs/remotes/origin/subtrees +4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744 refs/remotes/origin/test +b83624f6ac0995273c0034a7ab8c68929bdc91b69ad54ef94979b93eba3f6022 refs/remotes/origin/track-local +4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744 refs/remotes/origin/trailing +7e4633ae1b0e83503dbea4417f9d5ccaf22b877c5a4522b6d1d2b16090ee2f6f refs/remotes/origin/with-empty-log +d88b60d2641df3656381dc8e201abb820a414de03eb63c065b06a2ab37d3f5ca refs/tags/annotated_tag_to_blob +^33e415b835a670bb5c3c760efa0433ac0cbd2d44679f68f2df3a9ae7014cf2a8 +21e1e1ebe45b2c1ef79ab050334e36a8015a546f0740bea4505e10d81a946f61 refs/tags/e90810b +^4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744 +34f79ad1c813b93d2ee11c830c2134815a31d9629e6aa9773338fedaab90976b refs/tags/hard_tag +^decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f +33e415b835a670bb5c3c760efa0433ac0cbd2d44679f68f2df3a9ae7014cf2a8 refs/tags/point_to_blob +14bd335f9d7188c778d44eba8801fe9bda46b66593291f5b9f7cd5f8888af12f refs/tags/taggerless +^4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744 +c258f010a08328a29cde33411d955520e0375fcbbcc14b7636a70f7536c32ef6 refs/tags/test +^4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744 +34f79ad1c813b93d2ee11c830c2134815a31d9629e6aa9773338fedaab90976b refs/tags/wrapped_tag +^decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f diff --git a/tests/resources/testrepo_256/.gitted/refs/heads/master b/tests/resources/testrepo_256/.gitted/refs/heads/master new file mode 100644 index 00000000000..106231c4cfa --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/refs/heads/master @@ -0,0 +1 @@ +decaff3051968d1f3a2defd3d4a80ced03101555e1fd8913b3544026c0717d4f diff --git a/tests/resources/testrepo_256/.gitted/refs/remotes/origin/HEAD b/tests/resources/testrepo_256/.gitted/refs/remotes/origin/HEAD new file mode 100644 index 00000000000..6efe28fff83 --- /dev/null +++ b/tests/resources/testrepo_256/.gitted/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master diff --git a/tests/resources/testrepo_256/README b/tests/resources/testrepo_256/README new file mode 100644 index 00000000000..a8233120f6a --- /dev/null +++ b/tests/resources/testrepo_256/README @@ -0,0 +1 @@ +hey there diff --git a/tests/resources/testrepo_256/branch_file.txt b/tests/resources/testrepo_256/branch_file.txt new file mode 100644 index 00000000000..3697d64be94 --- /dev/null +++ b/tests/resources/testrepo_256/branch_file.txt @@ -0,0 +1,2 @@ +hi +bye! diff --git a/tests/resources/testrepo_256/new.txt b/tests/resources/testrepo_256/new.txt new file mode 100644 index 00000000000..a71586c1dfe --- /dev/null +++ b/tests/resources/testrepo_256/new.txt @@ -0,0 +1 @@ +my new file From c0178ef365fcfabfa475906f2be8463e5afb4266 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 10:48:24 +0100 Subject: [PATCH 123/816] refs: honor sha256 during allocation --- src/libgit2/refs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index 8e4abaccc1f..5e2fe97e76f 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -72,6 +72,7 @@ git_reference *git_reference__alloc( const git_oid *oid, const git_oid *peel) { + git_oid_t oid_type; git_reference *ref; GIT_ASSERT_ARG_WITH_RETVAL(name, NULL); @@ -84,10 +85,16 @@ git_reference *git_reference__alloc( ref->type = GIT_REFERENCE_DIRECT; git_oid_cpy(&ref->target.oid, oid); +#ifdef GIT_EXPERIMENTAL_SHA256 + oid_type = oid->type; +#else + oid_type = GIT_OID_SHA1; +#endif + if (peel != NULL) git_oid_cpy(&ref->peel, peel); else - git_oid_clear(&ref->peel, GIT_OID_SHA1); + git_oid_clear(&ref->peel, oid_type); return ref; } From 46365f6860dc3459e84c4ecf6b40f8754d443c83 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 10:50:29 +0100 Subject: [PATCH 124/816] odb_pack: handle sha256 short lookups --- src/libgit2/odb_pack.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libgit2/odb_pack.c b/src/libgit2/odb_pack.c index 1b1d122b06c..c6151f4e729 100644 --- a/src/libgit2/odb_pack.c +++ b/src/libgit2/odb_pack.c @@ -309,11 +309,17 @@ static int pack_entry_find_prefix( { int error; size_t i; - git_oid found_full_oid = GIT_OID_SHA1_ZERO; + git_oid found_full_oid; bool found = false; struct git_pack_file *last_found = backend->last_found, *p; git_midx_entry midx_entry; +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_clear(&found_full_oid, short_oid->type); +#else + git_oid_clear(&found_full_oid, GIT_OID_SHA1); +#endif + if (backend->midx) { error = git_midx_entry_find(&midx_entry, backend->midx, short_oid, len); if (error == GIT_EAMBIGUOUS) From 53a46b40af65562a6ce87e15addc1843bbe762ed Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 10:52:04 +0100 Subject: [PATCH 125/816] oid: support sha256 in tostr_s Our thread-local sha string buffer should be sized to support SHA256 strings. --- src/libgit2/threadstate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/threadstate.h b/src/libgit2/threadstate.h index f9e7ba7bfe0..65edec71723 100644 --- a/src/libgit2/threadstate.h +++ b/src/libgit2/threadstate.h @@ -13,7 +13,7 @@ typedef struct { git_error *last_error; git_error error_t; git_str error_buf; - char oid_fmt[GIT_OID_SHA1_HEXSIZE+1]; + char oid_fmt[GIT_OID_MAX_HEXSIZE+1]; } git_threadstate; extern int git_threadstate_global_init(void); From a850a4211a498f37688ad32b487a942c88eb31a8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 10:52:48 +0100 Subject: [PATCH 126/816] submodule: document OID as "oid" not "SHA1" --- src/libgit2/submodule.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/submodule.h b/src/libgit2/submodule.h index 7fa98248620..40b7b70f777 100644 --- a/src/libgit2/submodule.h +++ b/src/libgit2/submodule.h @@ -69,9 +69,9 @@ * - `repo` is the parent repository that contains this submodule. * - `flags` after for internal use, tracking where this submodule has been * found (head, index, config, workdir) and known status info, etc. - * - `head_oid` is the SHA1 for the submodule path in the repo HEAD. - * - `index_oid` is the SHA1 for the submodule recorded in the index. - * - `wd_oid` is the SHA1 for the HEAD of the checked out submodule. + * - `head_oid` is the oid for the submodule path in the repo HEAD. + * - `index_oid` is the oid for the submodule recorded in the index. + * - `wd_oid` is the oid for the HEAD of the checked out submodule. * * If the submodule has been added to .gitmodules but not yet git added, * then the `index_oid` will be zero but still marked valid. If the From e61fac75520eacc4ea45b293d50af339662d8312 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 12:23:05 +0100 Subject: [PATCH 127/816] packbuilder: write sha256 trailers when expected --- src/libgit2/pack-objects.c | 18 +++++++++++++----- src/libgit2/pack-objects.h | 2 ++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index 20a5dfcbdd5..d6fd603268e 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -127,6 +127,7 @@ static int packbuilder_config(git_packbuilder *pb) int git_packbuilder_new(git_packbuilder **out, git_repository *repo) { + git_hash_algorithm_t hash_algorithm; git_packbuilder *pb; *out = NULL; @@ -134,6 +135,11 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) pb = git__calloc(1, sizeof(*pb)); GIT_ERROR_CHECK_ALLOC(pb); + pb->oid_type = repo->oid_type; + + hash_algorithm = git_oid_algorithm(pb->oid_type); + GIT_ASSERT(hash_algorithm); + if (git_oidmap_new(&pb->object_ix) < 0 || git_oidmap_new(&pb->walk_objects) < 0 || git_pool_init(&pb->object_pool, sizeof(struct walk_object)) < 0) @@ -142,7 +148,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) pb->repo = repo; pb->nr_threads = 1; /* do not spawn any thread by default */ - if (git_hash_ctx_init(&pb->ctx, GIT_HASH_ALGORITHM_SHA1) < 0 || + if (git_hash_ctx_init(&pb->ctx, hash_algorithm) < 0 || git_zstream_init(&pb->zstream, GIT_ZSTREAM_DEFLATE) < 0 || git_repository_odb(&pb->odb, repo) < 0 || packbuilder_config(pb) < 0) @@ -315,9 +321,11 @@ static int write_object( git_object_t type; unsigned char hdr[10], *zbuf = NULL; void *data = NULL; - size_t hdr_len, zbuf_len = COMPRESS_BUFLEN, data_len; + size_t hdr_len, zbuf_len = COMPRESS_BUFLEN, data_len, oid_size; int error; + oid_size = git_oid_size(pb->oid_type); + /* * If we have a delta base, let's use the delta to save space. * Otherwise load the whole object. 'data' ends up pointing to @@ -347,8 +355,8 @@ static int write_object( goto done; if (type == GIT_OBJECT_REF_DELTA) { - if ((error = write_cb(po->delta->id.id, GIT_OID_SHA1_SIZE, cb_data)) < 0 || - (error = git_hash_update(&pb->ctx, po->delta->id.id, GIT_OID_SHA1_SIZE)) < 0) + if ((error = write_cb(po->delta->id.id, oid_size, cb_data)) < 0 || + (error = git_hash_update(&pb->ctx, po->delta->id.id, oid_size)) < 0) goto done; } @@ -668,7 +676,7 @@ static int write_pack(git_packbuilder *pb, if ((error = git_hash_final(entry_oid.id, &pb->ctx)) < 0) goto done; - error = write_cb(entry_oid.id, GIT_OID_SHA1_SIZE, cb_data); + error = write_cb(entry_oid.id, git_oid_size(pb->oid_type), cb_data); done: /* if callback cancelled writing, we must still free delta_data */ diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h index 2faa3ec7f51..c6bc52fdc5e 100644 --- a/src/libgit2/pack-objects.h +++ b/src/libgit2/pack-objects.h @@ -56,6 +56,8 @@ struct git_packbuilder { git_repository *repo; /* associated repository */ git_odb *odb; /* associated object database */ + git_oid_t oid_type; + git_hash_ctx ctx; git_zstream zstream; From 27e29472b5151635203e2f96a42457d0d6014421 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 12:27:27 +0100 Subject: [PATCH 128/816] config: use sha256 as file checksum The config file checksum is only used to detect changes internally -- it is not stored within the repository. Therefore this need not be configurable. Use SHA256 everywhere, regardless of the repository object format. --- src/libgit2/config_file.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index f3b87578d9c..716924de600 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -26,7 +26,7 @@ typedef struct config_file { git_futils_filestamp stamp; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_SHA256_SIZE]; char *path; git_array_t(struct config_file) includes; } config_file; @@ -133,7 +133,7 @@ static int config_file_is_modified(int *modified, config_file *file) { config_file *include; git_str buf = GIT_STR_INIT; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_SHA256_SIZE]; uint32_t i; int error = 0; @@ -145,10 +145,10 @@ static int config_file_is_modified(int *modified, config_file *file) if ((error = git_futils_readbuffer(&buf, file->path)) < 0) goto out; - if ((error = git_hash_buf(checksum, buf.ptr, buf.size, GIT_HASH_ALGORITHM_SHA1)) < 0) + if ((error = git_hash_buf(checksum, buf.ptr, buf.size, GIT_HASH_ALGORITHM_SHA256)) < 0) goto out; - if (memcmp(checksum, file->checksum, GIT_HASH_SHA1_SIZE) != 0) { + if (memcmp(checksum, file->checksum, GIT_HASH_SHA256_SIZE) != 0) { *modified = 1; goto out; } @@ -881,7 +881,7 @@ static int config_file_read( goto out; git_futils_filestamp_set_from_stat(&file->stamp, &st); - if ((error = git_hash_buf(file->checksum, contents.ptr, contents.size, GIT_HASH_ALGORITHM_SHA1)) < 0) + if ((error = git_hash_buf(file->checksum, contents.ptr, contents.size, GIT_HASH_ALGORITHM_SHA256)) < 0) goto out; if ((error = config_file_read_buffer(entries, repo, file, level, depth, @@ -1129,10 +1129,7 @@ static int config_file_write( git_config_parser parser = GIT_CONFIG_PARSER_INIT; git_filebuf file = GIT_FILEBUF_INIT; struct write_data write_data; - int filebuf_hash, error; - - filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(GIT_OID_SHA1)); - GIT_ASSERT(filebuf_hash); + int error; memset(&write_data, 0, sizeof(write_data)); @@ -1140,7 +1137,8 @@ static int config_file_write( error = git_str_puts(&contents, git_str_cstr(&cfg->locked_content) == NULL ? "" : git_str_cstr(&cfg->locked_content)); } else { if ((error = git_filebuf_open(&file, cfg->file.path, - filebuf_hash, GIT_CONFIG_FILE_MODE)) < 0) + GIT_FILEBUF_HASH_SHA256, + GIT_CONFIG_FILE_MODE)) < 0) goto done; /* We need to read in our own config file */ From 93e55a029818ec872d61da1f5776f3baf385f956 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 12:42:43 +0100 Subject: [PATCH 129/816] object: sha256 lookups --- src/libgit2/object.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/libgit2/object.c b/src/libgit2/object.c index d87d40cf16d..b7796f0574e 100644 --- a/src/libgit2/object.c +++ b/src/libgit2/object.c @@ -181,6 +181,7 @@ int git_object_lookup_prefix( git_object *object = NULL; git_odb *odb = NULL; git_odb_object *odb_obj = NULL; + size_t oid_hexsize; int error = 0; GIT_ASSERT_ARG(repo); @@ -196,10 +197,12 @@ int git_object_lookup_prefix( if (error < 0) return error; - if (len > GIT_OID_SHA1_HEXSIZE) - len = GIT_OID_SHA1_HEXSIZE; + oid_hexsize = git_oid_hexsize(repo->oid_type); - if (len == GIT_OID_SHA1_HEXSIZE) { + if (len > oid_hexsize) + len = oid_hexsize; + + if (len == oid_hexsize) { git_cached_obj *cached = NULL; /* We want to match the full id : we can first look up in the cache, @@ -233,8 +236,9 @@ int git_object_lookup_prefix( error = git_odb_read(&odb_obj, odb, id); } } else { - git_oid short_oid = GIT_OID_SHA1_ZERO; + git_oid short_oid; + git_oid_clear(&short_oid, repo->oid_type); git_oid__cpy_prefix(&short_oid, id, len); /* If len < GIT_OID_SHA1_HEXSIZE (a strict short oid was given), we have @@ -262,7 +266,8 @@ int git_object_lookup_prefix( } int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_object_t type) { - return git_object_lookup_prefix(object_out, repo, id, GIT_OID_SHA1_HEXSIZE, type); + return git_object_lookup_prefix(object_out, + repo, id, git_oid_hexsize(repo->oid_type), type); } void git_object_free(git_object *object) @@ -503,31 +508,36 @@ int git_object_lookup_bypath( static int git_object__short_id(git_str *out, const git_object *obj) { git_repository *repo; - int len = GIT_ABBREV_DEFAULT, error; - git_oid id = GIT_OID_SHA1_ZERO; + git_oid id; git_odb *odb; + size_t oid_hexsize; + int len = GIT_ABBREV_DEFAULT, error; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(obj); repo = git_object_owner(obj); + git_oid_clear(&id, repo->oid_type); + oid_hexsize = git_oid_hexsize(repo->oid_type); + if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0) return error; + if (len < 0 || (size_t)len > oid_hexsize) { + git_error_set(GIT_ERROR_CONFIG, "invalid oid abbreviation setting: '%d'", len); + return -1; + } + if ((error = git_repository_odb(&odb, repo)) < 0) return error; - while (len < GIT_OID_SHA1_HEXSIZE) { + while ((size_t)len < oid_hexsize) { /* set up short oid */ memcpy(&id.id, &obj->cached.oid.id, (len + 1) / 2); if (len & 1) id.id[len / 2] &= 0xf0; -#ifdef GIT_EXPERIMENTAL_SHA256 - id.type = GIT_OID_SHA1; -#endif - error = git_odb_exists_prefix(NULL, odb, &id, len); if (error != GIT_EAMBIGUOUS) break; From d1c92a9568a5d1d974b2601bed41a5c0504cf232 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 5 Apr 2023 12:48:00 +0100 Subject: [PATCH 130/816] refdb: handle SHA256 references --- src/libgit2/parse.c | 11 +++++++---- src/libgit2/parse.h | 2 +- src/libgit2/refdb_fs.c | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/libgit2/parse.c b/src/libgit2/parse.c index 55d3cb10ec9..9eb86a3f584 100644 --- a/src/libgit2/parse.c +++ b/src/libgit2/parse.c @@ -102,13 +102,16 @@ int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base) return 0; } -int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx) +int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx, git_oid_t oid_type) { - if (ctx->line_len < GIT_OID_SHA1_HEXSIZE) + size_t oid_hexsize = git_oid_hexsize(oid_type); + GIT_ASSERT(oid_hexsize); + + if (ctx->line_len < oid_hexsize) return -1; - if ((git_oid__fromstrn(out, ctx->line, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1)) < 0) + if ((git_oid__fromstrn(out, ctx->line, oid_hexsize, oid_type)) < 0) return -1; - git_parse_advance_chars(ctx, GIT_OID_SHA1_HEXSIZE); + git_parse_advance_chars(ctx, oid_hexsize); return 0; } diff --git a/src/libgit2/parse.h b/src/libgit2/parse.h index 0ecb7c103b9..beef1de12fb 100644 --- a/src/libgit2/parse.h +++ b/src/libgit2/parse.h @@ -50,7 +50,7 @@ int git_parse_advance_expected( int git_parse_advance_ws(git_parse_ctx *ctx); int git_parse_advance_nl(git_parse_ctx *ctx); int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base); -int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx); +int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx, git_oid_t oid_type); enum GIT_PARSE_PEEK_FLAGS { GIT_PARSE_PEEK_SKIP_WHITESPACE = (1 << 0) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 9ce1a960833..6000dafb3fc 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -1949,9 +1949,9 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) entry->committer = git__calloc(1, sizeof(*entry->committer)); GIT_ERROR_CHECK_ALLOC(entry->committer); - if (git_parse_advance_oid(&entry->oid_old, &parser) < 0 || + if (git_parse_advance_oid(&entry->oid_old, &parser, log->oid_type) < 0 || git_parse_advance_expected(&parser, " ", 1) < 0 || - git_parse_advance_oid(&entry->oid_cur, &parser) < 0) + git_parse_advance_oid(&entry->oid_cur, &parser, log->oid_type) < 0) goto next; sig = parser.line; From bd5e3082fd494429a515db55353aab64b441a166 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 09:26:02 +0100 Subject: [PATCH 131/816] remote: support SHA256 for remote refs --- src/libgit2/remote.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index c3e2a324d23..c1dccbe3281 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1631,7 +1631,10 @@ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks) const git_refspec *spec; const char *refname; int error; - git_oid zero_id = GIT_OID_SHA1_ZERO; + git_oid zero_id; + + GIT_ASSERT(remote && remote->repo); + git_oid_clear(&zero_id, remote->repo->oid_type); if (callbacks) GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); @@ -1733,9 +1736,12 @@ static int update_ref( const git_remote_callbacks *callbacks) { git_reference *ref; - git_oid old_id = GIT_OID_SHA1_ZERO; + git_oid old_id; int error; + GIT_ASSERT(remote && remote->repo); + git_oid_clear(&old_id, remote->repo->oid_type); + error = git_reference_name_to_id(&old_id, remote->repo, ref_name); if (error < 0 && error != GIT_ENOTFOUND) @@ -1779,6 +1785,8 @@ static int update_one_tip( int valid; int error; + GIT_ASSERT(remote && remote->repo); + if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0) goto done; @@ -1839,7 +1847,7 @@ static int update_one_tip( } if (error == GIT_ENOTFOUND) { - git_oid_clear(&old, GIT_OID_SHA1); + git_oid_clear(&old, remote->repo->oid_type); error = 0; if (autotag && (error = git_vector_insert(update_heads, head)) < 0) @@ -1885,7 +1893,7 @@ static int update_tips_for_spec( int error = 0; size_t i; - GIT_ASSERT_ARG(remote); + GIT_ASSERT_ARG(remote && remote->repo); if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return -1; @@ -1901,10 +1909,10 @@ static int update_tips_for_spec( } /* Handle specified oid sources */ - if (git_oid__is_hexstr(spec->src, GIT_OID_SHA1)) { + if (git_oid__is_hexstr(spec->src, remote->repo->oid_type)) { git_oid id; - if ((error = git_oid__fromstr(&id, spec->src, GIT_OID_SHA1)) < 0) + if ((error = git_oid__fromstr(&id, spec->src, remote->repo->oid_type)) < 0) goto on_error; if (spec->dst && From d16731e445eda35192f9c338d750a773d343d59a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 09:27:29 +0100 Subject: [PATCH 132/816] push: support SHA256 refs --- src/libgit2/push.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/push.c b/src/libgit2/push.c index e256818707a..8b47abc2463 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -118,8 +118,8 @@ static int parse_refspec(git_push *push, push_spec **spec, const char *str) s = git__calloc(1, sizeof(*s)); GIT_ERROR_CHECK_ALLOC(s); - git_oid_clear(&s->loid, GIT_OID_SHA1); - git_oid_clear(&s->roid, GIT_OID_SHA1); + git_oid_clear(&s->loid, push->repo->oid_type); + git_oid_clear(&s->roid, push->repo->oid_type); if (git_refspec__parse(&s->refspec, str, false) < 0) { git_error_set(GIT_ERROR_INVALID, "invalid refspec %s", str); From 440b1995ab45ae205dd63366a374f2c491bd16a9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 09:30:20 +0100 Subject: [PATCH 133/816] fetch: support SHA256 refs --- src/libgit2/fetch.c | 4 ++-- src/libgit2/fetchhead.c | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 003b5198ae8..ff10bde024f 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -76,7 +76,7 @@ static int maybe_want_oid(git_remote *remote, git_refspec *spec) oid_head = git__calloc(1, sizeof(git_remote_head)); GIT_ERROR_CHECK_ALLOC(oid_head); - git_oid__fromstr(&oid_head->oid, spec->src, GIT_OID_SHA1); + git_oid__fromstr(&oid_head->oid, spec->src, remote->repo->oid_type); if (spec->dst) { oid_head->name = git__strdup(spec->dst); @@ -137,7 +137,7 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts) /* Handle explicitly specified OID specs */ git_vector_foreach(&remote->active_refspecs, i, spec) { - if (!git_oid__is_hexstr(spec->src, GIT_OID_SHA1)) + if (!git_oid__is_hexstr(spec->src, remote->repo->oid_type)) continue; if (!(remote_caps & oid_mask)) { diff --git a/src/libgit2/fetchhead.c b/src/libgit2/fetchhead.c index 0ebfe5c439b..2f276e5265e 100644 --- a/src/libgit2/fetchhead.c +++ b/src/libgit2/fetchhead.c @@ -105,15 +105,14 @@ static int fetchhead_ref_write( git_filebuf *file, git_fetchhead_ref *fetchhead_ref) { - char oid[GIT_OID_SHA1_HEXSIZE + 1]; + char oid[GIT_OID_MAX_HEXSIZE + 1]; const char *type, *name; int head = 0; GIT_ASSERT_ARG(file); GIT_ASSERT_ARG(fetchhead_ref); - git_oid_fmt(oid, &fetchhead_ref->oid); - oid[GIT_OID_SHA1_HEXSIZE] = '\0'; + git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, &fetchhead_ref->oid); if (git__prefixcmp(fetchhead_ref->ref_name, GIT_REFS_HEADS_DIR) == 0) { type = "branch "; @@ -174,7 +173,8 @@ static int fetchhead_ref_parse( git_str *ref_name, const char **remote_url, char *line, - size_t line_num) + size_t line_num, + git_oid_t oid_type) { char *oid_str, *is_merge_str, *desc, *name = NULL; const char *type = NULL; @@ -196,13 +196,13 @@ static int fetchhead_ref_parse( *is_merge = 1; } - if (strlen(oid_str) != GIT_OID_SHA1_HEXSIZE) { + if (strlen(oid_str) != git_oid_hexsize(oid_type)) { git_error_set(GIT_ERROR_FETCHHEAD, "invalid object ID in FETCH_HEAD line %"PRIuZ, line_num); return -1; } - if (git_oid__fromstr(oid, oid_str, GIT_OID_SHA1) < 0) { + if (git_oid__fromstr(oid, oid_str, oid_type) < 0) { const git_error *oid_err = git_error_last(); const char *err_msg = oid_err ? oid_err->message : "invalid object ID"; @@ -269,7 +269,8 @@ static int fetchhead_ref_parse( return error; } -int git_repository_fetchhead_foreach(git_repository *repo, +int git_repository_fetchhead_foreach( + git_repository *repo, git_repository_fetchhead_foreach_cb cb, void *payload) { @@ -296,8 +297,9 @@ int git_repository_fetchhead_foreach(git_repository *repo, while ((line = git__strsep(&buffer, "\n")) != NULL) { ++line_num; - if ((error = fetchhead_ref_parse( - &oid, &is_merge, &name, &remote_url, line, line_num)) < 0) + if ((error = fetchhead_ref_parse(&oid, &is_merge, &name, + &remote_url, line, line_num, + repo->oid_type)) < 0) goto done; if (git_str_len(&name) > 0) From 14fc473a4d7f08d8b18878ecbf78ae03d6d756eb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 09:34:09 +0100 Subject: [PATCH 134/816] branch: support sha256 OIDs for branch refs --- src/libgit2/branch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/branch.c b/src/libgit2/branch.c index 4cbd1e26f7a..9a31c9c6ffc 100644 --- a/src/libgit2/branch.c +++ b/src/libgit2/branch.c @@ -134,9 +134,9 @@ int git_branch_create( const git_commit *commit, int force) { - char commit_id[GIT_OID_SHA1_HEXSIZE + 1]; + char commit_id[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_tostr(commit_id, GIT_OID_SHA1_HEXSIZE + 1, git_commit_id(commit)); + git_oid_tostr(commit_id, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); return create_branch(ref_out, repository, branch_name, commit, commit_id, force); } From cf6faa882e14fffcf988103659b4086d62f7d3dd Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 10:23:38 +0100 Subject: [PATCH 135/816] revert: support SHA256 oids --- src/libgit2/revert.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/libgit2/revert.c b/src/libgit2/revert.c index 1106dfe2f2c..4a31ad40a1a 100644 --- a/src/libgit2/revert.c +++ b/src/libgit2/revert.c @@ -107,12 +107,10 @@ static int revert_state_cleanup(git_repository *repo) static int revert_seterr(git_commit *commit, const char *fmt) { - char commit_oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + char commit_id[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_fmt(commit_oidstr, git_commit_id(commit)); - commit_oidstr[GIT_OID_SHA1_HEXSIZE] = '\0'; - - git_error_set(GIT_ERROR_REVERT, fmt, commit_oidstr); + git_oid_tostr(commit_id, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); + git_error_set(GIT_ERROR_REVERT, fmt, commit_id); return -1; } @@ -176,7 +174,7 @@ int git_revert( git_revert_options opts; git_reference *our_ref = NULL; git_commit *our_commit = NULL; - char commit_oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + char commit_id[GIT_OID_MAX_HEXSIZE + 1]; const char *commit_msg; git_str their_label = GIT_STR_INIT; git_index *index = NULL; @@ -191,19 +189,18 @@ int git_revert( if ((error = git_repository__ensure_not_bare(repo, "revert")) < 0) return error; - git_oid_fmt(commit_oidstr, git_commit_id(commit)); - commit_oidstr[GIT_OID_SHA1_HEXSIZE] = '\0'; + git_oid_tostr(commit_id, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); if ((commit_msg = git_commit_summary(commit)) == NULL) { error = -1; goto on_error; } - if ((error = git_str_printf(&their_label, "parent of %.7s... %s", commit_oidstr, commit_msg)) < 0 || + if ((error = git_str_printf(&their_label, "parent of %.7s... %s", commit_id, commit_msg)) < 0 || (error = revert_normalize_opts(repo, &opts, given_opts, git_str_cstr(&their_label))) < 0 || (error = git_indexwriter_init_for_operation(&indexwriter, repo, &opts.checkout_opts.checkout_strategy)) < 0 || - (error = write_revert_head(repo, commit_oidstr)) < 0 || - (error = write_merge_msg(repo, commit_oidstr, commit_msg)) < 0 || + (error = write_revert_head(repo, commit_id)) < 0 || + (error = write_merge_msg(repo, commit_id, commit_msg)) < 0 || (error = git_repository_head(&our_ref, repo)) < 0 || (error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJECT_COMMIT)) < 0 || (error = git_revert_commit(&index, repo, commit, our_commit, opts.mainline, &opts.merge_opts)) < 0 || From bd2c3786d719d39403f7de0634c06e5cf155604e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 10:23:44 +0100 Subject: [PATCH 136/816] rebase: support SHA256 oids --- src/libgit2/rebase.c | 156 ++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 84 deletions(-) diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c index 1970d5ddc60..77e442e981d 100644 --- a/src/libgit2/rebase.c +++ b/src/libgit2/rebase.c @@ -65,6 +65,9 @@ struct git_rebase { git_rebase_t type; char *state_path; + /* Temporary buffer for paths within the state path. */ + git_str state_filename; + unsigned int head_detached:1, inmemory:1, quiet:1, @@ -134,33 +137,42 @@ static int rebase_state_type( GIT_INLINE(int) rebase_readfile( git_str *out, - git_str *state_path, + git_rebase *rebase, const char *filename) { - size_t state_path_len = state_path->size; + /* + * `rebase->state_filename` is a temporary buffer to avoid + * unnecessary allocations and copies of `rebase->state_path`. + * At the start and end of this function it always contains the + * contents of `rebase->state_path` itself. + */ + size_t state_path_len = rebase->state_filename.size; int error; git_str_clear(out); - if ((error = git_str_joinpath(state_path, state_path->ptr, filename)) < 0 || - (error = git_futils_readbuffer(out, state_path->ptr)) < 0) + if ((error = git_str_joinpath(&rebase->state_filename, rebase->state_filename.ptr, filename)) < 0 || + (error = git_futils_readbuffer(out, rebase->state_filename.ptr)) < 0) goto done; git_str_rtrim(out); done: - git_str_truncate(state_path, state_path_len); + git_str_truncate(&rebase->state_filename, state_path_len); return error; } GIT_INLINE(int) rebase_readint( - size_t *out, git_str *asc_out, git_str *state_path, const char *filename) + size_t *out, + git_str *asc_out, + git_rebase *rebase, + const char *filename) { int32_t num; const char *eol; int error = 0; - if ((error = rebase_readfile(asc_out, state_path, filename)) < 0) + if ((error = rebase_readfile(asc_out, rebase, filename)) < 0) return error; if (git__strntol32(&num, asc_out->ptr, asc_out->size, &eol, 10) < 0 || num < 0 || *eol) { @@ -174,15 +186,18 @@ GIT_INLINE(int) rebase_readint( } GIT_INLINE(int) rebase_readoid( - git_oid *out, git_str *str_out, git_str *state_path, const char *filename) + git_oid *out, + git_str *str_out, + git_rebase *rebase, + const char *filename) { int error; - if ((error = rebase_readfile(str_out, state_path, filename)) < 0) + if ((error = rebase_readfile(str_out, rebase, filename)) < 0) return error; - if (str_out->size != GIT_OID_SHA1_HEXSIZE || - git_oid__fromstr(out, str_out->ptr, GIT_OID_SHA1) < 0) { + if (str_out->size != git_oid_hexsize(rebase->repo->oid_type) || + git_oid__fromstr(out, str_out->ptr, rebase->repo->oid_type) < 0) { git_error_set(GIT_ERROR_REBASE, "the file '%s' contains an invalid object ID", filename); return -1; } @@ -213,17 +228,14 @@ static git_rebase_operation *rebase_operation_alloc( static int rebase_open_merge(git_rebase *rebase) { - git_str state_path = GIT_STR_INIT, buf = GIT_STR_INIT, cmt = GIT_STR_INIT; + git_str buf = GIT_STR_INIT, cmt = GIT_STR_INIT; git_oid id; git_rebase_operation *operation; size_t i, msgnum = 0, end; int error; - if ((error = git_str_puts(&state_path, rebase->state_path)) < 0) - goto done; - /* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */ - if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 && + if ((error = rebase_readint(&msgnum, &buf, rebase, MSGNUM_FILE)) < 0 && error != GIT_ENOTFOUND) goto done; @@ -233,11 +245,11 @@ static int rebase_open_merge(git_rebase *rebase) } /* Read 'end' */ - if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0) + if ((error = rebase_readint(&end, &buf, rebase, END_FILE)) < 0) goto done; /* Read 'current' if it exists */ - if ((error = rebase_readoid(&id, &buf, &state_path, CURRENT_FILE)) < 0 && + if ((error = rebase_readoid(&id, &buf, rebase, CURRENT_FILE)) < 0 && error != GIT_ENOTFOUND) goto done; @@ -249,7 +261,7 @@ static int rebase_open_merge(git_rebase *rebase) git_str_clear(&cmt); if ((error = git_str_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 || - (error = rebase_readoid(&id, &buf, &state_path, cmt.ptr)) < 0) + (error = rebase_readoid(&id, &buf, rebase, cmt.ptr)) < 0) goto done; operation = rebase_operation_alloc(rebase, GIT_REBASE_OPERATION_PICK, &id, NULL); @@ -257,14 +269,13 @@ static int rebase_open_merge(git_rebase *rebase) } /* Read 'onto_name' */ - if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0) + if ((error = rebase_readfile(&buf, rebase, ONTO_NAME_FILE)) < 0) goto done; rebase->onto_name = git_str_detach(&buf); done: git_str_dispose(&cmt); - git_str_dispose(&state_path); git_str_dispose(&buf); return error; @@ -308,9 +319,9 @@ int git_rebase_open( const git_rebase_options *given_opts) { git_rebase *rebase; - git_str path = GIT_STR_INIT, orig_head_name = GIT_STR_INIT, - orig_head_id = GIT_STR_INIT, onto_id = GIT_STR_INIT; - size_t state_path_len; + git_str orig_head_name = GIT_STR_INIT, + orig_head_id = GIT_STR_INIT, + onto_id = GIT_STR_INIT; int error; GIT_ASSERT_ARG(repo); @@ -332,13 +343,10 @@ int git_rebase_open( goto done; } - if ((error = git_str_puts(&path, rebase->state_path)) < 0) + if ((error = git_str_puts(&rebase->state_filename, rebase->state_path)) < 0) goto done; - state_path_len = git_str_len(&path); - - if ((error = git_str_joinpath(&path, path.ptr, HEAD_NAME_FILE)) < 0 || - (error = git_futils_readbuffer(&orig_head_name, path.ptr)) < 0) + if ((error = rebase_readfile(&orig_head_name, rebase, HEAD_NAME_FILE)) < 0) goto done; git_str_rtrim(&orig_head_name); @@ -346,36 +354,16 @@ int git_rebase_open( if (strcmp(ORIG_DETACHED_HEAD, orig_head_name.ptr) == 0) rebase->head_detached = 1; - git_str_truncate(&path, state_path_len); - - if ((error = git_str_joinpath(&path, path.ptr, ORIG_HEAD_FILE)) < 0) - goto done; - - if (!git_fs_path_isfile(path.ptr)) { + if ((error = rebase_readoid(&rebase->orig_head_id, &orig_head_id, rebase, ORIG_HEAD_FILE)) < 0) { /* Previous versions of git.git used 'head' here; support that. */ - git_str_truncate(&path, state_path_len); + if (error == GIT_ENOTFOUND) + error = rebase_readoid(&rebase->orig_head_id, &orig_head_id, rebase, HEAD_FILE); - if ((error = git_str_joinpath(&path, path.ptr, HEAD_FILE)) < 0) + if (error < 0) goto done; } - if ((error = git_futils_readbuffer(&orig_head_id, path.ptr)) < 0) - goto done; - - git_str_rtrim(&orig_head_id); - - if ((error = git_oid__fromstr(&rebase->orig_head_id, orig_head_id.ptr, GIT_OID_SHA1)) < 0) - goto done; - - git_str_truncate(&path, state_path_len); - - if ((error = git_str_joinpath(&path, path.ptr, ONTO_FILE)) < 0 || - (error = git_futils_readbuffer(&onto_id, path.ptr)) < 0) - goto done; - - git_str_rtrim(&onto_id); - - if ((error = git_oid__fromstr(&rebase->onto_id, onto_id.ptr, GIT_OID_SHA1)) < 0) + if ((error = rebase_readoid(&rebase->onto_id, &onto_id, rebase, ONTO_FILE)) < 0) goto done; if (!rebase->head_detached) @@ -403,7 +391,6 @@ int git_rebase_open( else git_rebase_free(rebase); - git_str_dispose(&path); git_str_dispose(&orig_head_name); git_str_dispose(&orig_head_id); git_str_dispose(&onto_id); @@ -453,13 +440,13 @@ static const char *rebase_onto_name(const git_annotated_commit *onto) static int rebase_setupfiles_merge(git_rebase *rebase) { git_str commit_filename = GIT_STR_INIT; - char id_str[GIT_OID_SHA1_HEXSIZE]; + char id_str[GIT_OID_MAX_HEXSIZE + 1]; git_rebase_operation *operation; size_t i; int error = 0; if ((error = rebase_setupfile(rebase, END_FILE, 0, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 || - (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0) + (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0) goto done; for (i = 0; i < git_array_size(rebase->operations); i++) { @@ -468,10 +455,9 @@ static int rebase_setupfiles_merge(git_rebase *rebase) git_str_clear(&commit_filename); git_str_printf(&commit_filename, CMT_FILE_FMT, i+1); - git_oid_fmt(id_str, &operation->id); + git_oid_tostr(id_str, GIT_OID_MAX_HEXSIZE + 1, &operation->id); - if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0, - "%.*s\n", GIT_OID_SHA1_HEXSIZE, id_str)) < 0) + if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0, "%s\n", id_str)) < 0) goto done; } @@ -482,11 +468,11 @@ static int rebase_setupfiles_merge(git_rebase *rebase) static int rebase_setupfiles(git_rebase *rebase) { - char onto[GIT_OID_SHA1_HEXSIZE], orig_head[GIT_OID_SHA1_HEXSIZE]; + char onto[GIT_OID_MAX_HEXSIZE + 1], orig_head[GIT_OID_MAX_HEXSIZE + 1]; const char *orig_head_name; - git_oid_fmt(onto, &rebase->onto_id); - git_oid_fmt(orig_head, &rebase->orig_head_id); + git_oid_tostr(onto, GIT_OID_MAX_HEXSIZE + 1, &rebase->onto_id); + git_oid_tostr(orig_head, GIT_OID_MAX_HEXSIZE + 1, &rebase->orig_head_id); if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) { git_error_set(GIT_ERROR_OS, "failed to create rebase directory '%s'", rebase->state_path); @@ -498,8 +484,8 @@ static int rebase_setupfiles(git_rebase *rebase) if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 || rebase_setupfile(rebase, HEAD_NAME_FILE, 0, "%s\n", orig_head_name) < 0 || - rebase_setupfile(rebase, ONTO_FILE, 0, "%.*s\n", GIT_OID_SHA1_HEXSIZE, onto) < 0 || - rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%.*s\n", GIT_OID_SHA1_HEXSIZE, orig_head) < 0 || + rebase_setupfile(rebase, ONTO_FILE, 0, "%s\n", onto) < 0 || + rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%s\n", orig_head) < 0 || rebase_setupfile(rebase, QUIET_FILE, 0, rebase->quiet ? "t\n" : "\n") < 0) return -1; @@ -644,7 +630,8 @@ static int rebase_init_merge( GIT_UNUSED(upstream); - if ((error = git_str_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0) + if ((error = git_str_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0 || + (error = git_str_put(&rebase->state_filename, state_path.ptr, state_path.size)) < 0) goto done; rebase->state_path = git_str_detach(&state_path); @@ -814,7 +801,7 @@ static int rebase_next_merge( git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; git_rebase_operation *operation; git_checkout_options checkout_opts; - char current_idstr[GIT_OID_SHA1_HEXSIZE]; + char current_idstr[GIT_OID_MAX_HEXSIZE + 1]; unsigned int parent_count; int error; @@ -837,13 +824,13 @@ static int rebase_next_merge( goto done; } - git_oid_fmt(current_idstr, &operation->id); + git_oid_tostr(current_idstr, GIT_OID_MAX_HEXSIZE + 1, &operation->id); normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit); if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 || (error = rebase_setupfile(rebase, MSGNUM_FILE, 0, "%" PRIuZ "\n", rebase->current+1)) < 0 || - (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%.*s\n", GIT_OID_SHA1_HEXSIZE, current_idstr)) < 0 || + (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%s\n", current_idstr)) < 0 || (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0 || (error = git_merge__check_result(rebase->repo, index)) < 0 || (error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0 || @@ -1103,7 +1090,7 @@ static int rebase_commit_merge( git_reference *head = NULL; git_commit *head_commit = NULL, *commit = NULL; git_index *index = NULL; - char old_idstr[GIT_OID_SHA1_HEXSIZE], new_idstr[GIT_OID_SHA1_HEXSIZE]; + char old_idstr[GIT_OID_MAX_HEXSIZE + 1], new_idstr[GIT_OID_MAX_HEXSIZE + 1]; int error; operation = git_array_get(rebase->operations, rebase->current); @@ -1119,11 +1106,11 @@ static int rebase_commit_merge( rebase->repo, NULL, "HEAD", git_commit_id(commit), "rebase")) < 0) goto done; - git_oid_fmt(old_idstr, &operation->id); - git_oid_fmt(new_idstr, git_commit_id(commit)); + git_oid_tostr(old_idstr, GIT_OID_MAX_HEXSIZE + 1, &operation->id); + git_oid_tostr(new_idstr, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); if ((error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, - "%.*s %.*s\n", GIT_OID_SHA1_HEXSIZE, old_idstr, GIT_OID_SHA1_HEXSIZE, new_idstr)) < 0) + "%s %s\n", old_idstr, new_idstr)) < 0) goto done; git_oid_cpy(commit_id, git_commit_id(commit)); @@ -1306,7 +1293,9 @@ static int rebase_copy_notes( git_rebase *rebase, const git_signature *committer) { - git_str path = GIT_STR_INIT, rewritten = GIT_STR_INIT, notes_ref = GIT_STR_INIT; + git_str path = GIT_STR_INIT, + rewritten = GIT_STR_INIT, + notes_ref = GIT_STR_INIT; char *pair_list, *fromstr, *tostr, *end; git_oid from, to; unsigned int linenum = 1; @@ -1342,10 +1331,10 @@ static int rebase_copy_notes( tostr = end+1; *end = '\0'; - if (strlen(fromstr) != GIT_OID_SHA1_HEXSIZE || - strlen(tostr) != GIT_OID_SHA1_HEXSIZE || - git_oid__fromstr(&from, fromstr, GIT_OID_SHA1) < 0 || - git_oid__fromstr(&to, tostr, GIT_OID_SHA1) < 0) + if (strlen(fromstr) != git_oid_hexsize(rebase->repo->oid_type) || + strlen(tostr) != git_oid_hexsize(rebase->repo->oid_type) || + git_oid__fromstr(&from, fromstr, rebase->repo->oid_type) < 0 || + git_oid__fromstr(&to, tostr, rebase->repo->oid_type) < 0) goto on_error; if ((error = rebase_copy_note(rebase, notes_ref.ptr, &from, &to, committer)) < 0) @@ -1373,17 +1362,15 @@ static int return_to_orig_head(git_rebase *rebase) git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL; git_commit *terminal_commit = NULL; git_str branch_msg = GIT_STR_INIT, head_msg = GIT_STR_INIT; - char onto[GIT_OID_SHA1_HEXSIZE]; + char onto[GIT_OID_MAX_HEXSIZE + 1]; int error = 0; - git_oid_fmt(onto, &rebase->onto_id); + git_oid_tostr(onto, GIT_OID_MAX_HEXSIZE + 1, &rebase->onto_id); if ((error = git_str_printf(&branch_msg, - "rebase finished: %s onto %.*s", - rebase->orig_head_name, GIT_OID_SHA1_HEXSIZE, onto)) == 0 && + "rebase finished: %s onto %s", rebase->orig_head_name, onto)) == 0 && (error = git_str_printf(&head_msg, - "rebase finished: returning to %s", - rebase->orig_head_name)) == 0 && + "rebase finished: returning to %s", rebase->orig_head_name)) == 0 && (error = git_repository_head(&terminal_ref, rebase->repo)) == 0 && (error = git_reference_peel((git_object **)&terminal_commit, terminal_ref, GIT_OBJECT_COMMIT)) == 0 && @@ -1475,6 +1462,7 @@ void git_rebase_free(git_rebase *rebase) git__free(rebase->onto_name); git__free(rebase->orig_head_name); git__free(rebase->state_path); + git_str_dispose(&rebase->state_filename); git_array_clear(rebase->operations); git__free((char *)rebase->options.rewrite_notes_ref); git__free(rebase); From 6238d81c1bc13e6f3985226b0a4f7bc0b4a1a117 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 10:24:44 +0100 Subject: [PATCH 137/816] notes: support SHA256 --- src/libgit2/notes.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libgit2/notes.c b/src/libgit2/notes.c index 1b1935330e9..13ca3824bf1 100644 --- a/src/libgit2/notes.c +++ b/src/libgit2/notes.c @@ -460,7 +460,7 @@ int git_note_commit_read( { int error; git_tree *tree = NULL; - char target[GIT_OID_SHA1_HEXSIZE + 1]; + char target[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(target, sizeof(target), oid); @@ -507,7 +507,7 @@ int git_note_commit_create( { int error; git_tree *tree = NULL; - char target[GIT_OID_SHA1_HEXSIZE + 1]; + char target[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(target, sizeof(target), oid); @@ -578,7 +578,7 @@ int git_note_commit_remove( { int error; git_tree *tree = NULL; - char target[GIT_OID_SHA1_HEXSIZE + 1]; + char target[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(target, sizeof(target), oid); @@ -665,8 +665,9 @@ void git_note_free(git_note *note) } static int process_entry_path( - const char *entry_path, - git_oid *annotated_object_id) + git_oid *annotated_object_id, + git_note_iterator *it, + const char *entry_path) { int error = 0; size_t i = 0, j = 0, len; @@ -698,12 +699,12 @@ static int process_entry_path( buf.ptr[j] = '\0'; buf.size = j; - if (j != GIT_OID_SHA1_HEXSIZE) { + if (j != git_oid_hexsize(it->repo->oid_type)) { /* This is not a note entry */ goto cleanup; } - error = git_oid__fromstr(annotated_object_id, buf.ptr, GIT_OID_SHA1); + error = git_oid__fromstr(annotated_object_id, buf.ptr, it->repo->oid_type); cleanup: git_str_dispose(&buf); @@ -799,7 +800,7 @@ int git_note_next( git_oid_cpy(note_id, &item->id); - if ((error = process_entry_path(item->path, annotated_id)) < 0) + if ((error = process_entry_path(annotated_id, it, item->path)) < 0) return error; if ((error = git_iterator_advance(NULL, it)) < 0 && error != GIT_ITEROVER) From 5fa2e4cb3a6b973b475de8506d806550d77be579 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 10:24:56 +0100 Subject: [PATCH 138/816] reset: support SHA256 --- src/libgit2/reset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/reset.c b/src/libgit2/reset.c index 9574819cb16..605c4afd5e2 100644 --- a/src/libgit2/reset.c +++ b/src/libgit2/reset.c @@ -188,9 +188,9 @@ int git_reset( git_reset_t reset_type, const git_checkout_options *checkout_opts) { - char to[GIT_OID_SHA1_HEXSIZE + 1]; + char to[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_tostr(to, GIT_OID_SHA1_HEXSIZE + 1, git_object_id(target)); + git_oid_tostr(to, GIT_OID_MAX_HEXSIZE + 1, git_object_id(target)); return reset(repo, target, to, reset_type, checkout_opts); } From 7f70484799df14dbc666b3c395ded690d1a5a402 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 6 Apr 2023 10:26:06 +0100 Subject: [PATCH 139/816] apply: support SHA256 --- src/libgit2/reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/reader.c b/src/libgit2/reader.c index be29bb41c11..df2b2807f55 100644 --- a/src/libgit2/reader.c +++ b/src/libgit2/reader.c @@ -125,7 +125,7 @@ static int workdir_reader_read( goto done; if (out_id || reader->index) { - if ((error = git_odb__hash(&id, out->ptr, out->size, GIT_OBJECT_BLOB, GIT_OID_SHA1)) < 0) + if ((error = git_odb__hash(&id, out->ptr, out->size, GIT_OBJECT_BLOB, reader->repo->oid_type)) < 0) goto done; } From db2a794dda2b6f92291b3758507f863f39314c72 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 7 Apr 2023 15:28:58 +0100 Subject: [PATCH 140/816] diff: parse patches with sha256 --- examples/diff.c | 8 +++++ include/git2/diff.h | 44 ++++++++++++++++++++++-- src/libgit2/diff.c | 23 +++++++++---- src/libgit2/diff.h | 12 +++---- src/libgit2/diff_file.c | 12 +++---- src/libgit2/diff_generate.c | 51 +++++++++++++++++++--------- src/libgit2/diff_parse.c | 24 ++++++++++--- src/libgit2/diff_print.c | 33 ++++++++++++++---- src/libgit2/diff_tform.c | 8 ++--- src/libgit2/patch.h | 8 ++++- src/libgit2/patch_generate.c | 29 +++++++++++++--- src/libgit2/patch_parse.c | 24 ++++++++----- tests/libgit2/apply/apply_helpers.h | 1 + tests/libgit2/apply/both.c | 52 ++++++++++++++--------------- tests/libgit2/apply/callbacks.c | 6 ++-- tests/libgit2/apply/check.c | 6 ++-- tests/libgit2/apply/index.c | 16 ++++----- tests/libgit2/apply/tree.c | 2 +- tests/libgit2/apply/workdir.c | 20 +++++------ tests/libgit2/diff/diff_helpers.c | 17 ++++++++++ tests/libgit2/diff/diff_helpers.h | 4 +++ tests/libgit2/diff/parse.c | 40 +++++++++++----------- tests/libgit2/diff/patchid.c | 3 +- tests/libgit2/diff/stats.c | 3 +- 24 files changed, 307 insertions(+), 139 deletions(-) diff --git a/examples/diff.c b/examples/diff.c index a9fb5d4428a..80c5200e908 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -188,9 +188,17 @@ static void compute_diff_no_index(git_diff **diff, struct diff_options *o) { check_lg2( git_patch_to_buf(&buf, patch), "patch to buf", NULL); + +#ifdef GIT_EXPERIMENTAL_SHA256 + check_lg2( + git_diff_from_buffer(diff, buf.ptr, buf.size, NULL), + "diff from patch", NULL); +#else check_lg2( git_diff_from_buffer(diff, buf.ptr, buf.size), "diff from patch", NULL); +#endif + git_patch_free(patch); git_buf_dispose(&buf); free(file1_str); diff --git a/include/git2/diff.h b/include/git2/diff.h index 850d215a613..384b6e74570 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -421,6 +421,22 @@ typedef struct { */ uint32_t interhunk_lines; + /** + * The object ID type to emit in diffs; this is used by functions + * that operate without a repository - namely `git_diff_buffers`, + * or `git_diff_blobs` and `git_diff_blob_to_buffer` when one blob + * is `NULL`. + * + * This may be omitted (set to `0`). If a repository is available, + * the object ID format of the repository will be used. If no + * repository is available then the default is `GIT_OID_SHA`. + * + * If this is specified and a repository is available, then the + * specified `oid_type` must match the repository's object ID + * format. + */ + git_oid_t oid_type; + /** * The abbreviation length to use when formatting object ids. * Defaults to the value of 'core.abbrev' from the config, or 7 if unset. @@ -1153,9 +1169,8 @@ GIT_EXTERN(int) git_diff_to_buf( /**@}*/ - /* - * Misc + * Low-level file comparison, invoking callbacks per difference. */ /** @@ -1271,6 +1286,25 @@ GIT_EXTERN(int) git_diff_buffers( git_diff_line_cb line_cb, void *payload); +/* Patch file parsing. */ + +/** + * Options for parsing a diff / patch file. + */ +typedef struct { + unsigned int version; + git_oid_t oid_type; +} git_diff_parse_options; + +/* The current version of the diff parse options structure */ +#define GIT_DIFF_PARSE_OPTIONS_VERSION 1 + +/* Stack initializer for diff parse options. Alternatively use + * `git_diff_parse_options_init` programmatic initialization. + */ +#define GIT_DIFF_PARSE_OPTIONS_INIT \ + { GIT_DIFF_PARSE_OPTIONS_VERSION, GIT_OID_DEFAULT } + /** * Read the contents of a git patch file into a `git_diff` object. * @@ -1293,7 +1327,11 @@ GIT_EXTERN(int) git_diff_buffers( GIT_EXTERN(int) git_diff_from_buffer( git_diff **out, const char *content, - size_t content_len); + size_t content_len +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_diff_parse_options *opts +#endif + ); /** * This is an opaque structure which is allocated by `git_diff_get_stats`. diff --git a/src/libgit2/diff.c b/src/libgit2/diff.c index 20a18c4b9b0..db12ccd6809 100644 --- a/src/libgit2/diff.c +++ b/src/libgit2/diff.c @@ -19,8 +19,10 @@ #include "git2/email.h" struct patch_id_args { + git_diff *diff; git_hash_ctx ctx; git_oid result; + git_oid_t oid_type; int first_file; }; @@ -280,17 +282,19 @@ int git_diff_find_options_init( return 0; } -static int flush_hunk(git_oid *result, git_hash_ctx *ctx) +static int flush_hunk(git_oid *result, struct patch_id_args *args) { + git_hash_ctx *ctx = &args->ctx; git_oid hash; unsigned short carry = 0; - int error, i; + size_t i; + int error; if ((error = git_hash_final(hash.id, ctx)) < 0 || (error = git_hash_init(ctx)) < 0) return error; - for (i = 0; i < GIT_OID_SHA1_SIZE; i++) { + for (i = 0; i < git_oid_size(args->oid_type); i++) { carry += result->id[i] + hash.id[i]; result->id[i] = (unsigned char)carry; carry >>= 8; @@ -338,7 +342,7 @@ static int diff_patchid_print_callback_to_buf( if (line->origin == GIT_DIFF_LINE_FILE_HDR && !args->first_file && - (error = flush_hunk(&args->result, &args->ctx) < 0)) + (error = flush_hunk(&args->result, args) < 0)) goto out; if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0) @@ -362,14 +366,19 @@ int git_diff_patchid_options_init(git_diff_patchid_options *opts, unsigned int v int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts) { struct patch_id_args args; + git_hash_algorithm_t algorithm; int error; GIT_ERROR_CHECK_VERSION( opts, GIT_DIFF_PATCHID_OPTIONS_VERSION, "git_diff_patchid_options"); + algorithm = git_oid_algorithm(diff->opts.oid_type); + memset(&args, 0, sizeof(args)); + args.diff = diff; args.first_file = 1; - if ((error = git_hash_ctx_init(&args.ctx, GIT_HASH_ALGORITHM_SHA1)) < 0) + args.oid_type = diff->opts.oid_type; + if ((error = git_hash_ctx_init(&args.ctx, algorithm)) < 0) goto out; if ((error = git_diff_print(diff, @@ -378,11 +387,11 @@ int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opt &args)) < 0) goto out; - if ((error = (flush_hunk(&args.result, &args.ctx))) < 0) + if ((error = (flush_hunk(&args.result, &args))) < 0) goto out; #ifdef GIT_EXPERIMENTAL_SHA256 - args.result.type = GIT_OID_SHA1; + args.result.type = diff->opts.oid_type; #endif git_oid_cpy(out, &args.result); diff --git a/src/libgit2/diff.h b/src/libgit2/diff.h index 2cc35e65b7c..f21b2764505 100644 --- a/src/libgit2/diff.h +++ b/src/libgit2/diff.h @@ -30,15 +30,15 @@ typedef enum { } git_diff_origin_t; struct git_diff { - git_refcount rc; + git_refcount rc; git_repository *repo; - git_attr_session attrsession; + git_attr_session attrsession; git_diff_origin_t type; - git_diff_options opts; - git_vector deltas; /* vector of git_diff_delta */ + git_diff_options opts; + git_vector deltas; /* vector of git_diff_delta */ git_pool pool; - git_iterator_t old_src; - git_iterator_t new_src; + git_iterator_t old_src; + git_iterator_t new_src; git_diff_perfdata perf; int (*strcomp)(const char *, const char *); diff --git a/src/libgit2/diff_file.c b/src/libgit2/diff_file.c index c2d08675ab0..6b7f9590caa 100644 --- a/src/libgit2/diff_file.c +++ b/src/libgit2/diff_file.c @@ -144,7 +144,7 @@ int git_diff_file_content__init_from_src( if (!src->blob && !src->buf) { fc->flags |= GIT_DIFF_FLAG__NO_DATA; - git_oid_clear(&fc->file->id, GIT_OID_SHA1); + git_oid_clear(&fc->file->id, opts->oid_type); } else { fc->flags |= GIT_DIFF_FLAG__LOADED; fc->file->flags |= GIT_DIFF_FLAG_VALID_ID; @@ -154,7 +154,7 @@ int git_diff_file_content__init_from_src( git_blob_dup((git_blob **)&fc->blob, (git_blob *) src->blob); fc->file->size = git_blob_rawsize(src->blob); git_oid_cpy(&fc->file->id, git_blob_id(src->blob)); - fc->file->id_abbrev = GIT_OID_SHA1_HEXSIZE; + fc->file->id_abbrev = (uint16_t)git_oid_hexsize(repo->oid_type); fc->map.len = (size_t)fc->file->size; fc->map.data = (char *)git_blob_rawcontent(src->blob); @@ -162,10 +162,10 @@ int git_diff_file_content__init_from_src( fc->flags |= GIT_DIFF_FLAG__FREE_BLOB; } else { int error; - if ((error = git_odb__hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB, GIT_OID_SHA1)) < 0) + if ((error = git_odb__hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB, opts->oid_type)) < 0) return error; fc->file->size = src->buflen; - fc->file->id_abbrev = GIT_OID_SHA1_HEXSIZE; + fc->file->id_abbrev = (uint16_t)git_oid_hexsize(opts->oid_type); fc->map.len = src->buflen; fc->map.data = (char *)src->buf; @@ -178,7 +178,7 @@ int git_diff_file_content__init_from_src( static int diff_file_content_commit_to_str( git_diff_file_content *fc, bool check_status) { - char oid[GIT_OID_SHA1_HEXSIZE+1]; + char oid[GIT_OID_MAX_HEXSIZE+1]; git_str content = GIT_STR_INIT; const char *status = ""; @@ -420,7 +420,7 @@ static int diff_file_content_load_workdir( if (!error && (fc->file->flags & GIT_DIFF_FLAG_VALID_ID) == 0) { error = git_odb__hash( &fc->file->id, fc->map.data, fc->map.len, - GIT_OBJECT_BLOB, GIT_OID_SHA1); + GIT_OBJECT_BLOB, diff_opts->oid_type); fc->file->flags |= GIT_DIFF_FLAG_VALID_ID; } diff --git a/src/libgit2/diff_generate.c b/src/libgit2/diff_generate.c index a88ce8c3230..78fe510e748 100644 --- a/src/libgit2/diff_generate.c +++ b/src/libgit2/diff_generate.c @@ -61,8 +61,8 @@ static git_diff_delta *diff_delta__alloc( } delta->status = status; - git_oid_clear(&delta->old_file.id, GIT_OID_SHA1); - git_oid_clear(&delta->new_file.id, GIT_OID_SHA1); + git_oid_clear(&delta->old_file.id, diff->base.opts.oid_type); + git_oid_clear(&delta->new_file.id, diff->base.opts.oid_type); return delta; } @@ -149,10 +149,13 @@ static int diff_delta__from_one( const git_index_entry *entry = nitem; bool has_old = false; git_diff_delta *delta; + git_oid_t oid_type; const char *matched_pathspec; GIT_ASSERT_ARG((oitem != NULL) ^ (nitem != NULL)); + oid_type = diff->base.opts.oid_type; + if (oitem) { entry = oitem; has_old = true; @@ -186,20 +189,23 @@ static int diff_delta__from_one( GIT_ASSERT(status != GIT_DELTA_MODIFIED); delta->nfiles = 1; + git_oid_clear(&delta->old_file.id, diff->base.opts.oid_type); + git_oid_clear(&delta->new_file.id, diff->base.opts.oid_type); + if (has_old) { delta->old_file.mode = entry->mode; delta->old_file.size = entry->file_size; delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS; git_oid_cpy(&delta->old_file.id, &entry->id); - git_oid_clear(&delta->new_file.id, GIT_OID_SHA1); - delta->old_file.id_abbrev = GIT_OID_SHA1_HEXSIZE; + git_oid_clear(&delta->new_file.id, oid_type); + delta->old_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); } else /* ADDED, IGNORED, UNTRACKED */ { delta->new_file.mode = entry->mode; delta->new_file.size = entry->file_size; delta->new_file.flags |= GIT_DIFF_FLAG_EXISTS; - git_oid_clear(&delta->old_file.id, GIT_OID_SHA1); + git_oid_clear(&delta->old_file.id, oid_type); git_oid_cpy(&delta->new_file.id, &entry->id); - delta->new_file.id_abbrev = GIT_OID_SHA1_HEXSIZE; + delta->new_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); } delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; @@ -225,6 +231,9 @@ static int diff_delta__from_two( const git_oid *old_id = &old_entry->id; git_diff_delta *delta; const char *canonical_path = old_entry->path; + git_oid_t oid_type; + + oid_type = diff->base.opts.oid_type; if (status == GIT_DELTA_UNMODIFIED && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNMODIFIED)) @@ -254,14 +263,14 @@ static int diff_delta__from_two( delta->old_file.size = old_entry->file_size; delta->old_file.mode = old_mode; git_oid_cpy(&delta->old_file.id, old_id); - delta->old_file.id_abbrev = GIT_OID_SHA1_HEXSIZE; + delta->old_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID | GIT_DIFF_FLAG_EXISTS; } if (!git_index_entry_is_conflict(new_entry)) { git_oid_cpy(&delta->new_file.id, new_id); - delta->new_file.id_abbrev = GIT_OID_SHA1_HEXSIZE; + delta->new_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); delta->new_file.size = new_entry->file_size; delta->new_file.mode = new_mode; delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS; @@ -490,6 +499,14 @@ static int diff_generated_apply_options( return -1; } + if (!diff->base.opts.oid_type) { + diff->base.opts.oid_type = repo->oid_type; + } else if (diff->base.opts.oid_type != repo->oid_type) { + git_error_set(GIT_ERROR_INVALID, + "specified object ID type does not match repository object ID type"); + return -1; + } + /* flag INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)) diff->base.opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; @@ -603,7 +620,7 @@ int git_diff__oid_for_file( entry.mode = mode; entry.file_size = (uint32_t)size; entry.path = (char *)path; - git_oid_clear(&entry.id, GIT_OID_SHA1); + git_oid_clear(&entry.id, diff->opts.oid_type); return git_diff__oid_for_entry(out, diff, &entry, mode, NULL); } @@ -624,7 +641,7 @@ int git_diff__oid_for_entry( GIT_ASSERT(d->type == GIT_DIFF_TYPE_GENERATED); diff = (git_diff_generated *)d; - git_oid_clear(out, GIT_OID_SHA1); + git_oid_clear(out, diff->base.opts.oid_type); if (git_repository_workdir_path(&full_path, diff->base.repo, entry.path) < 0) return -1; @@ -660,7 +677,8 @@ int git_diff__oid_for_entry( git_error_clear(); } } else if (S_ISLNK(mode)) { - error = git_odb__hashlink(out, full_path.ptr, GIT_OID_SHA1); + error = git_odb__hashlink(out, full_path.ptr, + diff->base.opts.oid_type); diff->base.perf.oid_calculations++; } else if (!git__is_sizet(entry.file_size)) { git_error_set(GIT_ERROR_NOMEMORY, "file size overflow (for 32-bits) on '%s'", @@ -676,7 +694,8 @@ int git_diff__oid_for_entry( else { error = git_odb__hashfd_filtered( out, fd, (size_t)entry.file_size, - GIT_OBJECT_BLOB, GIT_OID_SHA1, fl); + GIT_OBJECT_BLOB, diff->base.opts.oid_type, + fl); p_close(fd); diff->base.perf.oid_calculations++; } @@ -785,7 +804,7 @@ static int maybe_modified( git_diff_generated *diff, diff_in_progress *info) { - git_oid noid = GIT_OID_SHA1_ZERO; + git_oid noid; git_delta_t status = GIT_DELTA_MODIFIED; const git_index_entry *oitem = info->oitem; const git_index_entry *nitem = info->nitem; @@ -796,6 +815,8 @@ static int maybe_modified( const char *matched_pathspec; int error = 0; + git_oid_clear(&noid, diff->base.opts.oid_type); + if (!diff_pathspec_match(&matched_pathspec, diff, oitem)) return 0; @@ -1700,11 +1721,11 @@ int git_diff__commit( *out = NULL; if ((parents = git_commit_parentcount(commit)) > 1) { - char commit_oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + char commit_oidstr[GIT_OID_MAX_HEXSIZE + 1]; error = -1; git_error_set(GIT_ERROR_INVALID, "commit %s is a merge commit", - git_oid_tostr(commit_oidstr, GIT_OID_SHA1_HEXSIZE + 1, git_commit_id(commit))); + git_oid_tostr(commit_oidstr, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit))); goto on_error; } diff --git a/src/libgit2/diff_parse.c b/src/libgit2/diff_parse.c index 75e41a5443b..04603969e40 100644 --- a/src/libgit2/diff_parse.c +++ b/src/libgit2/diff_parse.c @@ -29,7 +29,7 @@ static void diff_parsed_free(git_diff *d) git__free(diff); } -static git_diff_parsed *diff_parsed_alloc(void) +static git_diff_parsed *diff_parsed_alloc(git_oid_t oid_type) { git_diff_parsed *diff; @@ -51,6 +51,7 @@ static git_diff_parsed *diff_parsed_alloc(void) } diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE; + diff->base.opts.oid_type = oid_type; if (git_pool_init(&diff->base.pool, 1) < 0 || git_vector_init(&diff->patches, 0, NULL) < 0 || @@ -67,19 +68,34 @@ static git_diff_parsed *diff_parsed_alloc(void) int git_diff_from_buffer( git_diff **out, const char *content, - size_t content_len) + size_t content_len +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_diff_parse_options *opts +#endif + ) { git_diff_parsed *diff; git_patch *patch; git_patch_parse_ctx *ctx = NULL; + git_patch_options patch_opts = GIT_PATCH_OPTIONS_INIT; + git_oid_t oid_type; int error = 0; *out = NULL; - diff = diff_parsed_alloc(); +#ifdef GIT_EXPERIMENTAL_SHA256 + oid_type = (opts && opts->oid_type) ? opts->oid_type : + GIT_OID_DEFAULT; +#else + oid_type = GIT_OID_DEFAULT; +#endif + + patch_opts.oid_type = oid_type; + + diff = diff_parsed_alloc(oid_type); GIT_ERROR_CHECK_ALLOC(diff); - ctx = git_patch_parse_ctx_init(content, content_len, NULL); + ctx = git_patch_parse_ctx_init(content, content_len, &patch_opts); GIT_ERROR_CHECK_ALLOC(ctx); while (ctx->parse_ctx.remain_len) { diff --git a/src/libgit2/diff_print.c b/src/libgit2/diff_print.c index 3077e11e157..32c93682679 100644 --- a/src/libgit2/diff_print.c +++ b/src/libgit2/diff_print.c @@ -29,6 +29,7 @@ typedef struct { const char *new_prefix; uint32_t flags; int id_strlen; + git_oid_t oid_type; int (*strcomp)(const char *, const char *); } diff_print_info; @@ -46,6 +47,8 @@ static int diff_print_info_init__common( pi->payload = payload; pi->buf = out; + GIT_ASSERT(pi->oid_type); + if (!pi->id_strlen) { if (!repo) pi->id_strlen = GIT_ABBREV_DEFAULT; @@ -53,8 +56,9 @@ static int diff_print_info_init__common( return -1; } - if (pi->id_strlen > GIT_OID_SHA1_HEXSIZE) - pi->id_strlen = GIT_OID_SHA1_HEXSIZE; + if (pi->id_strlen > 0 && + (size_t)pi->id_strlen > git_oid_hexsize(pi->oid_type)) + pi->id_strlen = (int)git_oid_hexsize(pi->oid_type); memset(&pi->line, 0, sizeof(pi->line)); pi->line.old_lineno = -1; @@ -78,6 +82,7 @@ static int diff_print_info_init_fromdiff( if (diff) { pi->flags = diff->opts.flags; + pi->oid_type = diff->opts.oid_type; pi->id_strlen = diff->opts.id_abbrev; pi->old_prefix = diff->opts.old_prefix; pi->new_prefix = diff->opts.new_prefix; @@ -101,6 +106,7 @@ static int diff_print_info_init_frompatch( memset(pi, 0, sizeof(diff_print_info)); pi->flags = patch->diff_opts.flags; + pi->oid_type = patch->diff_opts.oid_type; pi->id_strlen = patch->diff_opts.id_abbrev; pi->old_prefix = patch->diff_opts.old_prefix; pi->new_prefix = patch->diff_opts.new_prefix; @@ -212,7 +218,10 @@ static int diff_print_one_raw( git_str *out = pi->buf; int id_abbrev; char code = git_diff_status_char(delta->status); - char start_oid[GIT_OID_SHA1_HEXSIZE+1], end_oid[GIT_OID_SHA1_HEXSIZE+1]; + char start_oid[GIT_OID_MAX_HEXSIZE + 1], + end_oid[GIT_OID_MAX_HEXSIZE + 1]; + size_t oid_hexsize; + bool id_is_abbrev; GIT_UNUSED(progress); @@ -231,12 +240,21 @@ static int diff_print_one_raw( return -1; } +#ifdef GIT_EXPERIMENTAL_SHA256 + GIT_ASSERT(delta->old_file.id.type == delta->new_file.id.type); + oid_hexsize = git_oid_hexsize(delta->old_file.id.type); +#else + oid_hexsize = GIT_OID_SHA1_HEXSIZE; +#endif + + id_is_abbrev = (pi->id_strlen > 0 && + (size_t)pi->id_strlen <= oid_hexsize); + git_oid_tostr(start_oid, pi->id_strlen + 1, &delta->old_file.id); git_oid_tostr(end_oid, pi->id_strlen + 1, &delta->new_file.id); - git_str_printf( - out, (pi->id_strlen <= GIT_OID_SHA1_HEXSIZE) ? - ":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c", + git_str_printf(out, + id_is_abbrev ? ":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c", delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code); if (delta->similarity > 0) @@ -273,7 +291,8 @@ static int diff_print_oid_range( git_str *out, const git_diff_delta *delta, int id_strlen, bool print_index) { - char start_oid[GIT_OID_SHA1_HEXSIZE+1], end_oid[GIT_OID_SHA1_HEXSIZE+1]; + char start_oid[GIT_OID_MAX_HEXSIZE + 1], + end_oid[GIT_OID_MAX_HEXSIZE + 1]; if (delta->old_file.mode && id_strlen > delta->old_file.id_abbrev) { diff --git a/src/libgit2/diff_tform.c b/src/libgit2/diff_tform.c index 8c0c1b7fc5e..4a156c7a341 100644 --- a/src/libgit2/diff_tform.c +++ b/src/libgit2/diff_tform.c @@ -364,7 +364,7 @@ static int insert_delete_side_of_split( memset(&deleted->new_file, 0, sizeof(deleted->new_file)); deleted->new_file.path = deleted->old_file.path; deleted->new_file.flags |= GIT_DIFF_FLAG_VALID_ID; - git_oid_clear(&deleted->new_file.id, GIT_OID_SHA1); + git_oid_clear(&deleted->new_file.id, diff->opts.oid_type); return git_vector_insert(onto, deleted); } @@ -398,7 +398,7 @@ static int apply_splits_and_deletes( memset(&delta->old_file, 0, sizeof(delta->old_file)); delta->old_file.path = delta->new_file.path; delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; - git_oid_clear(&delta->old_file.id, GIT_OID_SHA1); + git_oid_clear(&delta->old_file.id, diff->opts.oid_type); } /* clean up delta before inserting into new list */ @@ -997,7 +997,7 @@ int git_diff_find_similar( memset(&src->new_file, 0, sizeof(src->new_file)); src->new_file.path = src->old_file.path; src->new_file.flags |= GIT_DIFF_FLAG_VALID_ID; - git_oid_clear(&src->new_file.id, GIT_OID_SHA1); + git_oid_clear(&src->new_file.id, diff->opts.oid_type); num_updates++; @@ -1023,7 +1023,7 @@ int git_diff_find_similar( memset(&src->old_file, 0, sizeof(src->old_file)); src->old_file.path = src->new_file.path; src->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; - git_oid_clear(&src->old_file.id, GIT_OID_SHA1); + git_oid_clear(&src->old_file.id, diff->opts.oid_type); src->flags &= ~GIT_DIFF_FLAG__TO_SPLIT; num_rewrites--; diff --git a/src/libgit2/patch.h b/src/libgit2/patch.h index 1e1471ed613..86328e886e7 100644 --- a/src/libgit2/patch.h +++ b/src/libgit2/patch.h @@ -59,9 +59,15 @@ typedef struct { * This prefix will be removed when looking for files. The default is 1. */ uint32_t prefix_len; + + /** + * The type of object IDs in the patch file. The default is + * `GIT_OID_DEFAULT`. + */ + git_oid_t oid_type; } git_patch_options; -#define GIT_PATCH_OPTIONS_INIT { 1 } +#define GIT_PATCH_OPTIONS_INIT { 1, GIT_OID_DEFAULT } extern int git_patch__to_buf(git_str *out, git_patch *patch); extern void git_patch_free(git_patch *patch); diff --git a/src/libgit2/patch_generate.c b/src/libgit2/patch_generate.c index bc598fea870..079bc53ae9b 100644 --- a/src/libgit2/patch_generate.c +++ b/src/libgit2/patch_generate.c @@ -81,7 +81,8 @@ static void patch_generated_init_common(git_patch_generated *patch) static int patch_generated_normalize_options( git_diff_options *out, - const git_diff_options *opts) + const git_diff_options *opts, + git_repository *repo) { if (opts) { GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); @@ -91,6 +92,23 @@ static int patch_generated_normalize_options( memcpy(out, &default_opts, sizeof(git_diff_options)); } + if (repo && opts && opts->oid_type && repo->oid_type != opts->oid_type) { + /* + * This limitation feels unnecessary - we should consider + * allowing users to generate diffs with a different object + * ID format than the repository. + */ + git_error_set(GIT_ERROR_INVALID, + "specified object ID type does not match repository object ID type"); + return -1; + } else if (repo) { + out->oid_type = repo->oid_type; + } else if (opts && opts->oid_type) { + out->oid_type = opts->oid_type; + } else { + out->oid_type = GIT_OID_DEFAULT; + } + out->old_prefix = opts && opts->old_prefix ? git__strdup(opts->old_prefix) : git__strdup(DIFF_OLD_PREFIX_DEFAULT); @@ -118,7 +136,7 @@ static int patch_generated_init( patch->delta_index = delta_index; if ((error = patch_generated_normalize_options( - &patch->base.diff_opts, &diff->opts)) < 0 || + &patch->base.diff_opts, &diff->opts, diff->repo)) < 0 || (error = git_diff_file_content__init_from_diff( &patch->ofile, diff, patch->base.delta, true)) < 0 || (error = git_diff_file_content__init_from_diff( @@ -449,7 +467,7 @@ static int patch_generated_from_sources( git_xdiff_output *xo, git_diff_file_content_src *oldsrc, git_diff_file_content_src *newsrc, - const git_diff_options *opts) + const git_diff_options *given_opts) { int error = 0; git_repository *repo = @@ -457,11 +475,12 @@ static int patch_generated_from_sources( newsrc->blob ? git_blob_owner(newsrc->blob) : NULL; git_diff_file *lfile = &pd->delta.old_file, *rfile = &pd->delta.new_file; git_diff_file_content *ldata = &pd->patch.ofile, *rdata = &pd->patch.nfile; + git_diff_options *opts = &pd->patch.base.diff_opts; - if ((error = patch_generated_normalize_options(&pd->patch.base.diff_opts, opts)) < 0) + if ((error = patch_generated_normalize_options(opts, given_opts, repo)) < 0) return error; - if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { + if ((opts->flags & GIT_DIFF_REVERSE) != 0) { void *tmp = lfile; lfile = rfile; rfile = tmp; tmp = ldata; ldata = rdata; rdata = tmp; } diff --git a/src/libgit2/patch_parse.c b/src/libgit2/patch_parse.c index ffdb99231a2..c06915537f2 100644 --- a/src/libgit2/patch_parse.c +++ b/src/libgit2/patch_parse.c @@ -166,15 +166,19 @@ static int parse_header_oid( uint16_t *oid_len, git_patch_parse_ctx *ctx) { - size_t len; + size_t hexsize, len; + + hexsize = git_oid_hexsize(ctx->opts.oid_type); - for (len = 0; len < ctx->parse_ctx.line_len && len < GIT_OID_SHA1_HEXSIZE; len++) { + for (len = 0; + len < ctx->parse_ctx.line_len && len < hexsize; + len++) { if (!git__isxdigit(ctx->parse_ctx.line[len])) break; } - if (len < GIT_OID_MINPREFIXLEN || len > GIT_OID_SHA1_HEXSIZE || - git_oid__fromstrn(oid, ctx->parse_ctx.line, len, GIT_OID_SHA1) < 0) + if (len < GIT_OID_MINPREFIXLEN || len > hexsize || + git_oid__fromstrn(oid, ctx->parse_ctx.line, len, ctx->opts.oid_type) < 0) return git_parse_err("invalid hex formatted object id at line %"PRIuZ, ctx->parse_ctx.line_num); @@ -1065,12 +1069,14 @@ static int check_patch(git_patch_parsed *patch) return git_parse_err("patch with no hunks"); if (delta->status == GIT_DELTA_ADDED) { - git_oid_clear(&delta->old_file.id, GIT_OID_SHA1); + git_oid_clear(&delta->old_file.id, + patch->base.diff_opts.oid_type); delta->old_file.id_abbrev = 0; } if (delta->status == GIT_DELTA_DELETED) { - git_oid_clear(&delta->new_file.id, GIT_OID_SHA1); + git_oid_clear(&delta->new_file.id, + patch->base.diff_opts.oid_type); delta->new_file.id_abbrev = 0; } @@ -1187,11 +1193,13 @@ int git_patch_parse( patch->base.delta->status = GIT_DELTA_MODIFIED; patch->base.delta->nfiles = 2; + patch->base.diff_opts.oid_type = ctx->opts.oid_type; + start = ctx->parse_ctx.remain_len; if ((error = parse_patch_header(patch, ctx)) < 0 || - (error = parse_patch_body(patch, ctx)) < 0 || - (error = check_patch(patch)) < 0) + (error = parse_patch_body(patch, ctx)) < 0 || + (error = check_patch(patch)) < 0) goto done; used = start - ctx->parse_ctx.remain_len; diff --git a/tests/libgit2/apply/apply_helpers.h b/tests/libgit2/apply/apply_helpers.h index 82094773e15..b1a1479de45 100644 --- a/tests/libgit2/apply/apply_helpers.h +++ b/tests/libgit2/apply/apply_helpers.h @@ -1,4 +1,5 @@ #include "../merge/merge_helpers.h" +#include "../diff/diff_helpers.h" #define TEST_REPO_PATH "merge-recursive" diff --git a/tests/libgit2/apply/both.c b/tests/libgit2/apply/both.c index 1331e7ea452..44c5b19371f 100644 --- a/tests/libgit2/apply/both.c +++ b/tests/libgit2/apply/both.c @@ -78,7 +78,7 @@ void test_apply_both__parsed_diff(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -102,7 +102,7 @@ void test_apply_both__removes_file(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_DELETE_FILE, strlen(DIFF_DELETE_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -128,7 +128,7 @@ void test_apply_both__adds_file(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -161,7 +161,7 @@ void test_apply_both__application_failure_leaves_index_unmodified(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -198,7 +198,7 @@ void test_apply_both__index_must_match_workdir(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); git_diff_free(diff); @@ -214,7 +214,7 @@ void test_apply_both__index_mode_must_match_workdir(void) /* Set a file in the working directory executable. */ cl_must_pass(p_chmod("merge-recursive/asparagus.txt", 0755)); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -248,7 +248,7 @@ void test_apply_both__application_failure_leaves_workdir_unmodified(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); @@ -301,7 +301,7 @@ void test_apply_both__keeps_nonconflicting_changes(void) cl_git_rmfile("merge-recursive/oyster.txt"); cl_git_rewritefile("merge-recursive/gravy.txt", "Hello, world.\n"); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -341,7 +341,7 @@ void test_apply_both__can_apply_nonconflicting_file_changes(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); validate_apply_index(repo, both_expected, both_expected_cnt); @@ -391,7 +391,7 @@ void test_apply_both__honors_crlf_attributes(void) cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -415,7 +415,7 @@ void test_apply_both__rename(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_FILE, strlen(DIFF_RENAME_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -440,7 +440,7 @@ void test_apply_both__rename_and_modify(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_FILE, strlen(DIFF_RENAME_AND_MODIFY_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -465,7 +465,7 @@ void test_apply_both__rename_a_to_b_to_c(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C, strlen(DIFF_RENAME_A_TO_B_TO_C))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -490,7 +490,7 @@ void test_apply_both__rename_a_to_b_to_c_exact(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C_EXACT, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C_EXACT, strlen(DIFF_RENAME_A_TO_B_TO_C_EXACT))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -515,7 +515,7 @@ void test_apply_both__rename_circular(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_CIRCULAR, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_CIRCULAR, strlen(DIFF_RENAME_CIRCULAR))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -539,7 +539,7 @@ void test_apply_both__rename_2_to_1(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_2_TO_1, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_2_TO_1, strlen(DIFF_RENAME_2_TO_1))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -565,7 +565,7 @@ void test_apply_both__rename_1_to_2(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_1_TO_2, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_1_TO_2, strlen(DIFF_RENAME_1_TO_2))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -590,7 +590,7 @@ void test_apply_both__two_deltas_one_file(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_FILE, strlen(DIFF_TWO_DELTAS_ONE_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -616,7 +616,7 @@ void test_apply_both__two_deltas_one_new_file(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_NEW_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_NEW_FILE, strlen(DIFF_TWO_DELTAS_ONE_NEW_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -641,7 +641,7 @@ void test_apply_both__rename_and_modify_deltas(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_DELTAS, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_DELTAS, strlen(DIFF_RENAME_AND_MODIFY_DELTAS))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -667,7 +667,7 @@ void test_apply_both__rename_delta_after_modify_delta(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY, strlen(DIFF_RENAME_AFTER_MODIFY))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -681,7 +681,7 @@ void test_apply_both__cant_rename_after_modify_nonexistent_target_path(void) { git_diff *diff; - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY_TARGET_PATH, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY_TARGET_PATH, strlen(DIFF_RENAME_AFTER_MODIFY_TARGET_PATH))); cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -692,7 +692,7 @@ void test_apply_both__cant_modify_source_path_after_rename(void) { git_diff *diff; - cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_SOURCE_PATH, + cl_git_pass(diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_SOURCE_PATH, strlen(DIFF_RENAME_AND_MODIFY_SOURCE_PATH))); cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -714,7 +714,7 @@ void test_apply_both__readd_deleted_file(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_AND_READD_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_DELETE_AND_READD_FILE, strlen(DIFF_DELETE_AND_READD_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -728,7 +728,7 @@ void test_apply_both__cant_remove_file_twice(void) { git_diff *diff; - cl_git_pass(git_diff_from_buffer(&diff, DIFF_REMOVE_FILE_TWICE, + cl_git_pass(diff_from_buffer(&diff, DIFF_REMOVE_FILE_TWICE, strlen(DIFF_REMOVE_FILE_TWICE))); cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); @@ -739,7 +739,7 @@ void test_apply_both__cant_add_invalid_filename(void) { git_diff *diff; - cl_git_pass(git_diff_from_buffer(&diff, DIFF_ADD_INVALID_FILENAME, + cl_git_pass(diff_from_buffer(&diff, DIFF_ADD_INVALID_FILENAME, strlen(DIFF_ADD_INVALID_FILENAME))); cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); diff --git a/tests/libgit2/apply/callbacks.c b/tests/libgit2/apply/callbacks.c index 2f9af310161..f076ca48622 100644 --- a/tests/libgit2/apply/callbacks.c +++ b/tests/libgit2/apply/callbacks.c @@ -40,7 +40,7 @@ void test_apply_callbacks__delta_aborts(void) opts.delta_cb = delta_abort_cb; - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_fail_with(-99, git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts)); @@ -79,7 +79,7 @@ void test_apply_callbacks__delta_can_skip(void) opts.delta_cb = delta_skip_cb; - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); @@ -117,7 +117,7 @@ void test_apply_callbacks__hunk_can_skip(void) opts.hunk_cb = hunk_skip_odds_cb; opts.payload = &count; - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MANY_CHANGES_ONE, strlen(DIFF_MANY_CHANGES_ONE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); diff --git a/tests/libgit2/apply/check.c b/tests/libgit2/apply/check.c index d055d455b8f..0c1f86dc531 100644 --- a/tests/libgit2/apply/check.c +++ b/tests/libgit2/apply/check.c @@ -60,7 +60,7 @@ void test_apply_check__parsed_diff(void) git_apply_options opts = GIT_APPLY_OPTIONS_INIT; opts.flags |= GIT_APPLY_CHECK; - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts)); @@ -76,7 +76,7 @@ void test_apply_check__binary(void) git_apply_options opts = GIT_APPLY_OPTIONS_INIT; opts.flags |= GIT_APPLY_CHECK; - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES_BINARY, strlen(DIFF_MODIFY_TWO_FILES_BINARY))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts)); @@ -112,7 +112,7 @@ void test_apply_check__does_not_apply(void) git_index_free(index); opts.flags |= GIT_APPLY_CHECK; - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts)); validate_apply_index(repo, index_expected, index_expected_cnt); diff --git a/tests/libgit2/apply/index.c b/tests/libgit2/apply/index.c index 2dc0d53cb34..564d55c8c1c 100644 --- a/tests/libgit2/apply/index.c +++ b/tests/libgit2/apply/index.c @@ -78,7 +78,7 @@ void test_apply_index__parsed_diff(void) size_t index_expected_cnt = sizeof(index_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); @@ -102,7 +102,7 @@ void test_apply_index__removes_file(void) size_t index_expected_cnt = sizeof(index_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_DELETE_FILE, strlen(DIFF_DELETE_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); @@ -128,7 +128,7 @@ void test_apply_index__adds_file(void) size_t index_expected_cnt = sizeof(index_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); @@ -169,7 +169,7 @@ void test_apply_index__modified_workdir_with_unmodified_index_is_ok(void) cl_git_rmfile("merge-recursive/asparagus.txt"); cl_git_rewritefile("merge-recursive/veal.txt", "Hello, world.\n"); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -201,7 +201,7 @@ void test_apply_index__application_failure_leaves_index_unmodified(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -240,7 +240,7 @@ void test_apply_index__keeps_nonconflicting_changes(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -285,7 +285,7 @@ void test_apply_index__can_apply_nonconflicting_file_changes(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -311,7 +311,7 @@ void test_apply_index__change_mode(void) size_t index_expected_cnt = sizeof(index_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); diff --git a/tests/libgit2/apply/tree.c b/tests/libgit2/apply/tree.c index 667bb9d401a..b97fe8d352b 100644 --- a/tests/libgit2/apply/tree.c +++ b/tests/libgit2/apply/tree.c @@ -81,7 +81,7 @@ void test_apply_tree__adds_file(void) cl_git_pass(git_commit_tree(&a_tree, a_commit)); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); cl_git_pass(git_apply_to_tree(&index, repo, a_tree, diff, NULL)); diff --git a/tests/libgit2/apply/workdir.c b/tests/libgit2/apply/workdir.c index e1011d114cc..5ae56847a80 100644 --- a/tests/libgit2/apply/workdir.c +++ b/tests/libgit2/apply/workdir.c @@ -77,7 +77,7 @@ void test_apply_workdir__parsed_diff(void) size_t workdir_expected_cnt = sizeof(workdir_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); @@ -101,7 +101,7 @@ void test_apply_workdir__removes_file(void) size_t workdir_expected_cnt = sizeof(workdir_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, + cl_git_pass(diff_from_buffer(&diff, DIFF_DELETE_FILE, strlen(DIFF_DELETE_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); @@ -127,7 +127,7 @@ void test_apply_workdir__adds_file(void) size_t workdir_expected_cnt = sizeof(workdir_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); @@ -177,7 +177,7 @@ void test_apply_workdir__modified_index_with_unmodified_workdir_is_ok(void) cl_git_pass(git_index_remove(index, "asparagus.txt", 0)); cl_git_pass(git_index_write(index)); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); validate_apply_index(repo, index_expected, index_expected_cnt); @@ -208,7 +208,7 @@ void test_apply_workdir__application_failure_leaves_workdir_unmodified(void) cl_git_rewritefile("merge-recursive/veal.txt", "This is a modification.\n"); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); @@ -233,7 +233,7 @@ void test_apply_workdir__keeps_nonconflicting_changes(void) cl_git_rmfile("merge-recursive/oyster.txt"); cl_git_rewritefile("merge-recursive/gravy.txt", "Hello, world.\n"); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); @@ -268,7 +268,7 @@ void test_apply_workdir__can_apply_nonconflicting_file_changes(void) cl_git_append2file("merge-recursive/asparagus.txt", "This line is added in the workdir.\n"); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); validate_index_unchanged(repo); @@ -295,7 +295,7 @@ void test_apply_workdir__change_mode(void) size_t workdir_expected_cnt = sizeof(workdir_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(diff_from_buffer(&diff, diff_file, strlen(diff_file))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); validate_index_unchanged(repo); @@ -321,7 +321,7 @@ void test_apply_workdir__apply_many_changes_one(void) size_t workdir_expected_cnt = sizeof(workdir_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MANY_CHANGES_ONE, strlen(DIFF_MANY_CHANGES_ONE))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); @@ -347,7 +347,7 @@ void test_apply_workdir__apply_many_changes_two(void) size_t workdir_expected_cnt = sizeof(workdir_expected) / sizeof(struct merge_index_entry); - cl_git_pass(git_diff_from_buffer(&diff, + cl_git_pass(diff_from_buffer(&diff, DIFF_MANY_CHANGES_TWO, strlen(DIFF_MANY_CHANGES_TWO))); cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); diff --git a/tests/libgit2/diff/diff_helpers.c b/tests/libgit2/diff/diff_helpers.c index 341b0a448a3..5daebffeb3c 100644 --- a/tests/libgit2/diff/diff_helpers.c +++ b/tests/libgit2/diff/diff_helpers.c @@ -314,3 +314,20 @@ void diff_assert_equal(git_diff *a, git_diff *b) } } +#ifdef GIT_EXPERIMENTAL_SHA256 +int diff_from_buffer( + git_diff **out, + const char *content, + size_t content_len) +{ + return git_diff_from_buffer(out, content, content_len, NULL); +} +#else +int diff_from_buffer( + git_diff **out, + const char *content, + size_t content_len) +{ + return git_diff_from_buffer(out, content, content_len); +} +#endif diff --git a/tests/libgit2/diff/diff_helpers.h b/tests/libgit2/diff/diff_helpers.h index af855ce684f..1be4b47801c 100644 --- a/tests/libgit2/diff/diff_helpers.h +++ b/tests/libgit2/diff/diff_helpers.h @@ -71,3 +71,7 @@ extern void diff_print_raw(FILE *fp, git_diff *diff); extern void diff_assert_equal(git_diff *a, git_diff *b); +extern int diff_from_buffer( + git_diff **out, + const char *content, + size_t content_len); diff --git a/tests/libgit2/diff/parse.c b/tests/libgit2/diff/parse.c index cae843cc836..79745b99503 100644 --- a/tests/libgit2/diff/parse.c +++ b/tests/libgit2/diff/parse.c @@ -19,19 +19,19 @@ void test_diff_parse__nonpatches_fail_with_notfound(void) const char *not_with_both = "Lead.\n" PATCH_NOT_A_PATCH "Trail.\n"; cl_git_fail_with(GIT_ENOTFOUND, - git_diff_from_buffer(&diff, + diff_from_buffer(&diff, not, strlen(not))); cl_git_fail_with(GIT_ENOTFOUND, - git_diff_from_buffer(&diff, + diff_from_buffer(&diff, not_with_leading, strlen(not_with_leading))); cl_git_fail_with(GIT_ENOTFOUND, - git_diff_from_buffer(&diff, + diff_from_buffer(&diff, not_with_trailing, strlen(not_with_trailing))); cl_git_fail_with(GIT_ENOTFOUND, - git_diff_from_buffer(&diff, + diff_from_buffer(&diff, not_with_both, strlen(not_with_both))); } @@ -51,7 +51,7 @@ static void test_parse_invalid_diff(const char *invalid_diff) git_str_puts(&buf, PATCH_BINARY_LITERAL); cl_git_fail_with(GIT_ERROR, - git_diff_from_buffer(&diff, buf.ptr, buf.size)); + diff_from_buffer(&diff, buf.ptr, buf.size)); git_str_dispose(&buf); } @@ -72,7 +72,7 @@ void test_diff_parse__exact_rename(void) "2.9.3\n"; git_diff *diff; - cl_git_pass(git_diff_from_buffer( + cl_git_pass(diff_from_buffer( &diff, content, strlen(content))); git_diff_free(diff); } @@ -92,7 +92,7 @@ void test_diff_parse__empty_file(void) "2.20.1\n"; git_diff *diff; - cl_git_pass(git_diff_from_buffer( + cl_git_pass(diff_from_buffer( &diff, content, strlen(content))); git_diff_free(diff); } @@ -102,7 +102,7 @@ void test_diff_parse__no_extended_headers(void) const char *content = PATCH_NO_EXTENDED_HEADERS; git_diff *diff; - cl_git_pass(git_diff_from_buffer( + cl_git_pass(diff_from_buffer( &diff, content, strlen(content))); git_diff_free(diff); } @@ -125,7 +125,7 @@ void test_diff_parse__add_delete_no_index(void) "-three\n"; git_diff *diff; - cl_git_pass(git_diff_from_buffer( + cl_git_pass(diff_from_buffer( &diff, content, strlen(content))); git_diff_free(diff); } @@ -166,7 +166,7 @@ static void test_tree_to_tree_computed_to_parsed( cl_git_pass(git_diff_to_buf(&computed_buf, computed, GIT_DIFF_FORMAT_PATCH)); - cl_git_pass(git_diff_from_buffer(&parsed, + cl_git_pass(diff_from_buffer(&parsed, computed_buf.ptr, computed_buf.size)); diff_assert_equal(computed, parsed); @@ -248,7 +248,7 @@ void test_diff_parse__get_patch_from_diff(void) computed, GIT_DIFF_FORMAT_PATCH)); cl_git_pass(git_patch_from_diff(&patch_computed, computed, 0)); - cl_git_pass(git_diff_from_buffer(&parsed, + cl_git_pass(diff_from_buffer(&parsed, computed_buf.ptr, computed_buf.size)); cl_git_pass(git_patch_from_diff(&patch_parsed, parsed, 0)); @@ -292,7 +292,7 @@ void test_diff_parse__foreach_works_with_parsed_patch(void) int called = 0; git_diff *diff; - cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(diff_from_buffer(&diff, patch, strlen(patch))); cl_git_pass(git_diff_foreach(diff, file_cb, NULL, NULL, NULL, &called)); cl_assert_equal_i(called, 1); @@ -312,7 +312,7 @@ void test_diff_parse__parsing_minimal_patch_succeeds(void) git_buf buf = GIT_BUF_INIT; git_diff *diff; - cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(diff_from_buffer(&diff, patch, strlen(patch))); cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH)); cl_assert_equal_s(patch, buf.ptr); @@ -330,7 +330,7 @@ void test_diff_parse__patch_roundtrip_succeeds(void) cl_git_pass(git_patch_from_buffers(&patch, buf1, strlen(buf1), "obj1", buf2, strlen(buf2), "obj2", NULL)); cl_git_pass(git_patch_to_buf(&patchbuf, patch)); - cl_git_pass(git_diff_from_buffer(&diff, patchbuf.ptr, patchbuf.size)); + cl_git_pass(diff_from_buffer(&diff, patchbuf.ptr, patchbuf.size)); cl_git_pass(git_diff_to_buf(&diffbuf, diff, GIT_DIFF_FORMAT_PATCH)); cl_assert_equal_s(patchbuf.ptr, diffbuf.ptr); @@ -372,7 +372,7 @@ void test_diff_parse__issue4672(void) const git_diff_hunk *hunk; size_t n, l = 0; - cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text))); + cl_git_pass(diff_from_buffer(&diff, text, strlen(text))); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); cl_git_pass(git_patch_get_hunk(&hunk, &n, patch, 0)); @@ -393,7 +393,7 @@ void test_diff_parse__lineinfo(void) const git_diff_hunk *hunk; size_t n, l = 0; - cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text))); + cl_git_pass(diff_from_buffer(&diff, text, strlen(text))); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); cl_git_pass(git_patch_get_hunk(&hunk, &n, patch, 0)); @@ -419,7 +419,7 @@ void test_diff_parse__new_file_with_space(void) git_patch *patch; git_diff *diff; - cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content))); + cl_git_pass(diff_from_buffer(&diff, content, strlen(content))); cl_git_pass(git_patch_from_diff((git_patch **) &patch, diff, 0)); cl_assert_equal_p(patch->diff_opts.old_prefix, NULL); @@ -437,7 +437,7 @@ void test_diff_parse__new_file_with_space_and_regenerate_patch(void) git_diff *diff = NULL; git_buf buf = GIT_BUF_INIT; - cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content))); + cl_git_pass(diff_from_buffer(&diff, content, strlen(content))); cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH)); git_buf_dispose(&buf); @@ -450,7 +450,7 @@ void test_diff_parse__delete_file_with_space_and_regenerate_patch(void) git_diff *diff = NULL; git_buf buf = GIT_BUF_INIT; - cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content))); + cl_git_pass(diff_from_buffer(&diff, content, strlen(content))); cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH)); git_buf_dispose(&buf); @@ -464,7 +464,7 @@ void test_diff_parse__crlf(void) git_patch *patch; const git_diff_delta *delta; - cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text))); + cl_git_pass(diff_from_buffer(&diff, text, strlen(text))); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); delta = git_patch_get_delta(patch); diff --git a/tests/libgit2/diff/patchid.c b/tests/libgit2/diff/patchid.c index 1cc368e2193..91807e7b747 100644 --- a/tests/libgit2/diff/patchid.c +++ b/tests/libgit2/diff/patchid.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "patch/patch_common.h" +#include "diff_helpers.h" static void verify_patch_id(const char *diff_content, const char *expected_id) { @@ -7,7 +8,7 @@ static void verify_patch_id(const char *diff_content, const char *expected_id) git_diff *diff; cl_git_pass(git_oid__fromstr(&expected_oid, expected_id, GIT_OID_SHA1)); - cl_git_pass(git_diff_from_buffer(&diff, diff_content, strlen(diff_content))); + cl_git_pass(diff_from_buffer(&diff, diff_content, strlen(diff_content))); cl_git_pass(git_diff_patchid(&actual_oid, diff, NULL)); cl_assert_equal_oid(&expected_oid, &actual_oid); diff --git a/tests/libgit2/diff/stats.c b/tests/libgit2/diff/stats.c index b076ad5a93d..7af89155084 100644 --- a/tests/libgit2/diff/stats.c +++ b/tests/libgit2/diff/stats.c @@ -4,6 +4,7 @@ #include "commit.h" #include "diff.h" #include "diff_generate.h" +#include "diff_helpers.h" static git_repository *_repo; static git_diff_stats *_stats; @@ -368,7 +369,7 @@ void test_diff_stats__new_file(void) " 1 file changed, 1 insertion(+)\n" " create mode 100644 Gurjeet Singh\n"; - cl_git_pass(git_diff_from_buffer(&diff, input, strlen(input))); + cl_git_pass(diff_from_buffer(&diff, input, strlen(input))); cl_git_pass(git_diff_get_stats(&_stats, diff)); cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY, 0)); cl_assert_equal_s(stat, buf.ptr); From 47868ee45bc1f8680288caebec5a0443bceda12d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 8 Apr 2023 20:32:10 +0100 Subject: [PATCH 141/816] repo: use `GIT_OID_DEFAULT` for default oid type --- src/libgit2/repository.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 4bf92dcdca3..804e436abeb 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -934,7 +934,7 @@ static int obtain_config_and_set_oid_type( if ((error = load_objectformat(repo, config)) < 0) goto out; } else { - repo->oid_type = GIT_OID_SHA1; + repo->oid_type = GIT_OID_DEFAULT; } out: @@ -1804,7 +1804,7 @@ static int load_objectformat(git_repository *repo, git_config *config) if ((error = git_config_get_entry(&entry, config, "extensions.objectformat")) < 0) { if (error == GIT_ENOTFOUND) { - repo->oid_type = GIT_OID_SHA1; + repo->oid_type = GIT_OID_DEFAULT; git_error_clear(); error = 0; } @@ -2240,7 +2240,7 @@ static int repo_init_config( SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); } - if (oid_type != GIT_OID_SHA1) { + if (oid_type != GIT_OID_DEFAULT) { SET_REPO_CONFIG(int32, "core.repositoryformatversion", 1); SET_REPO_CONFIG(string, "extensions.objectformat", git_oid_type_name(oid_type)); } From f4774446ef1c314dfa7802d8d2b27d6bedb44c67 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 8 Apr 2023 21:19:33 +0100 Subject: [PATCH 142/816] merge: support sha256 --- src/libgit2/annotated_commit.c | 4 ++-- src/libgit2/annotated_commit.h | 2 +- src/libgit2/merge.c | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libgit2/annotated_commit.c b/src/libgit2/annotated_commit.c index 7bd8b6077f9..c5c8ace789d 100644 --- a/src/libgit2/annotated_commit.c +++ b/src/libgit2/annotated_commit.c @@ -39,8 +39,8 @@ static int annotated_commit_init( if ((error = git_commit_dup(&annotated_commit->commit, commit)) < 0) goto done; - git_oid_fmt(annotated_commit->id_str, git_commit_id(commit)); - annotated_commit->id_str[GIT_OID_SHA1_HEXSIZE] = '\0'; + git_oid_tostr(annotated_commit->id_str, GIT_OID_MAX_HEXSIZE + 1, + git_commit_id(commit)); if (!description) description = annotated_commit->id_str; diff --git a/src/libgit2/annotated_commit.h b/src/libgit2/annotated_commit.h index c87eaa8057b..1f805fe9bda 100644 --- a/src/libgit2/annotated_commit.h +++ b/src/libgit2/annotated_commit.h @@ -41,7 +41,7 @@ struct git_annotated_commit { const char *ref_name; const char *remote_url; - char id_str[GIT_OID_SHA1_HEXSIZE+1]; + char id_str[GIT_OID_MAX_HEXSIZE + 1]; }; extern int git_annotated_commit_from_head(git_annotated_commit **out, diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 9a52b9f786b..0114e4b75a0 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -611,13 +611,13 @@ int git_repository_mergehead_foreach( buffer = merge_head_file.ptr; while ((line = git__strsep(&buffer, "\n")) != NULL) { - if (strlen(line) != GIT_OID_SHA1_HEXSIZE) { + if (strlen(line) != git_oid_hexsize(repo->oid_type)) { git_error_set(GIT_ERROR_INVALID, "unable to parse OID - invalid length"); error = -1; goto cleanup; } - if ((error = git_oid__fromstr(&oid, line, GIT_OID_SHA1)) < 0) + if ((error = git_oid__fromstr(&oid, line, repo->oid_type)) < 0) goto cleanup; if ((error = cb(&oid, payload)) != 0) { @@ -1061,7 +1061,7 @@ static int index_entry_similarity_calc( const git_merge_options *opts) { git_blob *blob; - git_diff_file diff_file = { GIT_OID_SHA1_ZERO }; + git_diff_file diff_file; git_object_size_t blobsize; int error; @@ -1070,6 +1070,8 @@ static int index_entry_similarity_calc( *out = NULL; + git_oid_clear(&diff_file.id, repo->oid_type); + if ((error = git_blob_lookup(&blob, repo, &entry->id)) < 0) return error; From e01df92875a5005ac9337bbcc0a7681cc25e6738 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 8 Apr 2023 21:24:00 +0100 Subject: [PATCH 143/816] cherrypick: support sha256 --- src/libgit2/cherrypick.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/cherrypick.c b/src/libgit2/cherrypick.c index 04812b1c6f5..3ef42d5e78e 100644 --- a/src/libgit2/cherrypick.c +++ b/src/libgit2/cherrypick.c @@ -106,10 +106,10 @@ static int cherrypick_state_cleanup(git_repository *repo) static int cherrypick_seterr(git_commit *commit, const char *fmt) { - char commit_oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + char commit_oidstr[GIT_OID_MAX_HEXSIZE + 1]; git_error_set(GIT_ERROR_CHERRYPICK, fmt, - git_oid_tostr(commit_oidstr, GIT_OID_SHA1_HEXSIZE + 1, git_commit_id(commit))); + git_oid_tostr(commit_oidstr, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit))); return -1; } @@ -173,7 +173,7 @@ int git_cherrypick( git_cherrypick_options opts; git_reference *our_ref = NULL; git_commit *our_commit = NULL; - char commit_oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + char commit_oidstr[GIT_OID_MAX_HEXSIZE + 1]; const char *commit_msg, *commit_summary; git_str their_label = GIT_STR_INIT; git_index *index = NULL; From 8961f5b92efd7703783e0a0e1f7edd1d65c778fd Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 8 Apr 2023 21:27:48 +0100 Subject: [PATCH 144/816] describe: support sha256 --- src/libgit2/describe.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/libgit2/describe.c b/src/libgit2/describe.c index 3f73d87d63f..04453472330 100644 --- a/src/libgit2/describe.c +++ b/src/libgit2/describe.c @@ -363,12 +363,15 @@ static int find_unique_abbrev_size( size_t size = abbreviated_size; git_odb *odb; git_oid dummy; + size_t hexsize; int error; if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; - while (size < GIT_OID_SHA1_HEXSIZE) { + hexsize = git_oid_hexsize(repo->oid_type); + + while (size < hexsize) { if ((error = git_odb_exists_prefix(&dummy, odb, oid_in, size)) == 0) { *out = (int) size; return 0; @@ -383,7 +386,7 @@ static int find_unique_abbrev_size( } /* If we didn't find any shorter prefix, we have to do the whole thing */ - *out = GIT_OID_SHA1_HEXSIZE; + *out = (int)hexsize; return 0; } @@ -397,7 +400,7 @@ static int show_suffix( { int error, size = 0; - char hex_oid[GIT_OID_SHA1_HEXSIZE]; + char hex_oid[GIT_OID_MAX_HEXSIZE]; if ((error = find_unique_abbrev_size(&size, repo, id, abbrev_size)) < 0) return error; @@ -414,7 +417,7 @@ static int show_suffix( #define MAX_CANDIDATES_TAGS FLAG_BITS - 1 static int describe_not_found(const git_oid *oid, const char *message_format) { - char oid_str[GIT_OID_SHA1_HEXSIZE + 1]; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(oid_str, sizeof(oid_str), oid); git_error_set(GIT_ERROR_DESCRIBE, message_format, oid_str); @@ -525,7 +528,7 @@ static int describe( if (annotated_cnt && (git_pqueue_size(&list) == 0)) { /* if (debug) { - char oid_str[GIT_OID_SHA1_HEXSIZE + 1]; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(oid_str, sizeof(oid_str), &c->oid); fprintf(stderr, "finished search at %s\n", oid_str); @@ -592,7 +595,7 @@ static int describe( "head", "lightweight", "annotated", }; - char oid_str[GIT_OID_SHA1_HEXSIZE + 1]; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; if (debug) { for (cur_match = 0; cur_match < match_cnt; cur_match++) { @@ -816,7 +819,7 @@ static int git_describe__format( /* If we didn't find *any* tags, we fall back to the commit's id */ if (result->fallback_to_id) { - char hex_oid[GIT_OID_SHA1_HEXSIZE + 1] = {0}; + char hex_oid[GIT_OID_MAX_HEXSIZE + 1] = {0}; int size = 0; if ((error = find_unique_abbrev_size( From 4875d998de40d929ab6af8e26a76c9570d84121c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 8 Apr 2023 21:30:31 +0100 Subject: [PATCH 145/816] commit_list: support sha256 --- src/libgit2/commit_list.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libgit2/commit_list.c b/src/libgit2/commit_list.c index 12b329b251e..485871db36f 100644 --- a/src/libgit2/commit_list.c +++ b/src/libgit2/commit_list.c @@ -125,7 +125,7 @@ static int commit_quick_parse( git_oid *parent_oid; git_commit *commit; git_commit__parse_options parse_opts = { - GIT_OID_SHA1, + walk->repo->oid_type, GIT_COMMIT_PARSE_QUICK }; size_t i; @@ -176,7 +176,9 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) if (cgraph_file) { git_commit_graph_entry e; - error = git_commit_graph_entry_find(&e, cgraph_file, &commit->oid, GIT_OID_SHA1_SIZE); + error = git_commit_graph_entry_find(&e, cgraph_file, + &commit->oid, git_oid_size(walk->repo->oid_type)); + if (error == 0 && git__is_uint16(e.parent_count)) { size_t i; commit->generation = (uint32_t)e.generation; From a47bc4eacbe9c1d4e8e546fba7abcd22fca537b1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 8 Apr 2023 21:32:45 +0100 Subject: [PATCH 146/816] email: support sha256 --- src/libgit2/email.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libgit2/email.c b/src/libgit2/email.c index 0a75021c8db..8a10a12b75f 100644 --- a/src/libgit2/email.c +++ b/src/libgit2/email.c @@ -130,11 +130,12 @@ static int append_header( const git_signature *author, git_email_create_options *opts) { - char id[GIT_OID_SHA1_HEXSIZE]; + char id[GIT_OID_MAX_HEXSIZE + 1]; int error; - if ((error = git_oid_fmt(id, commit_id)) < 0 || - (error = git_str_printf(out, "From %.*s %s\n", GIT_OID_SHA1_HEXSIZE, id, EMAIL_TIMESTAMP)) < 0 || + git_oid_tostr(id, GIT_OID_MAX_HEXSIZE + 1, commit_id); + + if ((error = git_str_printf(out, "From %s %s\n", id, EMAIL_TIMESTAMP)) < 0 || (error = git_str_printf(out, "From: %s <%s>\n", author->name, author->email)) < 0 || (error = append_date(out, &author->when)) < 0 || (error = append_subject(out, patch_idx, patch_count, summary, opts)) < 0) From cf06de46edcabd43a642a51e31480ed1ff29bd4b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 9 Apr 2023 22:10:49 +0100 Subject: [PATCH 147/816] iterator: support sha256 --- src/libgit2/iterator.c | 25 ++++++++++++++++++++----- src/libgit2/iterator.h | 3 +++ src/libgit2/refdb_fs.c | 5 ++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/libgit2/iterator.c b/src/libgit2/iterator.c index 1ee8e25f505..95ded1046dc 100644 --- a/src/libgit2/iterator.c +++ b/src/libgit2/iterator.c @@ -1036,6 +1036,8 @@ typedef struct { git_index *index; git_vector index_snapshot; + git_oid_t oid_type; + git_array_t(filesystem_iterator_frame) frames; git_ignores ignores; @@ -1271,7 +1273,7 @@ static int filesystem_iterator_entry_hash( int error; if (S_ISDIR(entry->st.st_mode)) { - memset(&entry->id, 0, GIT_OID_SHA1_SIZE); + memset(&entry->id, 0, git_oid_size(iter->oid_type)); return 0; } @@ -1281,7 +1283,7 @@ static int filesystem_iterator_entry_hash( if (!(error = git_str_joinpath(&fullpath, iter->root, entry->path)) && !(error = git_path_validate_str_length(iter->base.repo, &fullpath))) - error = git_odb__hashfile(&entry->id, fullpath.ptr, GIT_OBJECT_BLOB, GIT_OID_SHA1); + error = git_odb__hashfile(&entry->id, fullpath.ptr, GIT_OBJECT_BLOB, iter->oid_type); git_str_dispose(&fullpath); return error; @@ -1530,7 +1532,7 @@ static void filesystem_iterator_set_current( if (iter->base.flags & GIT_ITERATOR_INCLUDE_HASH) git_oid_cpy(&iter->entry.id, &entry->id); else - git_oid_clear(&iter->entry.id, GIT_OID_SHA1); + git_oid_clear(&iter->entry.id, iter->oid_type); iter->entry.path = entry->path; @@ -1975,6 +1977,8 @@ static int iterator_for_filesystem( (iterator__flag(&iter->base, PRECOMPOSE_UNICODE) ? GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE : 0); + iter->oid_type = options->oid_type; + if ((error = filesystem_iterator_init(iter)) < 0) goto on_error; @@ -1989,10 +1993,15 @@ static int iterator_for_filesystem( int git_iterator_for_filesystem( git_iterator **out, const char *root, - git_iterator_options *options) + git_iterator_options *given_opts) { + git_iterator_options options = GIT_ITERATOR_OPTIONS_INIT; + + if (given_opts) + memcpy(&options, given_opts, sizeof(git_iterator_options)); + return iterator_for_filesystem(out, - NULL, root, NULL, NULL, GIT_ITERATOR_FS, options); + NULL, root, NULL, NULL, GIT_ITERATOR_FS, &options); } int git_iterator_for_workdir_ext( @@ -2019,6 +2028,12 @@ int git_iterator_for_workdir_ext( options.flags |= GIT_ITERATOR_HONOR_IGNORES | GIT_ITERATOR_IGNORE_DOT_GIT; + if (!options.oid_type) + options.oid_type = repo->oid_type; + else if (options.oid_type != repo->oid_type) + git_error_set(GIT_ERROR_INVALID, + "specified object ID type does not match repository object ID type"); + return iterator_for_filesystem(out, repo, repo_workdir, index, tree, GIT_ITERATOR_WORKDIR, &options); } diff --git a/src/libgit2/iterator.h b/src/libgit2/iterator.h index 6bb8489d035..7963ce7e22c 100644 --- a/src/libgit2/iterator.h +++ b/src/libgit2/iterator.h @@ -63,6 +63,9 @@ typedef struct { /* flags, from above */ unsigned int flags; + + /* oid type - necessary for non-workdir filesystem iterators */ + git_oid_t oid_type; } git_iterator_options; #define GIT_ITERATOR_OPTIONS_INIT {0} diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 6000dafb3fc..c5b292ae329 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -805,7 +805,9 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter) git__free(iter); } -static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) +static int iter_load_loose_paths( + refdb_fs_backend *backend, + refdb_fs_iter *iter) { int error = 0; git_str path = GIT_STR_INIT; @@ -819,6 +821,7 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) return 0; fsit_opts.flags = backend->iterator_flags; + fsit_opts.oid_type = backend->oid_type; if (iter->glob) { const char *last_sep = NULL; From 26b9c0564b6ba27b4587e667cc30a938e8878152 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 9 Apr 2023 22:13:45 +0100 Subject: [PATCH 148/816] ident: support sha256 --- src/libgit2/ident.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/ident.c b/src/libgit2/ident.c index bf9a4998e55..97110c66410 100644 --- a/src/libgit2/ident.c +++ b/src/libgit2/ident.c @@ -42,7 +42,7 @@ static int ident_find_id( static int ident_insert_id( git_str *to, const git_str *from, const git_filter_source *src) { - char oid[GIT_OID_SHA1_HEXSIZE+1]; + char oid[GIT_OID_MAX_HEXSIZE + 1]; const char *id_start, *id_end, *from_end = from->ptr + from->size; size_t need_size; @@ -57,7 +57,7 @@ static int ident_insert_id( return GIT_PASSTHROUGH; need_size = (size_t)(id_start - from->ptr) + - 5 /* "$Id: " */ + GIT_OID_SHA1_HEXSIZE + 2 /* " $" */ + + 5 /* "$Id: " */ + GIT_OID_MAX_HEXSIZE + 2 /* " $" */ + (size_t)(from_end - id_end); if (git_str_grow(to, need_size) < 0) @@ -65,7 +65,7 @@ static int ident_insert_id( git_str_set(to, from->ptr, (size_t)(id_start - from->ptr)); git_str_put(to, "$Id: ", 5); - git_str_put(to, oid, GIT_OID_SHA1_HEXSIZE); + git_str_puts(to, oid); git_str_put(to, " $", 2); git_str_put(to, id_end, (size_t)(from_end - id_end)); From 87727409b5a497f0419b5135dff441b7a6213f67 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 9 Apr 2023 22:26:03 +0100 Subject: [PATCH 149/816] blame: support sha256 --- src/libgit2/blame.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index b70cd615ec8..d93dd5e76b1 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -60,10 +60,11 @@ static bool hunk_starts_at_or_after_line(git_blame_hunk *hunk, size_t line) } static git_blame_hunk *new_hunk( - size_t start, - size_t lines, - size_t orig_start, - const char *path) + size_t start, + size_t lines, + size_t orig_start, + const char *path, + git_blame *blame) { git_blame_hunk *hunk = git__calloc(1, sizeof(git_blame_hunk)); if (!hunk) return NULL; @@ -72,8 +73,8 @@ static git_blame_hunk *new_hunk( hunk->final_start_line_number = start; hunk->orig_start_line_number = orig_start; hunk->orig_path = path ? git__strdup(path) : NULL; - git_oid_clear(&hunk->orig_commit_id, GIT_OID_SHA1); - git_oid_clear(&hunk->final_commit_id, GIT_OID_SHA1); + git_oid_clear(&hunk->orig_commit_id, blame->repository->oid_type); + git_oid_clear(&hunk->final_commit_id, blame->repository->oid_type); return hunk; } @@ -86,13 +87,14 @@ static void free_hunk(git_blame_hunk *hunk) git__free(hunk); } -static git_blame_hunk *dup_hunk(git_blame_hunk *hunk) +static git_blame_hunk *dup_hunk(git_blame_hunk *hunk, git_blame *blame) { git_blame_hunk *newhunk = new_hunk( hunk->final_start_line_number, hunk->lines_in_hunk, hunk->orig_start_line_number, - hunk->orig_path); + hunk->orig_path, + blame); if (!newhunk) return NULL; @@ -237,7 +239,8 @@ static git_blame_hunk *split_hunk_in_vector( git_vector *vec, git_blame_hunk *hunk, size_t rel_line, - bool return_new) + bool return_new, + git_blame *blame) { size_t new_line_count; git_blame_hunk *nh; @@ -250,8 +253,9 @@ static git_blame_hunk *split_hunk_in_vector( } new_line_count = hunk->lines_in_hunk - rel_line; - nh = new_hunk(hunk->final_start_line_number + rel_line, new_line_count, - hunk->orig_start_line_number + rel_line, hunk->orig_path); + nh = new_hunk(hunk->final_start_line_number + rel_line, + new_line_count, hunk->orig_start_line_number + rel_line, + hunk->orig_path, blame); if (!nh) return NULL; @@ -304,7 +308,8 @@ static int index_blob_lines(git_blame *blame) static git_blame_hunk *hunk_from_entry(git_blame__entry *e, git_blame *blame) { git_blame_hunk *h = new_hunk( - e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path); + e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path, + blame); if (!h) return NULL; @@ -445,14 +450,16 @@ static int buffer_hunk_cb( blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byline(blame, wedge_line); if (!blame->current_hunk) { /* Line added at the end of the file */ - blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path); + blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, + blame->path, blame); GIT_ERROR_CHECK_ALLOC(blame->current_hunk); git_vector_insert(&blame->hunks, blame->current_hunk); } else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ /* If this hunk doesn't start between existing hunks, split a hunk up so it does */ blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk, - wedge_line - blame->current_hunk->orig_start_line_number, true); + wedge_line - blame->current_hunk->orig_start_line_number, true, + blame); GIT_ERROR_CHECK_ALLOC(blame->current_hunk); } @@ -481,7 +488,7 @@ static int buffer_line_cb( } else { /* Create a new buffer-blame hunk with this line */ shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); - blame->current_hunk = new_hunk(blame->current_diff_line, 1, 0, blame->path); + blame->current_hunk = new_hunk(blame->current_diff_line, 1, 0, blame->path, blame); GIT_ERROR_CHECK_ALLOC(blame->current_hunk); git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL); @@ -529,7 +536,7 @@ int git_blame_buffer( /* Duplicate all of the hunk structures in the reference blame */ git_vector_foreach(&reference->hunks, i, hunk) { - git_blame_hunk *h = dup_hunk(hunk); + git_blame_hunk *h = dup_hunk(hunk, blame); GIT_ERROR_CHECK_ALLOC(h); git_vector_insert(&blame->hunks, h); From be484d355b1b41748689fd29381bdcdcbd4c45bb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 10 Apr 2023 09:47:05 +0100 Subject: [PATCH 150/816] midx: support sha256 --- include/git2/sys/midx.h | 6 ++- src/libgit2/midx.c | 92 +++++++++++++++++++++++++++------------ src/libgit2/midx.h | 16 +++++-- src/libgit2/odb_pack.c | 11 ++++- tests/libgit2/pack/midx.c | 7 ++- 5 files changed, 96 insertions(+), 36 deletions(-) diff --git a/include/git2/sys/midx.h b/include/git2/sys/midx.h index e3d7498298c..3a87484d2b5 100644 --- a/include/git2/sys/midx.h +++ b/include/git2/sys/midx.h @@ -29,7 +29,11 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_midx_writer_new( git_midx_writer **out, - const char *pack_dir); + const char *pack_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ); /** * Free the multi-pack-index writer and its resources. diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index b0905523713..f6071f0bbbd 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -115,19 +115,20 @@ static int midx_parse_oid_lookup( struct git_midx_chunk *chunk_oid_lookup) { uint32_t i; - unsigned char *oid, *prev_oid, zero_oid[GIT_OID_SHA1_SIZE] = {0}; + unsigned char *oid, *prev_oid, zero_oid[GIT_OID_MAX_SIZE] = {0}; + size_t oid_size = git_oid_size(idx->oid_type); if (chunk_oid_lookup->offset == 0) return midx_error("missing OID Lookup chunk"); if (chunk_oid_lookup->length == 0) return midx_error("empty OID Lookup chunk"); - if (chunk_oid_lookup->length != idx->num_objects * GIT_OID_SHA1_SIZE) + if (chunk_oid_lookup->length != idx->num_objects * oid_size) return midx_error("OID Lookup chunk has wrong length"); idx->oid_lookup = oid = (unsigned char *)(data + chunk_oid_lookup->offset); prev_oid = zero_oid; - for (i = 0; i < idx->num_objects; ++i, oid += GIT_OID_SHA1_SIZE) { - if (git_oid_raw_cmp(prev_oid, oid, GIT_OID_SHA1_SIZE) >= 0) + for (i = 0; i < idx->num_objects; ++i, oid += oid_size) { + if (git_oid_raw_cmp(prev_oid, oid, oid_size) >= 0) return midx_error("OID Lookup index is non-monotonic"); prev_oid = oid; } @@ -178,7 +179,7 @@ int git_midx_parse( struct git_midx_chunk *last_chunk; uint32_t i; off64_t last_chunk_offset, chunk_offset, trailer_offset; - size_t checksum_size; + size_t checksum_size, oid_size; int error; struct git_midx_chunk chunk_packfile_names = {0}, chunk_oid_fanout = {0}, @@ -188,7 +189,9 @@ int git_midx_parse( GIT_ASSERT_ARG(idx); - if (size < sizeof(struct git_midx_header) + GIT_OID_SHA1_SIZE) + oid_size = git_oid_size(idx->oid_type); + + if (size < sizeof(struct git_midx_header) + oid_size) return midx_error("multi-pack index is too short"); hdr = ((struct git_midx_header *)data); @@ -209,7 +212,7 @@ int git_midx_parse( sizeof(struct git_midx_header) + (1 + hdr->chunks) * 12; - checksum_size = GIT_HASH_SHA1_SIZE; + checksum_size = oid_size; trailer_offset = size - checksum_size; if (trailer_offset < last_chunk_offset) @@ -287,8 +290,9 @@ int git_midx_parse( } int git_midx_open( - git_midx_file **idx_out, - const char *path) + git_midx_file **idx_out, + const char *path, + git_oid_t oid_type) { git_midx_file *idx; git_file fd = -1; @@ -296,6 +300,8 @@ int git_midx_open( struct stat st; int error; + GIT_ASSERT_ARG(idx_out && path && oid_type); + /* TODO: properly open the file without access time using O_NOATIME */ fd = git_futils_open_ro(path); if (fd < 0) @@ -317,6 +323,8 @@ int git_midx_open( idx = git__calloc(1, sizeof(git_midx_file)); GIT_ERROR_CHECK_ALLOC(idx); + idx->oid_type = oid_type; + error = git_str_sets(&idx->filename, path); if (error < 0) return error; @@ -344,7 +352,7 @@ bool git_midx_needs_refresh( git_file fd = -1; struct stat st; ssize_t bytes_read; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_MAX_SIZE]; size_t checksum_size; /* TODO: properly open the file without access time using O_NOATIME */ @@ -364,8 +372,8 @@ bool git_midx_needs_refresh( return true; } - checksum_size = GIT_HASH_SHA1_SIZE; - bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - GIT_OID_SHA1_SIZE); + checksum_size = git_oid_size(idx->oid_type); + bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - checksum_size); p_close(fd); if (bytes_read != (ssize_t)checksum_size) @@ -381,7 +389,7 @@ int git_midx_entry_find( size_t len) { int pos, found = 0; - size_t pack_index; + size_t pack_index, oid_size, oid_hexsize; uint32_t hi, lo; unsigned char *current = NULL; const unsigned char *object_offset; @@ -389,30 +397,33 @@ int git_midx_entry_find( GIT_ASSERT_ARG(idx); + oid_size = git_oid_size(idx->oid_type); + oid_hexsize = git_oid_hexsize(idx->oid_type); + hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1])); - pos = git_pack__lookup_id(idx->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id, GIT_OID_SHA1); + pos = git_pack__lookup_id(idx->oid_lookup, oid_size, lo, hi, short_oid->id, idx->oid_type); if (pos >= 0) { /* An object matching exactly the oid was found */ found = 1; - current = idx->oid_lookup + (pos * GIT_OID_SHA1_SIZE); + current = idx->oid_lookup + (pos * oid_size); } else { /* No object was found */ /* pos refers to the object with the "closest" oid to short_oid */ pos = -1 - pos; if (pos < (int)idx->num_objects) { - current = idx->oid_lookup + (pos * GIT_OID_SHA1_SIZE); + current = idx->oid_lookup + (pos * oid_size); if (!git_oid_raw_ncmp(short_oid->id, current, len)) found = 1; } } - if (found && len != GIT_OID_SHA1_HEXSIZE && pos + 1 < (int)idx->num_objects) { + if (found && len != oid_hexsize && pos + 1 < (int)idx->num_objects) { /* Check for ambiguousity */ - const unsigned char *next = current + GIT_OID_SHA1_SIZE; + const unsigned char *next = current + oid_size; if (!git_oid_raw_ncmp(short_oid->id, next, len)) found = 2; @@ -443,7 +454,7 @@ int git_midx_entry_find( return midx_error("invalid index into the packfile names table"); e->pack_index = pack_index; e->offset = offset; - git_oid__fromraw(&e->sha1, current, GIT_OID_SHA1); + git_oid__fromraw(&e->sha1, current, idx->oid_type); return 0; } @@ -453,13 +464,15 @@ int git_midx_foreach_entry( void *data) { git_oid oid; - size_t i; + size_t oid_size, i; int error; GIT_ASSERT_ARG(idx); + oid_size = git_oid_size(idx->oid_type); + for (i = 0; i < idx->num_objects; ++i) { - if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * GIT_OID_SHA1_SIZE], GIT_OID_SHA1)) < 0) + if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * oid_size], idx->oid_type)) < 0) return error; if ((error = cb(&oid, data)) != 0) @@ -501,9 +514,21 @@ static int packfile__cmp(const void *a_, const void *b_) int git_midx_writer_new( git_midx_writer **out, - const char *pack_dir) + const char *pack_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { - git_midx_writer *w = git__calloc(1, sizeof(git_midx_writer)); + git_midx_writer *w; + +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + + GIT_ASSERT_ARG(out && pack_dir && oid_type); + + w = git__calloc(1, sizeof(git_midx_writer)); GIT_ERROR_CHECK_ALLOC(w); if (git_str_sets(&w->pack_dir, pack_dir) < 0) { @@ -518,6 +543,8 @@ int git_midx_writer_new( return -1; } + w->oid_type = oid_type; + *out = w; return 0; } @@ -662,12 +689,13 @@ static int midx_write( oid_lookup = GIT_STR_INIT, object_offsets = GIT_STR_INIT, object_large_offsets = GIT_STR_INIT; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size, oid_size; git_midx_entry *entry; object_entry_array_t object_entries_array = GIT_ARRAY_INIT; git_vector object_entries = GIT_VECTOR_INIT; git_hash_ctx ctx; + git_hash_algorithm_t checksum_type; struct midx_write_hash_context hash_cb_data = {0}; hdr.signature = htonl(MIDX_SIGNATURE); @@ -679,10 +707,14 @@ static int midx_write( hash_cb_data.cb_data = cb_data; hash_cb_data.ctx = &ctx; - checksum_size = GIT_HASH_SHA1_SIZE; - error = git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1); - if (error < 0) + oid_size = git_oid_size(w->oid_type); + + GIT_ASSERT((checksum_type = git_oid_algorithm(w->oid_type))); + checksum_size = git_hash_size(checksum_type); + + if ((error = git_hash_ctx_init(&ctx, checksum_type)) < 0) return error; + cb_data = &hash_cb_data; write_cb = midx_write_hash; @@ -749,7 +781,9 @@ static int midx_write( /* Fill the OID Lookup table. */ git_vector_foreach (&object_entries, i, entry) { - error = git_str_put(&oid_lookup, (char *)&entry->sha1.id, GIT_OID_SHA1_SIZE); + error = git_str_put(&oid_lookup, + (char *)&entry->sha1.id, oid_size); + if (error < 0) goto cleanup; } diff --git a/src/libgit2/midx.h b/src/libgit2/midx.h index bcb0d9a0abd..5107f69cba3 100644 --- a/src/libgit2/midx.h +++ b/src/libgit2/midx.h @@ -51,8 +51,14 @@ typedef struct git_midx_file { /* The number of entries in the Object Large Offsets table. Each entry has an 8-byte with an offset */ size_t num_object_large_offsets; - /* The trailer of the file. Contains the SHA1-checksum of the whole file. */ - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + /* + * The trailer of the file. Contains the checksum of the whole + * file, in the repository's object format hash. + */ + unsigned char checksum[GIT_HASH_MAX_SIZE]; + + /* The type of object IDs in the midx. */ + git_oid_t oid_type; /* something like ".git/objects/pack/multi-pack-index". */ git_str filename; @@ -82,11 +88,15 @@ struct git_midx_writer { /* The list of `git_pack_file`s. */ git_vector packs; + + /* The object ID type of the writer. */ + git_oid_t oid_type; }; int git_midx_open( git_midx_file **idx_out, - const char *path); + const char *path, + git_oid_t oid_type); bool git_midx_needs_refresh( const git_midx_file *idx, const char *path); diff --git a/src/libgit2/odb_pack.c b/src/libgit2/odb_pack.c index c6151f4e729..fc533ae83e2 100644 --- a/src/libgit2/odb_pack.c +++ b/src/libgit2/odb_pack.c @@ -479,7 +479,9 @@ static int refresh_multi_pack_index(struct pack_backend *backend) } } - error = git_midx_open(&backend->midx, git_str_cstr(&midx_path)); + error = git_midx_open(&backend->midx, git_str_cstr(&midx_path), + backend->opts.oid_type); + git_str_dispose(&midx_path); if (error < 0) return error; @@ -798,7 +800,12 @@ static int pack_backend__writemidx(git_odb_backend *_backend) backend = (struct pack_backend *)_backend; - error = git_midx_writer_new(&w, backend->pack_folder); + error = git_midx_writer_new(&w, backend->pack_folder +#ifdef GIT_EXPERIMENTAL_SHA256 + , backend->opts.oid_type +#endif + ); + if (error < 0) return error; diff --git a/tests/libgit2/pack/midx.c b/tests/libgit2/pack/midx.c index f7d680165bc..4c4dfc51178 100644 --- a/tests/libgit2/pack/midx.c +++ b/tests/libgit2/pack/midx.c @@ -16,7 +16,7 @@ void test_pack_midx__parse(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_str_joinpath(&midx_path, git_repository_path(repo), "objects/pack/multi-pack-index")); - cl_git_pass(git_midx_open(&idx, git_str_cstr(&midx_path))); + cl_git_pass(git_midx_open(&idx, git_str_cstr(&midx_path), GIT_OID_SHA1)); cl_assert_equal_i(git_midx_needs_refresh(idx, git_str_cstr(&midx_path)), 0); cl_git_pass(git_oid__fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); @@ -57,7 +57,12 @@ void test_pack_midx__writer(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_str_joinpath(&path, git_repository_path(repo), "objects/pack")); + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path), GIT_OID_SHA1)); +#else cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path))); +#endif cl_git_pass(git_midx_writer_add(w, "pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx")); cl_git_pass(git_midx_writer_add(w, "pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx")); From b899fda3d88dc92f50e73544fb7524a1c3c70354 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 10 Apr 2023 10:34:20 +0100 Subject: [PATCH 151/816] commit graph: support sha256 --- include/git2/sys/commit_graph.h | 14 ++- src/libgit2/commit_graph.c | 153 +++++++++++++++++++++--------- src/libgit2/commit_graph.h | 24 ++++- src/libgit2/odb.c | 3 +- tests/libgit2/graph/commitgraph.c | 17 +++- 5 files changed, 159 insertions(+), 52 deletions(-) diff --git a/include/git2/sys/commit_graph.h b/include/git2/sys/commit_graph.h index 823c7ed579b..06e045fcd2b 100644 --- a/include/git2/sys/commit_graph.h +++ b/include/git2/sys/commit_graph.h @@ -28,7 +28,13 @@ GIT_BEGIN_DECL * @param objects_dir the path to a git objects directory. * @return Zero on success; -1 on failure. */ -GIT_EXTERN(int) git_commit_graph_open(git_commit_graph **cgraph_out, const char *objects_dir); +GIT_EXTERN(int) git_commit_graph_open( + git_commit_graph **cgraph_out, + const char *objects_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ); /** * Frees commit-graph data. This should only be called when memory allocated @@ -50,7 +56,11 @@ GIT_EXTERN(void) git_commit_graph_free(git_commit_graph *cgraph); */ GIT_EXTERN(int) git_commit_graph_writer_new( git_commit_graph_writer **out, - const char *objects_info_dir); + const char *objects_info_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ); /** * Free the commit-graph writer and its resources. diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index bf557f7ad66..4edd7110640 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -138,19 +138,22 @@ static int commit_graph_parse_oid_lookup( struct git_commit_graph_chunk *chunk_oid_lookup) { uint32_t i; - unsigned char *oid, *prev_oid, zero_oid[GIT_OID_SHA1_SIZE] = {0}; + unsigned char *oid, *prev_oid, zero_oid[GIT_OID_MAX_SIZE] = {0}; + size_t oid_size; + + oid_size = git_oid_size(file->oid_type); if (chunk_oid_lookup->offset == 0) return commit_graph_error("missing OID Lookup chunk"); if (chunk_oid_lookup->length == 0) return commit_graph_error("empty OID Lookup chunk"); - if (chunk_oid_lookup->length != file->num_commits * GIT_OID_SHA1_SIZE) + if (chunk_oid_lookup->length != file->num_commits * oid_size) return commit_graph_error("OID Lookup chunk has wrong length"); file->oid_lookup = oid = (unsigned char *)(data + chunk_oid_lookup->offset); prev_oid = zero_oid; - for (i = 0; i < file->num_commits; ++i, oid += GIT_OID_SHA1_SIZE) { - if (git_oid_raw_cmp(prev_oid, oid, GIT_OID_SHA1_SIZE) >= 0) + for (i = 0; i < file->num_commits; ++i, oid += oid_size) { + if (git_oid_raw_cmp(prev_oid, oid, oid_size) >= 0) return commit_graph_error("OID Lookup index is non-monotonic"); prev_oid = oid; } @@ -163,11 +166,13 @@ static int commit_graph_parse_commit_data( const unsigned char *data, struct git_commit_graph_chunk *chunk_commit_data) { + size_t oid_size = git_oid_size(file->oid_type); + if (chunk_commit_data->offset == 0) return commit_graph_error("missing Commit Data chunk"); if (chunk_commit_data->length == 0) return commit_graph_error("empty Commit Data chunk"); - if (chunk_commit_data->length != file->num_commits * (GIT_OID_SHA1_SIZE + 16)) + if (chunk_commit_data->length != file->num_commits * (oid_size + 16)) return commit_graph_error("Commit Data chunk has wrong length"); file->commit_data = data + chunk_commit_data->offset; @@ -209,7 +214,9 @@ int git_commit_graph_file_parse( GIT_ASSERT_ARG(file); - if (size < sizeof(struct git_commit_graph_header) + GIT_OID_SHA1_SIZE) + checksum_size = git_oid_size(file->oid_type); + + if (size < sizeof(struct git_commit_graph_header) + checksum_size) return commit_graph_error("commit-graph is too short"); hdr = ((struct git_commit_graph_header *)data); @@ -226,8 +233,7 @@ int git_commit_graph_file_parse( * headers, and a special zero chunk. */ last_chunk_offset = sizeof(struct git_commit_graph_header) + (1 + hdr->chunks) * 12; - trailer_offset = size - GIT_OID_SHA1_SIZE; - checksum_size = GIT_HASH_SHA1_SIZE; + trailer_offset = size - checksum_size; if (trailer_offset < last_chunk_offset) return commit_graph_error("wrong commit-graph size"); @@ -295,25 +301,35 @@ int git_commit_graph_file_parse( return 0; } -int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, bool open_file) +int git_commit_graph_new( + git_commit_graph **cgraph_out, + const char *objects_dir, + bool open_file, + git_oid_t oid_type) { git_commit_graph *cgraph = NULL; int error = 0; GIT_ASSERT_ARG(cgraph_out); GIT_ASSERT_ARG(objects_dir); + GIT_ASSERT_ARG(oid_type); cgraph = git__calloc(1, sizeof(git_commit_graph)); GIT_ERROR_CHECK_ALLOC(cgraph); + cgraph->oid_type = oid_type; + error = git_str_joinpath(&cgraph->filename, objects_dir, "info/commit-graph"); if (error < 0) goto error; if (open_file) { - error = git_commit_graph_file_open(&cgraph->file, git_str_cstr(&cgraph->filename)); + error = git_commit_graph_file_open(&cgraph->file, + git_str_cstr(&cgraph->filename), oid_type); + if (error < 0) goto error; + cgraph->checked = 1; } @@ -326,14 +342,18 @@ int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, } int git_commit_graph_validate(git_commit_graph *cgraph) { - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size = GIT_HASH_SHA1_SIZE; - size_t trailer_offset = cgraph->file->graph_map.len - checksum_size; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + git_hash_algorithm_t checksum_type; + size_t checksum_size, trailer_offset; + + checksum_type = git_oid_algorithm(cgraph->oid_type); + checksum_size = git_hash_size(checksum_type); + trailer_offset = cgraph->file->graph_map.len - checksum_size; if (cgraph->file->graph_map.len < checksum_size) return commit_graph_error("map length too small"); - if (git_hash_buf(checksum, cgraph->file->graph_map.data, trailer_offset, GIT_HASH_ALGORITHM_SHA1) < 0) + if (git_hash_buf(checksum, cgraph->file->graph_map.data, trailer_offset, checksum_type) < 0) return commit_graph_error("could not calculate signature"); if (memcmp(checksum, cgraph->file->checksum, checksum_size) != 0) return commit_graph_error("index signature mismatch"); @@ -341,16 +361,32 @@ int git_commit_graph_validate(git_commit_graph *cgraph) { return 0; } -int git_commit_graph_open(git_commit_graph **cgraph_out, const char *objects_dir) +int git_commit_graph_open( + git_commit_graph **cgraph_out, + const char *objects_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { - int error = git_commit_graph_new(cgraph_out, objects_dir, true); - if (!error) { +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + int error; + + error = git_commit_graph_new(cgraph_out, objects_dir, true, + oid_type); + + if (!error) return git_commit_graph_validate(*cgraph_out); - } + return error; } -int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *path) +int git_commit_graph_file_open( + git_commit_graph_file **file_out, + const char *path, + git_oid_t oid_type) { git_commit_graph_file *file; git_file fd = -1; @@ -379,6 +415,8 @@ int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *pat file = git__calloc(1, sizeof(git_commit_graph_file)); GIT_ERROR_CHECK_ALLOC(file); + file->oid_type = oid_type; + error = git_futils_mmap_ro(&file->graph_map, fd, 0, cgraph_size); p_close(fd); if (error < 0) { @@ -395,7 +433,9 @@ int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *pat return 0; } -int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph *cgraph) +int git_commit_graph_get_file( + git_commit_graph_file **file_out, + git_commit_graph *cgraph) { if (!cgraph->checked) { int error = 0; @@ -405,7 +445,8 @@ int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph cgraph->checked = 1; /* Best effort */ - error = git_commit_graph_file_open(&result, git_str_cstr(&cgraph->filename)); + error = git_commit_graph_file_open(&result, + git_str_cstr(&cgraph->filename), cgraph->oid_type); if (error < 0) return error; @@ -441,6 +482,7 @@ static int git_commit_graph_entry_get_byindex( size_t pos) { const unsigned char *commit_data; + size_t oid_size = git_oid_size(file->oid_type); GIT_ASSERT_ARG(e); GIT_ASSERT_ARG(file); @@ -450,15 +492,15 @@ static int git_commit_graph_entry_get_byindex( return GIT_ENOTFOUND; } - commit_data = file->commit_data + pos * (GIT_OID_SHA1_SIZE + 4 * sizeof(uint32_t)); - git_oid__fromraw(&e->tree_oid, commit_data, GIT_OID_SHA1); - e->parent_indices[0] = ntohl(*((uint32_t *)(commit_data + GIT_OID_SHA1_SIZE))); + commit_data = file->commit_data + pos * (oid_size + 4 * sizeof(uint32_t)); + git_oid__fromraw(&e->tree_oid, commit_data, file->oid_type); + e->parent_indices[0] = ntohl(*((uint32_t *)(commit_data + oid_size))); e->parent_indices[1] = ntohl( - *((uint32_t *)(commit_data + GIT_OID_SHA1_SIZE + sizeof(uint32_t)))); + *((uint32_t *)(commit_data + oid_size + sizeof(uint32_t)))); e->parent_count = (e->parent_indices[0] != GIT_COMMIT_GRAPH_MISSING_PARENT) + (e->parent_indices[1] != GIT_COMMIT_GRAPH_MISSING_PARENT); - e->generation = ntohl(*((uint32_t *)(commit_data + GIT_OID_SHA1_SIZE + 2 * sizeof(uint32_t)))); - e->commit_time = ntohl(*((uint32_t *)(commit_data + GIT_OID_SHA1_SIZE + 3 * sizeof(uint32_t)))); + e->generation = ntohl(*((uint32_t *)(commit_data + oid_size + 2 * sizeof(uint32_t)))); + e->commit_time = ntohl(*((uint32_t *)(commit_data + oid_size + 3 * sizeof(uint32_t)))); e->commit_time |= (e->generation & UINT64_C(0x3)) << UINT64_C(32); e->generation >>= 2u; @@ -485,7 +527,7 @@ static int git_commit_graph_entry_get_byindex( } } - git_oid__fromraw(&e->sha1, &file->oid_lookup[pos * GIT_OID_SHA1_SIZE], GIT_OID_SHA1); + git_oid__fromraw(&e->sha1, &file->oid_lookup[pos * oid_size], file->oid_type); return 0; } @@ -494,8 +536,8 @@ bool git_commit_graph_file_needs_refresh(const git_commit_graph_file *file, cons git_file fd = -1; struct stat st; ssize_t bytes_read; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size = GIT_HASH_SHA1_SIZE; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size = git_oid_size(file->oid_type); /* TODO: properly open the file without access time using O_NOATIME */ fd = git_futils_open_ro(path); @@ -530,35 +572,40 @@ int git_commit_graph_entry_find( int pos, found = 0; uint32_t hi, lo; const unsigned char *current = NULL; + size_t oid_size, oid_hexsize; GIT_ASSERT_ARG(e); GIT_ASSERT_ARG(file); GIT_ASSERT_ARG(short_oid); + oid_size = git_oid_size(file->oid_type); + oid_hexsize = git_oid_hexsize(file->oid_type); + hi = ntohl(file->oid_fanout[(int)short_oid->id[0]]); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(file->oid_fanout[(int)short_oid->id[0] - 1])); - pos = git_pack__lookup_id(file->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id, GIT_OID_SHA1); + pos = git_pack__lookup_id(file->oid_lookup, oid_size, lo, hi, + short_oid->id, file->oid_type); if (pos >= 0) { /* An object matching exactly the oid was found */ found = 1; - current = file->oid_lookup + (pos * GIT_OID_SHA1_SIZE); + current = file->oid_lookup + (pos * oid_size); } else { /* No object was found */ /* pos refers to the object with the "closest" oid to short_oid */ pos = -1 - pos; if (pos < (int)file->num_commits) { - current = file->oid_lookup + (pos * GIT_OID_SHA1_SIZE); + current = file->oid_lookup + (pos * oid_size); if (!git_oid_raw_ncmp(short_oid->id, current, len)) found = 1; } } - if (found && len != GIT_OID_SHA1_HEXSIZE && pos + 1 < (int)file->num_commits) { + if (found && len != oid_hexsize && pos + 1 < (int)file->num_commits) { /* Check for ambiguousity */ - const unsigned char *next = current + GIT_OID_SHA1_SIZE; + const unsigned char *next = current + oid_size; if (!git_oid_raw_ncmp(short_oid->id, next, len)) found = 2; @@ -637,11 +684,27 @@ static int packed_commit__cmp(const void *a_, const void *b_) return git_oid_cmp(&a->sha1, &b->sha1); } -int git_commit_graph_writer_new(git_commit_graph_writer **out, const char *objects_info_dir) +int git_commit_graph_writer_new( + git_commit_graph_writer **out, + const char *objects_info_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { - git_commit_graph_writer *w = git__calloc(1, sizeof(git_commit_graph_writer)); + git_commit_graph_writer *w; + +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + + GIT_ASSERT_ARG(out && objects_info_dir && oid_type); + + w = git__calloc(1, sizeof(git_commit_graph_writer)); GIT_ERROR_CHECK_ALLOC(w); + w->oid_type = oid_type; + if (git_str_sets(&w->objects_info_dir, objects_info_dir) < 0) { git__free(w); return -1; @@ -993,8 +1056,9 @@ static int commit_graph_write( off64_t offset; git_str oid_lookup = GIT_STR_INIT, commit_data = GIT_STR_INIT, extra_edge_list = GIT_STR_INIT; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + git_hash_algorithm_t checksum_type; + size_t checksum_size, oid_size; git_hash_ctx ctx; struct commit_graph_write_hash_context hash_cb_data = {0}; @@ -1007,8 +1071,11 @@ static int commit_graph_write( hash_cb_data.cb_data = cb_data; hash_cb_data.ctx = &ctx; - checksum_size = GIT_HASH_SHA1_SIZE; - error = git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1); + oid_size = git_oid_size(w->oid_type); + checksum_type = git_oid_algorithm(w->oid_type); + checksum_size = git_hash_size(checksum_type); + + error = git_hash_ctx_init(&ctx, checksum_type); if (error < 0) return error; cb_data = &hash_cb_data; @@ -1035,7 +1102,7 @@ static int commit_graph_write( git_vector_foreach (&w->commits, i, packed_commit) { error = git_str_put(&oid_lookup, (const char *)&packed_commit->sha1.id, - GIT_OID_SHA1_SIZE); + oid_size); if (error < 0) goto cleanup; @@ -1052,7 +1119,7 @@ static int commit_graph_write( error = git_str_put(&commit_data, (const char *)&packed_commit->tree_oid.id, - GIT_OID_SHA1_SIZE); + oid_size); if (error < 0) goto cleanup; diff --git a/src/libgit2/commit_graph.h b/src/libgit2/commit_graph.h index 517abb2390b..ecf4379bdb6 100644 --- a/src/libgit2/commit_graph.h +++ b/src/libgit2/commit_graph.h @@ -30,6 +30,9 @@ typedef struct git_commit_graph_file { git_map graph_map; + /* The type of object IDs in the commit graph file. */ + git_oid_t oid_type; + /* The OID Fanout table. */ const uint32_t *oid_fanout; /* The total number of commits in the graph. */ @@ -84,10 +87,10 @@ typedef struct git_commit_graph_entry { /* The index within the Extra Edge List of any parent after the first two. */ size_t extra_parents_index; - /* The SHA-1 hash of the root tree of the commit. */ + /* The object ID of the root tree of the commit. */ git_oid tree_oid; - /* The SHA-1 hash of the requested commit. */ + /* The object ID hash of the requested commit. */ git_oid sha1; } git_commit_graph_entry; @@ -99,18 +102,28 @@ struct git_commit_graph { /* The underlying commit-graph file. */ git_commit_graph_file *file; + /* The object ID types in the commit graph. */ + git_oid_t oid_type; + /* Whether the commit-graph file was already checked for validity. */ bool checked; }; /** Create a new commit-graph, optionally opening the underlying file. */ -int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, bool open_file); +int git_commit_graph_new( + git_commit_graph **cgraph_out, + const char *objects_dir, + bool open_file, + git_oid_t oid_type); /** Validate the checksum of a commit graph */ int git_commit_graph_validate(git_commit_graph *cgraph); /** Open and validate a commit-graph file. */ -int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *path); +int git_commit_graph_file_open( + git_commit_graph_file **file_out, + const char *path, + git_oid_t oid_type); /* * Attempt to get the git_commit_graph's commit-graph file. This object is @@ -134,6 +147,9 @@ struct git_commit_graph_writer { */ git_str objects_info_dir; + /* The object ID type of the commit graph. */ + git_oid_t oid_type; + /* The list of packed commits. */ git_vector commits; }; diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 0fc48035af2..68872e1a197 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -748,7 +748,8 @@ int git_odb__add_default_backends( git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock"); return -1; } - if (!db->cgraph && git_commit_graph_new(&db->cgraph, objects_dir, false) < 0) { + if (!db->cgraph && + git_commit_graph_new(&db->cgraph, objects_dir, false, db->options.oid_type) < 0) { git_mutex_unlock(&db->lock); return -1; } diff --git a/tests/libgit2/graph/commitgraph.c b/tests/libgit2/graph/commitgraph.c index 82f7f936f97..53869d61db0 100644 --- a/tests/libgit2/graph/commitgraph.c +++ b/tests/libgit2/graph/commitgraph.c @@ -16,7 +16,7 @@ void test_graph_commitgraph__parse(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_str_joinpath(&commit_graph_path, git_repository_path(repo), "objects/info/commit-graph")); - cl_git_pass(git_commit_graph_file_open(&file, git_str_cstr(&commit_graph_path))); + cl_git_pass(git_commit_graph_file_open(&file, git_str_cstr(&commit_graph_path), GIT_OID_SHA1)); cl_assert_equal_i(git_commit_graph_file_needs_refresh(file, git_str_cstr(&commit_graph_path)), 0); cl_git_pass(git_oid__fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); @@ -60,7 +60,7 @@ void test_graph_commitgraph__parse_octopus_merge(void) cl_git_pass(git_repository_open(&repo, cl_fixture("merge-recursive/.gitted"))); cl_git_pass(git_str_joinpath(&commit_graph_path, git_repository_path(repo), "objects/info/commit-graph")); - cl_git_pass(git_commit_graph_file_open(&file, git_str_cstr(&commit_graph_path))); + cl_git_pass(git_commit_graph_file_open(&file, git_str_cstr(&commit_graph_path), GIT_OID_SHA1)); cl_git_pass(git_oid__fromstr(&id, "d71c24b3b113fd1d1909998c5bfe33b86a65ee03", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_find(&e, file, &id, GIT_OID_SHA1_HEXSIZE)); @@ -103,7 +103,12 @@ void test_graph_commitgraph__writer(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_str_joinpath(&path, git_repository_path(repo), "objects/info")); + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_commit_graph_writer_new(&w, git_str_cstr(&path), GIT_OID_SHA1)); +#else cl_git_pass(git_commit_graph_writer_new(&w, git_str_cstr(&path))); +#endif /* This is equivalent to `git commit-graph write --reachable`. */ cl_git_pass(git_revwalk_new(&walk, repo)); @@ -135,7 +140,11 @@ void test_graph_commitgraph__validate(void) cl_git_pass(git_str_joinpath(&objects_dir, git_repository_path(repo), "objects")); /* git_commit_graph_open() calls git_commit_graph_validate() */ +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_commit_graph_open(&cgraph, git_str_cstr(&objects_dir), GIT_OID_SHA1)); +#else cl_git_pass(git_commit_graph_open(&cgraph, git_str_cstr(&objects_dir))); +#endif git_commit_graph_free(cgraph); git_str_dispose(&objects_dir); @@ -158,7 +167,11 @@ void test_graph_commitgraph__validate_corrupt(void) cl_must_pass(p_close(fd)); /* git_commit_graph_open() calls git_commit_graph_validate() */ +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_fail(git_commit_graph_open(&cgraph, cl_git_sandbox_path(1, "testrepo.git", "objects", NULL), GIT_OID_SHA1)); +#else cl_git_fail(git_commit_graph_open(&cgraph, cl_git_sandbox_path(1, "testrepo.git", "objects", NULL))); +#endif git_commit_graph_free(cgraph); git_repository_free(repo); From 54bcafeb1e1db31336ac834ad34f491d0eaf2b83 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 11 Apr 2023 10:13:46 +0100 Subject: [PATCH 152/816] config: return `GIT_ENOTFOUND` for missing programdata When the programdata path is missing, ensure that we pass down the `GIT_ENOTFOUND` error to the caller instead of converting it to a generic `-1`. --- src/libgit2/config.c | 7 +++++-- tests/libgit2/config/find.c | 11 +++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 tests/libgit2/config/find.c diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 6d15a8db6d4..23a8f9ffad1 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -1174,9 +1174,12 @@ int git_config__find_programdata(git_str *path) GIT_FS_PATH_OWNER_CURRENT_USER | GIT_FS_PATH_OWNER_ADMINISTRATOR; bool is_safe; + int error; + + if ((error = git_sysdir_find_programdata_file(path, GIT_CONFIG_FILENAME_PROGRAMDATA)) < 0) + return error; - if (git_sysdir_find_programdata_file(path, GIT_CONFIG_FILENAME_PROGRAMDATA) < 0 || - git_fs_path_owner_is(&is_safe, path->ptr, owner_level) < 0) + if (git_fs_path_owner_is(&is_safe, path->ptr, owner_level) < 0) return -1; if (!is_safe) { diff --git a/tests/libgit2/config/find.c b/tests/libgit2/config/find.c new file mode 100644 index 00000000000..7ca8ec767e1 --- /dev/null +++ b/tests/libgit2/config/find.c @@ -0,0 +1,11 @@ +#include "clar_libgit2.h" + +void test_config_find__one(void) +{ + git_buf buf = GIT_BUF_INIT; + + cl_git_fail_with(GIT_ENOTFOUND, git_config_find_global(&buf)); + cl_git_fail_with(GIT_ENOTFOUND, git_config_find_xdg(&buf)); + cl_git_fail_with(GIT_ENOTFOUND, git_config_find_system(&buf)); + cl_git_fail_with(GIT_ENOTFOUND, git_config_find_programdata(&buf)); +} From 363088309458e285d03a73e14d7f43a3983b54f9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 23 Feb 2023 00:37:56 +0000 Subject: [PATCH 153/816] meta: the main branch is now v1.7.0 --- CMakeLists.txt | 2 +- include/git2/version.h | 10 +++++----- package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa516753805..b505b181c34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.6.3" LANGUAGES C) +project(libgit2 VERSION "1.7.0" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") diff --git a/include/git2/version.h b/include/git2/version.h index 78750740aca..bed47f51e49 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,16 +11,16 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.6.3" +#define LIBGIT2_VERSION "1.7.0-alpha" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 /** The minor version number for this version of libgit2. */ -#define LIBGIT2_VER_MINOR 6 +#define LIBGIT2_VER_MINOR 7 /** The revision ("teeny") version number for this version of libgit2. */ -#define LIBGIT2_VER_REVISION 3 +#define LIBGIT2_VER_REVISION 0 /** The Windows DLL patch number for this version of libgit2. */ #define LIBGIT2_VER_PATCH 0 @@ -31,9 +31,9 @@ * a prerelease name like "beta" or "rc1". For final releases, this will * be `NULL`. */ -#define LIBGIT2_VER_PRERELEASE NULL +#define LIBGIT2_VER_PRERELEASE "alpha" /** The library ABI soversion for this version of libgit2. */ -#define LIBGIT2_SOVERSION "1.6" +#define LIBGIT2_SOVERSION "1.7" #endif diff --git a/package.json b/package.json index 5665b4edd02..398446ea5f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.6.3", + "version": "1.7.0-alpha", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From dd15c615bde54eb02c5cec17257a83dcd8528371 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 22 Apr 2023 23:19:59 +0100 Subject: [PATCH 154/816] shallow: remove feature flag The opt mechanism isn't _really_ meant to be for feature flags, and it's weird to feature flag shallow / unshallow at all. --- include/git2/common.h | 6 +----- src/libgit2/commit.c | 5 +---- src/libgit2/grafts.c | 6 ++---- src/libgit2/grafts.h | 2 -- src/libgit2/libgit2.c | 4 ---- src/libgit2/repository.c | 2 +- tests/libgit2/clone/shallow.c | 2 -- tests/libgit2/grafts/basic.c | 2 -- tests/libgit2/grafts/shallow.c | 12 ------------ 9 files changed, 5 insertions(+), 36 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index b09b078a1f7..f968deb233a 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -224,8 +224,7 @@ typedef enum { GIT_OPT_GET_OWNER_VALIDATION, GIT_OPT_SET_OWNER_VALIDATION, GIT_OPT_GET_HOMEDIR, - GIT_OPT_SET_HOMEDIR, - GIT_OPT_ENABLE_SHALLOW + GIT_OPT_SET_HOMEDIR } git_libgit2_opt_t; /** @@ -462,9 +461,6 @@ typedef enum { * > { "!noop", "newext" } indicates that the caller does not want * > to support repositories with the `noop` extension but does want * > to support repositories with the `newext` extension. - * - * opts(GIT_OPT_ENABLE_SHALLOW, int enabled) - * > Enable or disable shallow clone support completely. * * opts(GIT_OPT_GET_OWNER_VALIDATION, int *enabled) * > Gets the owner validation setting for repository diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index a7d83111509..f7be73acf3f 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -553,14 +553,11 @@ int git_commit__parse_ext( git_repository *repo = git_object_owner((git_object *)commit); git_commit_graft *graft; int error; - + if ((error = commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), parse_opts)) < 0) return error; - if (!git_shallow__enabled) - return 0; - /* Perform necessary grafts */ if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != 0 && git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) != 0) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 7cbb1dd7683..13c33aad0e1 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -12,8 +12,6 @@ #include "oidarray.h" #include "parse.h" -bool git_shallow__enabled = false; - struct git_grafts { /* Map of `git_commit_graft`s */ git_oidmap *commits; @@ -97,13 +95,13 @@ int git_grafts_refresh(git_grafts *grafts) if (!grafts->path) return 0; - if ((error = git_futils_readbuffer_updated(&contents, grafts->path, + if ((error = git_futils_readbuffer_updated(&contents, grafts->path, (grafts->path_checksum).id, &updated)) < 0) { if (error == GIT_ENOTFOUND) { git_grafts_clear(grafts); error = 0; } - + goto cleanup; } diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h index 4139438bba7..fc61468f576 100644 --- a/src/libgit2/grafts.h +++ b/src/libgit2/grafts.h @@ -19,8 +19,6 @@ typedef struct { typedef struct git_grafts git_grafts; -extern bool git_shallow__enabled; - int git_grafts_new(git_grafts **out); int git_grafts_from_file(git_grafts **out, const char *path); void git_grafts_free(git_grafts *grafts); diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index c5a9287fb6f..178880c9eb9 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -436,10 +436,6 @@ int git_libgit2_opts(int key, ...) error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *)); break; - case GIT_OPT_ENABLE_SHALLOW: - git_shallow__enabled = (va_arg(ap, int) != 0); - break; - default: git_error_set(GIT_ERROR_INVALID, "invalid option key"); error = -1; diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 1e356c84e05..99982b724f0 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1099,7 +1099,7 @@ int git_repository_open_ext( if (error < 0) goto cleanup; - if (git_shallow__enabled && (error = load_grafts(repo)) < 0) + if ((error = load_grafts(repo)) < 0) goto cleanup; if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) { diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/clone/shallow.c index eacfe1bcfa6..28b0116fadc 100644 --- a/tests/libgit2/clone/shallow.c +++ b/tests/libgit2/clone/shallow.c @@ -4,12 +4,10 @@ void test_clone_shallow__initialize(void) { - cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1)); } void test_clone_shallow__cleanup(void) { - git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); } static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) diff --git a/tests/libgit2/grafts/basic.c b/tests/libgit2/grafts/basic.c index 5ad437b195c..fe747709715 100644 --- a/tests/libgit2/grafts/basic.c +++ b/tests/libgit2/grafts/basic.c @@ -7,13 +7,11 @@ static git_repository *g_repo; void test_grafts_basic__initialize(void) { - git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1); g_repo = cl_git_sandbox_init("grafted.git"); } void test_grafts_basic__cleanup(void) { - git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); cl_git_sandbox_cleanup(); } diff --git a/tests/libgit2/grafts/shallow.c b/tests/libgit2/grafts/shallow.c index 8c272392243..5911a26aabc 100644 --- a/tests/libgit2/grafts/shallow.c +++ b/tests/libgit2/grafts/shallow.c @@ -7,25 +7,13 @@ static git_repository *g_repo; static git_oid g_shallow_oid; -void test_grafts_shallow__set_feature_flag(void) -{ - cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1)); -} - -void test_grafts_shallow__unset_feature_flag(void) -{ - cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0)); -} - void test_grafts_shallow__initialize(void) { - git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 1); cl_git_pass(git_oid__fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); } void test_grafts_shallow__cleanup(void) { - git_libgit2_opts(GIT_OPT_ENABLE_SHALLOW, 0); cl_git_sandbox_cleanup(); } From 6cec01b4d8498203ae3a03949ffd480845269a3d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 22 Apr 2023 23:38:52 +0100 Subject: [PATCH 155/816] shallow: move tests to online --- tests/libgit2/{clone => online}/shallow.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) rename tests/libgit2/{clone => online}/shallow.c (94%) diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/online/shallow.c similarity index 94% rename from tests/libgit2/clone/shallow.c rename to tests/libgit2/online/shallow.c index 28b0116fadc..a889a68cd6f 100644 --- a/tests/libgit2/clone/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -2,14 +2,6 @@ #include "futils.h" #include "repository.h" -void test_clone_shallow__initialize(void) -{ -} - -void test_clone_shallow__cleanup(void) -{ -} - static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) { GIT_UNUSED(payload); @@ -19,7 +11,7 @@ static int remote_single_branch(git_remote **out, git_repository *repo, const ch return 0; } -void test_clone_shallow__clone_depth_zero(void) +void test_online_shallow__clone_depth_zero(void) { git_str path = GIT_STR_INIT; git_repository *repo; @@ -45,7 +37,7 @@ void test_clone_shallow__clone_depth_zero(void) git_repository_free(repo); } -void test_clone_shallow__clone_depth_one(void) +void test_online_shallow__clone_depth_one(void) { git_str path = GIT_STR_INIT; git_repository *repo; @@ -86,7 +78,7 @@ void test_clone_shallow__clone_depth_one(void) git_repository_free(repo); } -void test_clone_shallow__clone_depth_five(void) +void test_online_shallow__clone_depth_five(void) { git_str path = GIT_STR_INIT; git_repository *repo; @@ -129,7 +121,7 @@ void test_clone_shallow__clone_depth_five(void) git_repository_free(repo); } -void test_clone_shallow__unshallow(void) +void test_online_shallow__unshallow(void) { git_str path = GIT_STR_INIT; git_repository *repo; From 48273490e7ccfaa56b784c69cb488111bd06f357 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 22 Apr 2023 23:42:41 +0100 Subject: [PATCH 156/816] shallow: use GIT_ASSERT (not assert) --- src/libgit2/grafts.c | 13 +++++++------ src/libgit2/repository.c | 11 ++++++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 13c33aad0e1..1bfdc500e9f 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -75,7 +75,8 @@ void git_grafts_clear(git_grafts *grafts) { git_commit_graft *graft; - assert(grafts); + if (!grafts) + return; git_oidmap_foreach_value(grafts->commits, graft, { git__free(graft->parents.ptr); @@ -90,7 +91,7 @@ int git_grafts_refresh(git_grafts *grafts) git_str contents = GIT_STR_INIT; int error, updated = 0; - assert(grafts); + GIT_ASSERT_ARG(grafts); if (!grafts->path) return 0; @@ -168,7 +169,7 @@ int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t paren int error; size_t i; - assert(grafts && oid); + GIT_ASSERT_ARG(grafts && oid); graft = git__calloc(1, sizeof(*graft)); GIT_ERROR_CHECK_ALLOC(graft); @@ -200,7 +201,7 @@ int git_grafts_remove(git_grafts *grafts, const git_oid *oid) git_commit_graft *graft; int error; - assert(grafts && oid); + GIT_ASSERT_ARG(grafts && oid); if ((graft = git_oidmap_get(grafts->commits, oid)) == NULL) return GIT_ENOTFOUND; @@ -216,7 +217,7 @@ int git_grafts_remove(git_grafts *grafts, const git_oid *oid) int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid) { - assert(out && grafts && oid); + GIT_ASSERT_ARG(out && grafts && oid); if ((*out = git_oidmap_get(grafts->commits, oid)) == NULL) return GIT_ENOTFOUND; return 0; @@ -228,7 +229,7 @@ int git_grafts_get_oids(git_array_oid_t *out, git_grafts *grafts) size_t i = 0; int error; - assert(out && grafts); + GIT_ASSERT_ARG(out && grafts); while ((error = git_oidmap_iterate(NULL, grafts->commits, &i, &oid)) == 0) { git_oid *cpy = git_array_alloc(*out); diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 99982b724f0..3b6ecae243a 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1613,14 +1613,16 @@ int git_repository_set_index(git_repository *repo, git_index *index) int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo) { - assert(out && repo && repo->grafts); + GIT_ASSERT_ARG(out && repo); + GIT_ASSERT(repo->grafts); *out = repo->grafts; return 0; } int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo) { - assert(out && repo && repo->shallow_grafts); + GIT_ASSERT_ARG(out && repo); + GIT_ASSERT(repo->shallow_grafts); *out = repo->shallow_grafts; return 0; } @@ -3672,7 +3674,7 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro git_oid *oid; int filebuf_hash, error = 0; - assert(repo); + GIT_ASSERT_ARG(repo); filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(GIT_OID_SHA1)); GIT_ASSERT(filebuf_hash); @@ -3695,9 +3697,8 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro goto on_error; } - if (git_array_size(roots) == 0) { + if (git_array_size(roots) == 0) remove(path.ptr); - } on_error: git_str_dispose(&path); From 3853ba8de64a0e774c6e73aacb5831707f841621 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 22 Apr 2023 23:55:44 +0100 Subject: [PATCH 157/816] smart: validate shallow/unshallow pkts --- src/libgit2/transports/smart_pkt.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index ec9764a87a6..e8c87cb8df8 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -444,11 +444,15 @@ static int shallow_pkt(git_pkt **out, const char *line, size_t len) GIT_ERROR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_SHALLOW; - line += 7; - len -= 7; + + if (git__prefixncmp(line, len, "shallow ")) + goto out_err; + + line += 8; + len -= 8; if (len >= GIT_OID_SHA1_HEXSIZE) { - git_oid__fromstr(&pkt->oid, line + 1, GIT_OID_SHA1); + git_oid__fromstr(&pkt->oid, line, GIT_OID_SHA1); line += GIT_OID_SHA1_HEXSIZE + 1; len -= GIT_OID_SHA1_HEXSIZE + 1; } @@ -456,6 +460,11 @@ static int shallow_pkt(git_pkt **out, const char *line, size_t len) *out = (git_pkt *) pkt; return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "invalid packet line"); + git__free(pkt); + return -1; } static int unshallow_pkt(git_pkt **out, const char *line, size_t len) @@ -466,11 +475,15 @@ static int unshallow_pkt(git_pkt **out, const char *line, size_t len) GIT_ERROR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_UNSHALLOW; - line += 9; - len -= 9; + + if (git__prefixncmp(line, len, "unshallow ")) + goto out_err; + + line += 10; + len -= 10; if (len >= GIT_OID_SHA1_HEXSIZE) { - git_oid__fromstr(&pkt->oid, line + 1, GIT_OID_SHA1); + git_oid__fromstr(&pkt->oid, line, GIT_OID_SHA1); line += GIT_OID_SHA1_HEXSIZE + 1; len -= GIT_OID_SHA1_HEXSIZE + 1; } @@ -478,6 +491,11 @@ static int unshallow_pkt(git_pkt **out, const char *line, size_t len) *out = (git_pkt *) pkt; return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "invalid packet line"); + git__free(pkt); + return -1; } static int parse_len(size_t *out, const char *line, size_t linelen) From 72139ef289383dafeea355ace222359c48d98563 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 23 Apr 2023 00:07:06 +0100 Subject: [PATCH 158/816] shallow: don't assume SHA1 --- src/libgit2/repository.c | 6 ++- src/libgit2/transports/smart_pkt.c | 66 +++++++++++++++++++----------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 3b6ecae243a..a60fb23fa0a 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3670,13 +3670,14 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro { git_filebuf file = GIT_FILEBUF_INIT; git_str path = GIT_STR_INIT; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; size_t idx; git_oid *oid; int filebuf_hash, error = 0; GIT_ASSERT_ARG(repo); - filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(GIT_OID_SHA1)); + filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(repo->oid_type)); GIT_ASSERT(filebuf_hash); if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0) @@ -3686,7 +3687,8 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro goto on_error; git_array_foreach(roots, idx, oid) { - git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_SHA1_HEXSIZE); + git_oid_tostr(oid_str, sizeof(oid_str), oid); + git_filebuf_write(&file, oid_str, git_oid_hexsize(repo->oid_type)); git_filebuf_write(&file, "\n", 1); } diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index e8c87cb8df8..3199c18f000 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -44,9 +44,14 @@ static int flush_pkt(git_pkt **out) } /* the rest of the line will be useful for multi_ack and multi_ack_detailed */ -static int ack_pkt(git_pkt **out, const char *line, size_t len) +static int ack_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) { git_pkt_ack *pkt; + size_t oid_hexsize = git_oid_hexsize(data->oid_type); pkt = git__calloc(1, sizeof(git_pkt_ack)); GIT_ERROR_CHECK_ALLOC(pkt); @@ -57,11 +62,11 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len) line += 4; len -= 4; - if (len < GIT_OID_SHA1_HEXSIZE || - git_oid__fromstr(&pkt->oid, line, GIT_OID_SHA1) < 0) + if (len < oid_hexsize || + git_oid__fromstr(&pkt->oid, line, data->oid_type) < 0) goto out_err; - line += GIT_OID_SHA1_HEXSIZE; - len -= GIT_OID_SHA1_HEXSIZE; + line += oid_hexsize; + len -= oid_hexsize; if (len && line[0] == ' ') { line++; @@ -436,9 +441,14 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len) return 0; } -static int shallow_pkt(git_pkt **out, const char *line, size_t len) +static int shallow_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) { git_pkt_shallow *pkt; + size_t oid_hexsize = git_oid_hexsize(data->oid_type); pkt = git__calloc(1, sizeof(git_pkt_shallow)); GIT_ERROR_CHECK_ALLOC(pkt); @@ -451,13 +461,14 @@ static int shallow_pkt(git_pkt **out, const char *line, size_t len) line += 8; len -= 8; - if (len >= GIT_OID_SHA1_HEXSIZE) { - git_oid__fromstr(&pkt->oid, line, GIT_OID_SHA1); - line += GIT_OID_SHA1_HEXSIZE + 1; - len -= GIT_OID_SHA1_HEXSIZE + 1; - } + if (len != oid_hexsize) + goto out_err; - *out = (git_pkt *) pkt; + git_oid__fromstr(&pkt->oid, line, data->oid_type); + line += oid_hexsize + 1; + len -= oid_hexsize + 1; + + *out = (git_pkt *)pkt; return 0; @@ -467,9 +478,14 @@ static int shallow_pkt(git_pkt **out, const char *line, size_t len) return -1; } -static int unshallow_pkt(git_pkt **out, const char *line, size_t len) +static int unshallow_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) { git_pkt_shallow *pkt; + size_t oid_hexsize = git_oid_hexsize(data->oid_type); pkt = git__calloc(1, sizeof(git_pkt_shallow)); GIT_ERROR_CHECK_ALLOC(pkt); @@ -482,11 +498,12 @@ static int unshallow_pkt(git_pkt **out, const char *line, size_t len) line += 10; len -= 10; - if (len >= GIT_OID_SHA1_HEXSIZE) { - git_oid__fromstr(&pkt->oid, line, GIT_OID_SHA1); - line += GIT_OID_SHA1_HEXSIZE + 1; - len -= GIT_OID_SHA1_HEXSIZE + 1; - } + if (len != oid_hexsize) + goto out_err; + + git_oid__fromstr(&pkt->oid, line, data->oid_type); + line += oid_hexsize + 1; + len -= oid_hexsize + 1; *out = (git_pkt *) pkt; @@ -615,7 +632,7 @@ int git_pkt_parse_line( else if (*line == GIT_SIDE_BAND_ERROR) error = sideband_error_pkt(pkt, line, len); else if (!git__prefixncmp(line, len, "ACK")) - error = ack_pkt(pkt, line, len); + error = ack_pkt(pkt, line, len, data); else if (!git__prefixncmp(line, len, "NAK")) error = nak_pkt(pkt); else if (!git__prefixncmp(line, len, "ERR")) @@ -629,9 +646,9 @@ int git_pkt_parse_line( else if (!git__prefixncmp(line, len, "unpack")) error = unpack_pkt(pkt, line, len); else if (!git__prefixcmp(line, "shallow")) - error = shallow_pkt(pkt, line, len); + error = shallow_pkt(pkt, line, len, data); else if (!git__prefixcmp(line, "unshallow")) - error = unshallow_pkt(pkt, line, len); + error = unshallow_pkt(pkt, line, len, data); else error = ref_pkt(pkt, line, len, data); @@ -788,12 +805,13 @@ int git_pkt_buffer_wants( /* Tell the server about our shallow objects */ for (i = 0; i < git_shallowarray_count(wants->shallow_roots); i++) { - char oid[GIT_OID_SHA1_HEXSIZE]; + char oid[GIT_OID_MAX_HEXSIZE + 1]; git_str shallow_buf = GIT_STR_INIT; - git_oid_fmt(oid, git_shallowarray_get(wants->shallow_roots, i)); + git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, + git_shallowarray_get(wants->shallow_roots, i)); git_str_puts(&shallow_buf, "shallow "); - git_str_put(&shallow_buf, oid, GIT_OID_SHA1_HEXSIZE); + git_str_puts(&shallow_buf, oid); git_str_putc(&shallow_buf, '\n'); git_str_printf(buf, "%04x%s", (unsigned int)git_str_len(&shallow_buf) + 4, git_str_cstr(&shallow_buf)); From d69c7a72386c9e01f4b0c8945724f870bf9aa4f6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Apr 2023 11:43:03 +0100 Subject: [PATCH 159/816] transport: transports understand oid type Teach the smart transport more about oid types, instead of assuming SHA1. --- src/libgit2/transports/smart_pkt.c | 6 ++++++ src/libgit2/transports/smart_protocol.c | 26 +++++++++++++++---------- tests/libgit2/transports/smart/packet.c | 4 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 3199c18f000..f2c9eea8e5e 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -53,6 +53,8 @@ static int ack_pkt( git_pkt_ack *pkt; size_t oid_hexsize = git_oid_hexsize(data->oid_type); + GIT_ASSERT(data && data->oid_type); + pkt = git__calloc(1, sizeof(git_pkt_ack)); GIT_ERROR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_ACK; @@ -450,6 +452,8 @@ static int shallow_pkt( git_pkt_shallow *pkt; size_t oid_hexsize = git_oid_hexsize(data->oid_type); + GIT_ASSERT(data && data->oid_type); + pkt = git__calloc(1, sizeof(git_pkt_shallow)); GIT_ERROR_CHECK_ALLOC(pkt); @@ -487,6 +491,8 @@ static int unshallow_pkt( git_pkt_shallow *pkt; size_t oid_hexsize = git_oid_hexsize(data->oid_type); + GIT_ASSERT(data && data->oid_type); + pkt = git__calloc(1, sizeof(git_pkt_shallow)); GIT_ERROR_CHECK_ALLOC(pkt); diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index c37c3cc8dcb..eb2bc5be4f8 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -256,13 +256,20 @@ int git_smart__detect_caps( return 0; } -static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf) +static int recv_pkt( + git_pkt **out_pkt, + git_pkt_type *out_type, + transport_smart *t, + gitno_buffer *buf) { const char *ptr = buf->data, *line_end = ptr; git_pkt *pkt = NULL; git_pkt_parse_data pkt_parse_data = { 0 }; int error = 0, ret; + pkt_parse_data.oid_type = t->owner->repo->oid_type; + pkt_parse_data.seen_capabilities = 1; + do { if (buf->offset > 0) error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset, &pkt_parse_data); @@ -303,7 +310,7 @@ static int store_common(transport_smart *t) int error; do { - if ((error = recv_pkt(&pkt, NULL, buf)) < 0) + if ((error = recv_pkt(&pkt, NULL, t, buf)) < 0) return error; if (pkt->type != GIT_PKT_ACK) { @@ -320,7 +327,7 @@ static int store_common(transport_smart *t) return 0; } -static int wait_while_ack(gitno_buffer *buf) +static int wait_while_ack(transport_smart *t, gitno_buffer *buf) { int error; git_pkt *pkt = NULL; @@ -329,7 +336,7 @@ static int wait_while_ack(gitno_buffer *buf) while (1) { git_pkt_free(pkt); - if ((error = recv_pkt(&pkt, NULL, buf)) < 0) + if ((error = recv_pkt(&pkt, NULL, t, buf)) < 0) return error; if (pkt->type == GIT_PKT_NAK) @@ -400,8 +407,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; - while ((error = recv_pkt((git_pkt **)&pkt, NULL, buf)) == 0) { - + while ((error = recv_pkt((git_pkt **)&pkt, NULL, t, buf)) == 0) { if (pkt->type == GIT_PKT_SHALLOW) { git_shallowarray_add(wants->shallow_roots, &pkt->oid); } else if (pkt->type == GIT_PKT_UNSHALLOW) { @@ -463,7 +469,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c if ((error = store_common(t)) < 0) goto on_error; } else { - if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0) + if ((error = recv_pkt(NULL, &pkt_type, t, buf)) < 0) goto on_error; if (pkt_type == GIT_PKT_ACK) { @@ -535,7 +541,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c /* Now let's eat up whatever the server gives us */ if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) { - if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0) + if ((error = recv_pkt(NULL, &pkt_type, t, buf)) < 0) return error; if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) { @@ -543,7 +549,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c return -1; } } else { - error = wait_while_ack(buf); + error = wait_while_ack(t, buf); } return error; @@ -659,7 +665,7 @@ int git_smart__download_pack( goto done; } - if ((error = recv_pkt(&pkt, NULL, buf)) >= 0) { + if ((error = recv_pkt(&pkt, NULL, t, buf)) >= 0) { /* Check cancellation after network call */ if (t->cancelled.val) { git_error_clear(); diff --git a/tests/libgit2/transports/smart/packet.c b/tests/libgit2/transports/smart/packet.c index 2035e3b65d0..a775a4cfab4 100644 --- a/tests/libgit2/transports/smart/packet.c +++ b/tests/libgit2/transports/smart/packet.c @@ -25,7 +25,7 @@ static void assert_data_pkt_parses(const char *line, const char *expected_data, size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_data *pkt; - git_pkt_parse_data pkt_parse_data = { 0 }; + git_pkt_parse_data pkt_parse_data = { 1, GIT_OID_SHA1 }; cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_DATA); @@ -71,7 +71,7 @@ static void assert_ack_parses(const char *line, const char *expected_oid, enum g const char *endptr; git_pkt_ack *pkt; git_oid oid; - git_pkt_parse_data pkt_parse_data = { 0 }; + git_pkt_parse_data pkt_parse_data = { 1, GIT_OID_SHA1 }; cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); From 47ebf589250159d6a98bd91625aefd2e1383ec26 Mon Sep 17 00:00:00 2001 From: Oliver Reiche Date: Wed, 3 May 2023 12:57:06 +0200 Subject: [PATCH 160/816] Fix missing oid type for "fake" repositories ... otherwise git_tree__parse_raw() will fail to obtain the correct oid size, which causes the entire parse to fail. --- src/libgit2/repository.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 804e436abeb..c45c5855058 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1152,6 +1152,8 @@ int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb) repo = repository_alloc(); GIT_ERROR_CHECK_ALLOC(repo); + repo->oid_type = GIT_OID_DEFAULT; + git_repository_set_odb(repo, odb); *repo_out = repo; From f1ef8ebee3ee21afba3ad1ad1335d34371a61d05 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 5 May 2023 16:13:40 +0100 Subject: [PATCH 161/816] odb: test object lookups from git_repository_wrap_odb --- tests/libgit2/odb/backend/loose.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/libgit2/odb/backend/loose.c b/tests/libgit2/odb/backend/loose.c index 781b61d9ff9..f5a0b4f5caf 100644 --- a/tests/libgit2/odb/backend/loose.c +++ b/tests/libgit2/odb/backend/loose.c @@ -32,7 +32,7 @@ void test_odb_backend_loose__cleanup(void) cl_fixture_cleanup("testrepo.git"); } -void test_odb_backend_loose__read(void) +void test_odb_backend_loose__read_from_odb(void) { git_oid oid; git_odb_object *obj; @@ -40,4 +40,23 @@ void test_odb_backend_loose__read(void) cl_git_pass(git_oid__fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); cl_git_pass(git_odb_read(&obj, _odb, &oid)); git_odb_object_free(obj); + + cl_git_pass(git_oid__fromstr(&oid, "fd093bff70906175335656e6ce6ae05783708765", GIT_OID_SHA1)); + cl_git_pass(git_odb_read(&obj, _odb, &oid)); + git_odb_object_free(obj); +} + +void test_odb_backend_loose__read_from_repo(void) +{ + git_oid oid; + git_blob *blob; + git_tree *tree; + + cl_git_pass(git_oid__fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_blob_lookup(&blob, _repo, &oid)); + git_blob_free(blob); + + cl_git_pass(git_oid__fromstr(&oid, "fd093bff70906175335656e6ce6ae05783708765", GIT_OID_SHA1)); + cl_git_pass(git_tree_lookup(&tree, _repo, &oid)); + git_tree_free(tree); } From 161d8a12e70936222a55b5571098299957cdee04 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 5 May 2023 16:29:58 +0100 Subject: [PATCH 162/816] sha256: wrap_odb supports SHA256 --- include/git2/repository.h | 14 ++++++++++++-- src/libgit2/repository.c | 24 +++++++++++++++++++++--- src/libgit2/repository.h | 5 +++++ tests/libgit2/odb/backend/loose.c | 2 +- tests/libgit2/odb/backend/mempack.c | 2 +- tests/libgit2/refs/iterator.c | 3 ++- 6 files changed, 42 insertions(+), 8 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 560e70ab6df..6ec2ac8220c 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -56,9 +56,19 @@ GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_work * * @param out pointer to the repo * @param odb the object database to wrap + * @param oid_type the oid type of the object database * @return 0 or an error code */ -GIT_EXTERN(int) git_repository_wrap_odb(git_repository **out, git_odb *odb); +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_repository_wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type); +#else +GIT_EXTERN(int) git_repository_wrap_odb( + git_repository **out, + git_odb *odb); +#endif /** * Look for a git repository and copy its path in the given buffer. @@ -536,7 +546,7 @@ GIT_EXTERN(const char *) git_repository_workdir(const git_repository *repo); /** * Get the path of the shared common directory for this repository. - * + * * If the repository is bare, it is the root directory for the repository. * If the repository is a worktree, it is the parent repo's gitdir. * Otherwise, it is the gitdir. diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index c45c5855058..473f3b146a9 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1145,21 +1145,39 @@ int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *w return err; } -int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb) +int git_repository__wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type) { git_repository *repo; repo = repository_alloc(); GIT_ERROR_CHECK_ALLOC(repo); - repo->oid_type = GIT_OID_DEFAULT; + repo->oid_type = oid_type; git_repository_set_odb(repo, odb); - *repo_out = repo; + *out = repo; return 0; } +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_repository_wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type) +{ + return git_repository__wrap_odb(out, odb, oid_type); +} +#else +int git_repository_wrap_odb(git_repository **out, git_odb *odb) +{ + return git_repository__wrap_odb(out, odb, GIT_OID_DEFAULT); +} +#endif + int git_repository_discover( git_buf *out, const char *start_path, diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index 9a36ef97210..b2208b8a695 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -190,6 +190,11 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo); int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo); int git_repository_index__weakptr(git_index **out, git_repository *repo); +int git_repository__wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type); + /* * Configuration map cache * diff --git a/tests/libgit2/odb/backend/loose.c b/tests/libgit2/odb/backend/loose.c index f5a0b4f5caf..02227945d71 100644 --- a/tests/libgit2/odb/backend/loose.c +++ b/tests/libgit2/odb/backend/loose.c @@ -21,7 +21,7 @@ void test_odb_backend_loose__initialize(void) cl_git_pass(git_odb__new(&_odb, NULL)); cl_git_pass(git_odb_add_backend(_odb, backend, 10)); - cl_git_pass(git_repository_wrap_odb(&_repo, _odb)); + cl_git_pass(git_repository__wrap_odb(&_repo, _odb, GIT_OID_SHA1)); } void test_odb_backend_loose__cleanup(void) diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c index eb8ab3cb0b2..c8a86a2ae95 100644 --- a/tests/libgit2/odb/backend/mempack.c +++ b/tests/libgit2/odb/backend/mempack.c @@ -16,7 +16,7 @@ void test_odb_backend_mempack__initialize(void) cl_git_pass(git_mempack_new(&backend)); cl_git_pass(git_odb__new(&_odb, NULL)); cl_git_pass(git_odb_add_backend(_odb, backend, 10)); - cl_git_pass(git_repository_wrap_odb(&_repo, _odb)); + cl_git_pass(git_repository__wrap_odb(&_repo, _odb, GIT_OID_SHA1)); } void test_odb_backend_mempack__cleanup(void) diff --git a/tests/libgit2/refs/iterator.c b/tests/libgit2/refs/iterator.c index f40d35d1171..706fd1ef7e0 100644 --- a/tests/libgit2/refs/iterator.c +++ b/tests/libgit2/refs/iterator.c @@ -2,6 +2,7 @@ #include "refs.h" #include "vector.h" #include "odb.h" +#include "repository.h" static git_repository *repo; @@ -128,7 +129,7 @@ void test_refs_iterator__empty(void) git_repository *empty; cl_git_pass(git_odb__new(&odb, NULL)); - cl_git_pass(git_repository_wrap_odb(&empty, odb)); + cl_git_pass(git_repository__wrap_odb(&empty, odb, GIT_OID_SHA1)); cl_git_pass(git_reference_iterator_new(&iter, empty)); cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&ref, iter)); From 8f7fc2ee505a0abe2186270a79b287e321c748c4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Apr 2023 11:16:47 +0100 Subject: [PATCH 163/816] shallow: avoid unnecessary pkt free Looks like a double-free here. --- src/libgit2/transports/smart_protocol.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index eb2bc5be4f8..6167a807409 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -408,26 +408,28 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c goto on_error; while ((error = recv_pkt((git_pkt **)&pkt, NULL, t, buf)) == 0) { + bool complete = false; + if (pkt->type == GIT_PKT_SHALLOW) { git_shallowarray_add(wants->shallow_roots, &pkt->oid); } else if (pkt->type == GIT_PKT_UNSHALLOW) { git_shallowarray_remove(wants->shallow_roots, &pkt->oid); } else if (pkt->type == GIT_PKT_FLUSH) { /* Server is done, stop processing shallow oids */ - break; + complete = true; } else { - git_error_set(GIT_ERROR_NET, "Unexpected pkt type"); - goto on_error; + git_error_set(GIT_ERROR_NET, "unexpected packet type"); + error = -1; } git_pkt_free((git_pkt *) pkt); - } - git_pkt_free((git_pkt *) pkt); + if (complete || error < 0) + break; + } - if (error < 0) { + if (error < 0) goto on_error; - } } /* * Our support for ACK extensions is simply to parse them. On From 6a02b459ab1d9ca6eaeda96cce94ba5ce6f8eaea Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Apr 2023 12:15:11 +0100 Subject: [PATCH 164/816] futils: use SHA256 for checksums always Use SHA256 for file checksums. SHA1 makes no sense as a default in 2023. Given that we're just looking at a file checksum to see if it's changed, this does not need to take repository's OID type into account or otherwise be configurable. --- src/libgit2/grafts.c | 5 +++-- src/util/futils.c | 13 ++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 1bfdc500e9f..ef314550d7d 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -18,7 +18,7 @@ struct git_grafts { /* File backing the graft. NULL if it's an in-memory graft */ char *path; - git_oid path_checksum; + unsigned char path_checksum[GIT_HASH_SHA256_SIZE]; }; int git_grafts_new(git_grafts **out) @@ -97,7 +97,8 @@ int git_grafts_refresh(git_grafts *grafts) return 0; if ((error = git_futils_readbuffer_updated(&contents, grafts->path, - (grafts->path_checksum).id, &updated)) < 0) { + grafts->path_checksum, &updated)) < 0) { + if (error == GIT_ENOTFOUND) { git_grafts_clear(grafts); error = 0; diff --git a/src/util/futils.c b/src/util/futils.c index 084f1cd2820..7b5a24b305f 100644 --- a/src/util/futils.c +++ b/src/util/futils.c @@ -221,14 +221,14 @@ int git_futils_readbuffer_fd_full(git_str *buf, git_file fd) int git_futils_readbuffer_updated( git_str *out, const char *path, - unsigned char checksum[GIT_HASH_SHA1_SIZE], + unsigned char checksum[GIT_HASH_SHA256_SIZE], int *updated) { int error; git_file fd; struct stat st; git_str buf = GIT_STR_INIT; - unsigned char checksum_new[GIT_HASH_SHA1_SIZE]; + unsigned char checksum_new[GIT_HASH_SHA256_SIZE]; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(path && *path); @@ -261,7 +261,10 @@ int git_futils_readbuffer_updated( p_close(fd); if (checksum) { - if ((error = git_hash_buf(checksum_new, buf.ptr, buf.size, GIT_HASH_ALGORITHM_SHA1)) < 0) { + error = git_hash_buf(checksum_new, buf.ptr, + buf.size, GIT_HASH_ALGORITHM_SHA256); + + if (error < 0) { git_str_dispose(&buf); return error; } @@ -269,7 +272,7 @@ int git_futils_readbuffer_updated( /* * If we were given a checksum, we only want to use it if it's different */ - if (!memcmp(checksum, checksum_new, GIT_HASH_SHA1_SIZE)) { + if (!memcmp(checksum, checksum_new, GIT_HASH_SHA256_SIZE)) { git_str_dispose(&buf); if (updated) *updated = 0; @@ -277,7 +280,7 @@ int git_futils_readbuffer_updated( return 0; } - memcpy(checksum, checksum_new, GIT_HASH_SHA1_SIZE); + memcpy(checksum, checksum_new, GIT_HASH_SHA256_SIZE); } /* From 69592bde1f2789162b215b612df7c8a13956b722 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Apr 2023 13:09:15 +0100 Subject: [PATCH 165/816] grafts: use `git_parse` to parse object IDs Don't mix parsing by hand and using `git_parse` to parse. --- src/libgit2/grafts.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index ef314550d7d..d46fc12c1a5 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -119,7 +119,7 @@ int git_grafts_refresh(git_grafts *grafts) return error; } -int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) +int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len) { git_array_oid_t parents = GIT_ARRAY_INIT; git_parse_ctx parser; @@ -127,29 +127,26 @@ int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) git_grafts_clear(grafts); - if ((error = git_parse_ctx_init(&parser, content, contentlen)) < 0) + if ((error = git_parse_ctx_init(&parser, buf, len)) < 0) goto error; for (; parser.remain_len; git_parse_advance_line(&parser)) { - const char *line_start = parser.line, *line_end = parser.line + parser.line_len; git_oid graft_oid; - if ((error = git_oid__fromstrn(&graft_oid, line_start, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1)) < 0) { + if ((error = git_parse_advance_oid(&graft_oid, &parser, GIT_OID_SHA1)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num); goto error; } - line_start += GIT_OID_SHA1_HEXSIZE; - while (line_start < line_end && *line_start == ' ') { + while (parser.line_len && git_parse_advance_expected(&parser, "\n", 1) != 0) { git_oid *id = git_array_alloc(parents); GIT_ERROR_CHECK_ALLOC(id); - if ((error = git_oid__fromstrn(id, ++line_start, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1)) < 0) { + if ((error = git_parse_advance_expected(&parser, " ", 1)) < 0 || + (error = git_parse_advance_oid(id, &parser, GIT_OID_SHA1)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num); goto error; } - - line_start += GIT_OID_SHA1_HEXSIZE; } if ((error = git_grafts_add(grafts, &graft_oid, parents)) < 0) @@ -186,6 +183,7 @@ int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t paren if ((error = git_grafts_remove(grafts, &graft->oid)) < 0 && error != GIT_ENOTFOUND) goto cleanup; + if ((error = git_oidmap_set(grafts->commits, &graft->oid, graft)) < 0) goto cleanup; From 7d7f3059decbd6b4730bfd09da54726c1b3ed8ea Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Apr 2023 13:32:43 +0100 Subject: [PATCH 166/816] grafts: handle SHA256 graft files --- src/libgit2/grafts.c | 22 +++++++++++++++++----- src/libgit2/grafts.h | 6 +++--- src/libgit2/repository.c | 4 ++-- tests/libgit2/grafts/basic.c | 2 +- tests/libgit2/grafts/parse.c | 2 +- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index d46fc12c1a5..00de03e8b21 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -16,15 +16,20 @@ struct git_grafts { /* Map of `git_commit_graft`s */ git_oidmap *commits; + /* Type of object IDs */ + git_oid_t oid_type; + /* File backing the graft. NULL if it's an in-memory graft */ char *path; unsigned char path_checksum[GIT_HASH_SHA256_SIZE]; }; -int git_grafts_new(git_grafts **out) +int git_grafts_new(git_grafts **out, git_oid_t oid_type) { git_grafts *grafts; + GIT_ASSERT_ARG(out && oid_type); + grafts = git__calloc(1, sizeof(*grafts)); GIT_ERROR_CHECK_ALLOC(grafts); @@ -33,19 +38,26 @@ int git_grafts_new(git_grafts **out) return -1; } + grafts->oid_type = oid_type; + *out = grafts; return 0; } -int git_grafts_from_file(git_grafts **out, const char *path) +int git_grafts_from_file( + git_grafts **out, + const char *path, + git_oid_t oid_type) { git_grafts *grafts = NULL; int error; + GIT_ASSERT_ARG(path && oid_type); + if (*out) return git_grafts_refresh(*out); - if ((error = git_grafts_new(&grafts)) < 0) + if ((error = git_grafts_new(&grafts, oid_type)) < 0) goto error; grafts->path = git__strdup(path); @@ -133,7 +145,7 @@ int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len) for (; parser.remain_len; git_parse_advance_line(&parser)) { git_oid graft_oid; - if ((error = git_parse_advance_oid(&graft_oid, &parser, GIT_OID_SHA1)) < 0) { + if ((error = git_parse_advance_oid(&graft_oid, &parser, grafts->oid_type)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num); goto error; } @@ -143,7 +155,7 @@ int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len) GIT_ERROR_CHECK_ALLOC(id); if ((error = git_parse_advance_expected(&parser, " ", 1)) < 0 || - (error = git_parse_advance_oid(id, &parser, GIT_OID_SHA1)) < 0) { + (error = git_parse_advance_oid(id, &parser, grafts->oid_type)) < 0) { git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num); goto error; } diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h index fc61468f576..0c0e9cecbd6 100644 --- a/src/libgit2/grafts.h +++ b/src/libgit2/grafts.h @@ -19,13 +19,13 @@ typedef struct { typedef struct git_grafts git_grafts; -int git_grafts_new(git_grafts **out); -int git_grafts_from_file(git_grafts **out, const char *path); +int git_grafts_new(git_grafts **out, git_oid_t oid_type); +int git_grafts_from_file(git_grafts **out, const char *path, git_oid_t oid_type); void git_grafts_free(git_grafts *grafts); void git_grafts_clear(git_grafts *grafts); int git_grafts_refresh(git_grafts *grafts); -int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen); +int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len); int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); int git_grafts_remove(git_grafts *grafts, const git_oid *oid); int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index a60fb23fa0a..5778a86f7e9 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -852,13 +852,13 @@ static int load_grafts(git_repository *repo) if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || - (error = git_grafts_from_file(&repo->grafts, path.ptr)) < 0) + (error = git_grafts_from_file(&repo->grafts, path.ptr, repo->oid_type)) < 0) goto error; git_str_clear(&path); if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 || - (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr)) < 0) + (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr, repo->oid_type)) < 0) goto error; error: diff --git a/tests/libgit2/grafts/basic.c b/tests/libgit2/grafts/basic.c index fe747709715..30c87f908af 100644 --- a/tests/libgit2/grafts/basic.c +++ b/tests/libgit2/grafts/basic.c @@ -22,7 +22,7 @@ void test_grafts_basic__graft_add(void) git_commit_graft *graft; git_grafts *grafts; - cl_git_pass(git_grafts_new(&grafts)); + cl_git_pass(git_grafts_new(&grafts, GIT_OID_SHA1)); cl_assert(oid1 = git_array_alloc(parents)); cl_git_pass(git_oid__fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9", GIT_OID_SHA1)); diff --git a/tests/libgit2/grafts/parse.c b/tests/libgit2/grafts/parse.c index 149b01c8c7b..3b0618a1d99 100644 --- a/tests/libgit2/grafts/parse.c +++ b/tests/libgit2/grafts/parse.c @@ -19,7 +19,7 @@ static git_grafts *grafts; void test_grafts_parse__initialize(void) { - cl_git_pass(git_grafts_new(&grafts)); + cl_git_pass(git_grafts_new(&grafts, GIT_OID_SHA1)); } void test_grafts_parse__cleanup(void) From 3388f5ba1b821e9683d21ca41c34ed752d2db222 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Apr 2023 09:31:34 +0100 Subject: [PATCH 167/816] shallow: don't default to -1 for depth Depth of `0` should indicate full depth. Disallow negative values (they may have a future meaning) and use `0` as the default. --- include/git2/remote.h | 6 +++--- src/libgit2/clone.c | 2 +- src/libgit2/fetch.c | 13 +++++-------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 9e4043f87bd..8d612701416 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -744,9 +744,9 @@ typedef struct { git_proxy_options proxy_opts; /** - * Depth of the fetch to perform. Depth <= 0 fetches the full history. + * Depth of the fetch to perform, or 0 for full history. * - * The default is -1. + * The default is 0. */ int depth; @@ -772,7 +772,7 @@ typedef struct { #define GIT_FETCH_OPTIONS_VERSION 1 #define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ - GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, -1, 0 } + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT } /** * Initialize git_fetch_options structure diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index 43341a493f4..fca0ca0cc7c 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -421,7 +421,7 @@ static int clone_into( memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); fetch_opts.update_fetchhead = 0; - if (opts->depth <= 0) + if (!opts->depth) fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index d66892ca0b9..86b650a60c5 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -172,10 +172,12 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) remote->need_pack = 0; - if (!opts) - remote->nego.depth = -1; - else + if (opts) { + GIT_ASSERT_ARG(opts->unshallow == 0 || opts->depth == 0); + GIT_ASSERT_ARG(opts->depth >= 0); + remote->nego.depth = opts->unshallow ? INT_MAX : opts->depth; + } if (filter_wants(remote, opts) < 0) return -1; @@ -184,11 +186,6 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) if (!remote->need_pack) return 0; - if (opts && opts->unshallow && opts->depth > 0) { - git_error_set(GIT_ERROR_INVALID, "options '--depth' and '--unshallow' cannot be used together"); - return -1; - } - /* * Now we have everything set up so we can start tell the * server what we want and what we have. From 19ccab005ed2a65ddcd3f50a2a09214a5849871d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Apr 2023 09:33:24 +0100 Subject: [PATCH 168/816] shallow: cleanup whitespace in tests --- tests/libgit2/transports/smart/shallowarray.c | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/libgit2/transports/smart/shallowarray.c b/tests/libgit2/transports/smart/shallowarray.c index ec4388e42d3..34511c5f641 100644 --- a/tests/libgit2/transports/smart/shallowarray.c +++ b/tests/libgit2/transports/smart/shallowarray.c @@ -15,37 +15,37 @@ void test_transports_smart_shallowarray__add_and_remove_oid_from_shallowarray(void) { - git_oid oid_0_obj, oid_1_obj, oid_2_obj; - git_shallowarray *shallow_roots = git__malloc(sizeof(git_shallowarray)); - git_array_init(shallow_roots->array); + git_oid oid_0_obj, oid_1_obj, oid_2_obj; + git_shallowarray *shallow_roots = git__malloc(sizeof(git_shallowarray)); + git_array_init(shallow_roots->array); - git_oid__fromstr(&oid_0_obj, oid_0, GIT_OID_SHA1); - git_oid__fromstr(&oid_1_obj, oid_1, GIT_OID_SHA1); - git_oid__fromstr(&oid_2_obj, oid_2, GIT_OID_SHA1); + git_oid__fromstr(&oid_0_obj, oid_0, GIT_OID_SHA1); + git_oid__fromstr(&oid_1_obj, oid_1, GIT_OID_SHA1); + git_oid__fromstr(&oid_2_obj, oid_2, GIT_OID_SHA1); - git_shallowarray_add(shallow_roots, &oid_0_obj); - git_shallowarray_add(shallow_roots, &oid_1_obj); - git_shallowarray_add(shallow_roots, &oid_2_obj); + git_shallowarray_add(shallow_roots, &oid_0_obj); + git_shallowarray_add(shallow_roots, &oid_1_obj); + git_shallowarray_add(shallow_roots, &oid_2_obj); - cl_assert_equal_i(3, shallow_roots->array.size); + cl_assert_equal_i(3, shallow_roots->array.size); cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1])); cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&shallow_roots->array.ptr[2])); - git_shallowarray_remove(shallow_roots, &oid_2_obj); + git_shallowarray_remove(shallow_roots, &oid_2_obj); - cl_assert_equal_i(2, shallow_roots->array.size); + cl_assert_equal_i(2, shallow_roots->array.size); cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1])); - git_shallowarray_remove(shallow_roots, &oid_1_obj); + git_shallowarray_remove(shallow_roots, &oid_1_obj); - cl_assert_equal_i(1, shallow_roots->array.size); + cl_assert_equal_i(1, shallow_roots->array.size); cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); - git_shallowarray_remove(shallow_roots, &oid_0_obj); + git_shallowarray_remove(shallow_roots, &oid_0_obj); - cl_assert_equal_i(0, shallow_roots->array.size); + cl_assert_equal_i(0, shallow_roots->array.size); git_array_clear(shallow_roots->array); git__free(shallow_roots); From 43db928895fa85e4ee104dc8757275400d5acc2a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Apr 2023 10:48:33 +0100 Subject: [PATCH 169/816] grafts: make `from_file` be `open_or_refresh` The semantics of `from_file` are weird - it looks like a function that just opens a file, but it actually inspects the pointer, which is unexpected and could make things very crashy. Make an `open` function that just does an open, and move the magic to `open_or_refresh` whose name better indicates that it may do weird stuff. --- src/libgit2/grafts.c | 19 ++++++++++++++----- src/libgit2/grafts.h | 3 ++- src/libgit2/repository.c | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 00de03e8b21..83f5b2ab418 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -44,7 +44,7 @@ int git_grafts_new(git_grafts **out, git_oid_t oid_type) return 0; } -int git_grafts_from_file( +int git_grafts_open( git_grafts **out, const char *path, git_oid_t oid_type) @@ -52,10 +52,7 @@ int git_grafts_from_file( git_grafts *grafts = NULL; int error; - GIT_ASSERT_ARG(path && oid_type); - - if (*out) - return git_grafts_refresh(*out); + GIT_ASSERT_ARG(out && path && oid_type); if ((error = git_grafts_new(&grafts, oid_type)) < 0) goto error; @@ -67,12 +64,24 @@ int git_grafts_from_file( goto error; *out = grafts; + error: if (error < 0) git_grafts_free(grafts); + return error; } +int git_grafts_open_or_refresh( + git_grafts **out, + const char *path, + git_oid_t oid_type) +{ + GIT_ASSERT_ARG(out && path && oid_type); + + return *out ? git_grafts_refresh(*out) : git_grafts_open(out, path, oid_type); +} + void git_grafts_free(git_grafts *grafts) { if (!grafts) diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h index 0c0e9cecbd6..0d561fc2538 100644 --- a/src/libgit2/grafts.h +++ b/src/libgit2/grafts.h @@ -20,7 +20,8 @@ typedef struct { typedef struct git_grafts git_grafts; int git_grafts_new(git_grafts **out, git_oid_t oid_type); -int git_grafts_from_file(git_grafts **out, const char *path, git_oid_t oid_type); +int git_grafts_open(git_grafts **out, const char *path, git_oid_t oid_type); +int git_grafts_open_or_refresh(git_grafts **out, const char *path, git_oid_t oid_type); void git_grafts_free(git_grafts *grafts); void git_grafts_clear(git_grafts *grafts); diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 5778a86f7e9..763b62375ab 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -852,13 +852,13 @@ static int load_grafts(git_repository *repo) if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || - (error = git_grafts_from_file(&repo->grafts, path.ptr, repo->oid_type)) < 0) + (error = git_grafts_open_or_refresh(&repo->grafts, path.ptr, repo->oid_type)) < 0) goto error; git_str_clear(&path); if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 || - (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr, repo->oid_type)) < 0) + (error = git_grafts_open_or_refresh(&repo->shallow_grafts, path.ptr, repo->oid_type)) < 0) goto error; error: From 04cddffea9d00d5788b4f41a7dce3356089228ab Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Apr 2023 13:29:35 +0100 Subject: [PATCH 170/816] cli: add --depth option to clone --- src/cli/cmd_clone.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/cli/cmd_clone.c b/src/cli/cmd_clone.c index a382b5875df..e4776256cb3 100644 --- a/src/cli/cmd_clone.c +++ b/src/cli/cmd_clone.c @@ -18,7 +18,7 @@ #define COMMAND_NAME "clone" -static char *branch, *remote_path, *local_path; +static char *branch, *remote_path, *local_path, *depth; static int show_help, quiet, checkout = 1, bare; static bool local_path_exists; static cli_progress progress = CLI_PROGRESS_INIT; @@ -36,6 +36,8 @@ static const cli_opt_spec opts[] = { CLI_OPT_USAGE_DEFAULT, NULL, "don't create a working directory" }, { CLI_OPT_TYPE_VALUE, "branch", 'b', &branch, 0, CLI_OPT_USAGE_DEFAULT, "name", "branch to check out" }, + { CLI_OPT_TYPE_VALUE, "depth", 0, &depth, 0, + CLI_OPT_USAGE_DEFAULT, "depth", "commit depth to check out " }, { CLI_OPT_TYPE_LITERAL }, { CLI_OPT_TYPE_ARG, "repository", 0, &remote_path, 0, CLI_OPT_USAGE_REQUIRED, "repository", "repository path" }, @@ -71,6 +73,22 @@ static char *compute_local_path(const char *orig_path) return local_path; } +static int compute_depth(const char *depth) +{ + int64_t i; + const char *endptr; + + if (!depth) + return 0; + + if (git__strntol64(&i, depth, strlen(depth), &endptr, 10) < 0 || i < 0 || i > INT_MAX || *endptr) { + fprintf(stderr, "fatal: depth '%s' is not valid.\n", depth); + exit(128); + } + + return (int)i; +} + static bool validate_local_path(const char *path) { if (!git_fs_path_exists(path)) @@ -127,11 +145,9 @@ int cmd_clone(int argc, char **argv) goto done; } - if (bare) - clone_opts.bare = 1; - - if (branch) - clone_opts.checkout_branch = branch; + clone_opts.bare = !!bare; + clone_opts.checkout_branch = branch; + clone_opts.fetch_opts.depth = compute_depth(depth); if (!checkout) clone_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE; From d873966fdeae7f0ac974318ce21772af555f1660 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 3 May 2023 22:47:12 +0200 Subject: [PATCH 171/816] util: detect all possible qsort_r and qsort_s variants As reported in https://bugs.freebsd.org/271234, recent versions of FreeBSD have adjusted the prototype for qsort_r() to match the POSIX interface. This causes libgit2's CMake configuration check to fail to detect qsort_r(), making it fall back to qsort_s(), which in libgit2 also has an incompatible interface. With recent versions of clang this results in a "incompatible function pointer types" compile error. Summarizing, there are four variations of 'qsort-with-context': * old style BSD qsort_r(), used in FreeBSD 13 and earlier, where the comparison function has the context parameter first * GNU or POSIX qsort_r(), also used in FreeBSD 14 and later, where the comparison function has the context parameter last * C11 qsort_s(), where the comparison function has the context parameter last * Microsoft qsort_s(), where the comparison function has the context parameter first Add explicit detections for all these variants, so they get detected as (in the same order as above): * `GIT_QSORT_R_BSD` * `GIT_QSORT_R_GNU` * `GIT_QSORT_S_C11` * `GIT_QSORT_S_MSC` An additional complication is that on FreeBSD 14 and later, uses the C11 _Generic() macro mechanism to automatically select the correct qsort_r() prototype, depending on the caller's comparison function argument. This breaks CMake's check_prototype_definition() functionality, since it tries to redefine the function, and _Generic macro is expanded inline causing a compile error. Work around that problem by putting the function names in parentheses, to prevent the preprocessor from using a macro to replace the function name. Also, in `git__qsort_r()`, change the `#if` order so the variants that do not have to use glue are preferred. --- src/CMakeLists.txt | 20 +++++++++++++++++--- src/util/git2_features.h.in | 3 ++- src/util/util.c | 17 ++++++++++------- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc0a0d4dce6..de591e4e4eb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,15 +58,29 @@ add_feature_info(futimens GIT_USE_FUTIMENS "futimens support") # qsort +# old-style FreeBSD qsort_r() has the 'context' parameter as the first argument +# of the comparison function: check_prototype_definition(qsort_r - "void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compar)(void *, const void *, const void *))" + "void (qsort_r)(void *base, size_t nmemb, size_t size, void *context, int (*compar)(void *, const void *, const void *))" "" "stdlib.h" GIT_QSORT_R_BSD) +# GNU or POSIX qsort_r() has the 'context' parameter as the last argument of the +# comparison function: check_prototype_definition(qsort_r - "void qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg)" + "void (qsort_r)(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *context)" "" "stdlib.h" GIT_QSORT_R_GNU) -check_function_exists(qsort_s GIT_QSORT_S) +# C11 qsort_s() has the 'context' parameter as the last argument of the +# comparison function, and returns an error status: +check_prototype_definition(qsort_s + "errno_t (qsort_s)(void *base, rsize_t nmemb, rsize_t size, int (*compar)(const void *, const void *, void *), void *context)" + "0" "stdlib.h" GIT_QSORT_S_C11) + +# MSC qsort_s() has the 'context' parameter as the first argument of the +# comparison function, and as the last argument of qsort_s(): +check_prototype_definition(qsort_s + "void (qsort_s)(void *base, size_t num, size_t width, int (*compare )(void *, const void *, const void *), void *context)" + "" "stdlib.h" GIT_QSORT_S_MSC) # random / entropy data diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 1575be641e1..5f606df8494 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -26,7 +26,8 @@ #cmakedefine GIT_QSORT_R_BSD #cmakedefine GIT_QSORT_R_GNU -#cmakedefine GIT_QSORT_S +#cmakedefine GIT_QSORT_S_C11 +#cmakedefine GIT_QSORT_S_MSC #cmakedefine GIT_SSH 1 #cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1 diff --git a/src/util/util.c b/src/util/util.c index 9c9f2c0403a..f4eaf5835ab 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -18,7 +18,7 @@ # endif # include -# ifdef GIT_QSORT_S +# ifdef GIT_QSORT_S_MSC # include # endif #endif @@ -673,7 +673,7 @@ size_t git__unescape(char *str) return (pos - str); } -#if defined(GIT_QSORT_S) || defined(GIT_QSORT_R_BSD) +#if defined(GIT_QSORT_S_MSC) || defined(GIT_QSORT_R_BSD) typedef struct { git__sort_r_cmp cmp; void *payload; @@ -690,7 +690,8 @@ static int GIT_LIBGIT2_CALL git__qsort_r_glue_cmp( #if !defined(GIT_QSORT_R_BSD) && \ !defined(GIT_QSORT_R_GNU) && \ - !defined(GIT_QSORT_S) + !defined(GIT_QSORT_S_C11) && \ + !defined(GIT_QSORT_S_MSC) static void swap(uint8_t *a, uint8_t *b, size_t elsize) { char tmp[256]; @@ -721,12 +722,14 @@ static void insertsort( void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { -#if defined(GIT_QSORT_R_BSD) +#if defined(GIT_QSORT_R_GNU) + qsort_r(els, nel, elsize, cmp, payload); +#elif defined(GIT_QSORT_S_C11) + qsort_s(els, nel, elsize, cmp, payload); +#elif defined(GIT_QSORT_R_BSD) git__qsort_r_glue glue = { cmp, payload }; qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp); -#elif defined(GIT_QSORT_R_GNU) - qsort_r(els, nel, elsize, cmp, payload); -#elif defined(GIT_QSORT_S) +#elif defined(GIT_QSORT_S_MSC) git__qsort_r_glue glue = { cmp, payload }; qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue); #else From 3d9cb5e0c6b36bf7e226890515088259180de212 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Tue, 9 May 2023 16:59:45 +0200 Subject: [PATCH 172/816] Work around -Werror problems when detecting qsort variants If `ENABLE_WERROR` is on, the CMake configure tests for the `qsort_r` and `qsort_s` variants may fail due to warnings about unused functions or unused parameters. These warnings can be ignored, so disable them specifically for running those tests. --- src/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index de591e4e4eb..db0fd10c75d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,6 +58,13 @@ add_feature_info(futimens GIT_USE_FUTIMENS "futimens support") # qsort +# for these tests, temporarily save CMAKE_C_FLAGS and disable warnings about +# unused functions and parameters, otherwise they will always fail if +# ENABLE_WERROR is on +set(SAVED_CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") +disable_warnings(unused-function) +disable_warnings(unused-parameter) + # old-style FreeBSD qsort_r() has the 'context' parameter as the first argument # of the comparison function: check_prototype_definition(qsort_r @@ -82,6 +89,9 @@ check_prototype_definition(qsort_s "void (qsort_s)(void *base, size_t num, size_t width, int (*compare )(void *, const void *, const void *), void *context)" "" "stdlib.h" GIT_QSORT_S_MSC) +# restore CMAKE_C_FLAGS +set(CMAKE_C_FLAGS "${SAVED_CMAKE_C_FLAGS}") + # random / entropy data check_function_exists(getentropy GIT_RAND_GETENTROPY) From 0a7e32b2326c02a91f9560dfd209e56ea9fb9d49 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 8 May 2023 10:07:11 +0100 Subject: [PATCH 173/816] oid: use an oid array instead of shallowarray Users should provide us an array of object ids; we don't need a separate type. And especially, we should not be mutating user-providing values. Instead, use `git_oid *` in the shallow code. --- include/git2/sys/transport.h | 22 +++-- src/libgit2/fetch.c | 29 +++--- src/libgit2/grafts.c | 16 ++- src/libgit2/grafts.h | 2 +- src/libgit2/oidarray.c | 52 +++++++++- src/libgit2/oidarray.h | 6 +- src/libgit2/remote.c | 5 - src/libgit2/repository.c | 20 ++-- src/libgit2/repository.h | 4 +- src/libgit2/transports/local.c | 11 +++ src/libgit2/transports/smart.c | 49 +--------- src/libgit2/transports/smart.h | 7 +- src/libgit2/transports/smart_pkt.c | 13 ++- src/libgit2/transports/smart_protocol.c | 56 +++++++++-- src/util/array.h | 3 + tests/libgit2/core/oidarray.c | 98 +++++++++++++++++++ tests/libgit2/online/shallow.c | 35 ++++--- tests/libgit2/transports/smart/shallowarray.c | 52 ---------- 18 files changed, 304 insertions(+), 176 deletions(-) create mode 100644 tests/libgit2/core/oidarray.c delete mode 100644 tests/libgit2/transports/smart/shallowarray.c diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 062bcd0edf1..96a35d08cb2 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -25,12 +25,11 @@ GIT_BEGIN_DECL -typedef struct git_shallowarray git_shallowarray; - typedef struct { const git_remote_head * const *refs; - size_t count; - git_shallowarray *shallow_roots; + size_t refs_len; + git_oid *shallow_roots; + size_t shallow_roots_len; int depth; } git_fetch_negotiation; @@ -107,6 +106,16 @@ struct git_transport { git_repository *repo, const git_fetch_negotiation *fetch_data); + /** + * Return the shallow roots of the remote. + * + * This function may be called after a successful call to + * `negotiate_fetch`. + */ + int GIT_CALLBACK(shallow_roots)( + git_oidarray *out, + git_transport *transport); + /** * Start downloading the packfile from the remote repository. * @@ -450,11 +459,6 @@ GIT_EXTERN(int) git_smart_subtransport_ssh( git_transport *owner, void *param); -GIT_EXTERN(size_t) git_shallowarray_count(git_shallowarray *array); -GIT_EXTERN(const git_oid *) git_shallowarray_get(git_shallowarray *array, size_t idx); -GIT_EXTERN(int) git_shallowarray_add(git_shallowarray *array, git_oid *oid); -GIT_EXTERN(int) git_shallowarray_remove(git_shallowarray *array, git_oid *oid); - /** @} */ GIT_END_DECL #endif diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 86b650a60c5..b4342521591 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -61,7 +61,7 @@ static int mark_local(git_remote *remote) git_vector_foreach(&remote->refs, i, head) { /* If we have the object, mark it so we don't ask for it. - However if we are unshallowing, we need to ask for it + However if we are unshallowing, we need to ask for it even though the head exists locally. */ if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid)) head->local = 1; @@ -169,6 +169,7 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts) int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) { git_transport *t = remote->transport; + int error; remote->need_pack = 0; @@ -191,33 +192,39 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) * server what we want and what we have. */ remote->nego.refs = (const git_remote_head * const *)remote->refs.contents; - remote->nego.count = remote->refs.length; - remote->nego.shallow_roots = git__malloc(sizeof(*remote->nego.shallow_roots)); - - git_array_init(remote->nego.shallow_roots->array); + remote->nego.refs_len = remote->refs.length; - git_repository__shallow_roots(&remote->nego.shallow_roots->array, remote->repo); + if (git_repository__shallow_roots(&remote->nego.shallow_roots, + &remote->nego.shallow_roots_len, + remote->repo) < 0) + return -1; - return t->negotiate_fetch(t, + error = t->negotiate_fetch(t, remote->repo, &remote->nego); + + git__free(remote->nego.shallow_roots); + + return error; } int git_fetch_download_pack(git_remote *remote) { + git_oidarray shallow_roots = { NULL }; git_transport *t = remote->transport; int error; if (!remote->need_pack) return 0; - if ((error = t->download_pack(t, remote->repo, &remote->stats)) != 0) + if ((error = t->download_pack(t, remote->repo, &remote->stats)) != 0 || + (error = t->shallow_roots(&shallow_roots, t)) != 0) return error; - if ((error = git_repository__shallow_roots_write(remote->repo, remote->nego.shallow_roots->array)) != 0) - return error; + error = git_repository__shallow_roots_write(remote->repo, &shallow_roots); - return 0; + git_oidarray_dispose(&shallow_roots); + return error; } int git_fetch_options_init(git_fetch_options *opts, unsigned int version) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 83f5b2ab418..1d9373a56f6 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -243,20 +243,26 @@ int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oi return 0; } -int git_grafts_get_oids(git_array_oid_t *out, git_grafts *grafts) +int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts) { + git_array_oid_t array = GIT_ARRAY_INIT; const git_oid *oid; - size_t i = 0; - int error; + size_t existing, i = 0; GIT_ASSERT_ARG(out && grafts); - while ((error = git_oidmap_iterate(NULL, grafts->commits, &i, &oid)) == 0) { - git_oid *cpy = git_array_alloc(*out); + if ((existing = git_oidmap_size(grafts->commits)) > 0) + git_array_init_to_size(array, existing); + + while (git_oidmap_iterate(NULL, grafts->commits, &i, &oid) == 0) { + git_oid *cpy = git_array_alloc(array); GIT_ERROR_CHECK_ALLOC(cpy); git_oid_cpy(cpy, oid); } + *out = array.ptr; + *out_len = array.size; + return 0; } diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h index 0d561fc2538..394867fd6cc 100644 --- a/src/libgit2/grafts.h +++ b/src/libgit2/grafts.h @@ -30,7 +30,7 @@ int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len); int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); int git_grafts_remove(git_grafts *grafts, const git_oid *oid); int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); -int git_grafts_get_oids(git_array_oid_t *out, git_grafts *grafts); +int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts); size_t git_grafts_size(git_grafts *grafts); #endif diff --git a/src/libgit2/oidarray.c b/src/libgit2/oidarray.c index 583017c4ee2..37f67756aa5 100644 --- a/src/libgit2/oidarray.c +++ b/src/libgit2/oidarray.c @@ -15,10 +15,17 @@ void git_oidarray_dispose(git_oidarray *arr) git__free(arr->ids); } -void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array) +void git_oidarray__from_array(git_oidarray *out, const git_array_oid_t *array) { - arr->count = array->size; - arr->ids = array->ptr; + out->count = array->size; + out->ids = array->ptr; +} + +void git_oidarray__to_array(git_array_oid_t *out, const git_oidarray *array) +{ + out->ptr = array->ids; + out->size = array->count; + out->asize = array->count; } void git_oidarray__reverse(git_oidarray *arr) @@ -33,6 +40,45 @@ void git_oidarray__reverse(git_oidarray *arr) } } +int git_oidarray__add(git_array_oid_t *arr, git_oid *id) +{ + git_oid *add, *iter; + size_t i; + + git_array_foreach(*arr, i, iter) { + if (git_oid_cmp(iter, id) == 0) + return 0; + } + + if ((add = git_array_alloc(*arr)) == NULL) + return -1; + + git_oid_cpy(add, id); + return 0; +} + +bool git_oidarray__remove(git_array_oid_t *arr, git_oid *id) +{ + bool found = false; + size_t remain, i; + git_oid *iter; + + git_array_foreach(*arr, i, iter) { + if (git_oid_cmp(iter, id) == 0) { + arr->size--; + remain = arr->size - i; + + if (remain > 0) + memmove(&arr->ptr[i], &arr->ptr[i+1], remain * sizeof(git_oid)); + + found = true; + break; + } + } + + return found; +} + #ifndef GIT_DEPRECATE_HARD void git_oidarray_free(git_oidarray *arr) diff --git a/src/libgit2/oidarray.h b/src/libgit2/oidarray.h index eed3a109120..8f1543a32e0 100644 --- a/src/libgit2/oidarray.h +++ b/src/libgit2/oidarray.h @@ -15,6 +15,10 @@ typedef git_array_t(git_oid) git_array_oid_t; extern void git_oidarray__reverse(git_oidarray *arr); -extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array); +extern void git_oidarray__from_array(git_oidarray *out, const git_array_oid_t *array); +extern void git_oidarray__to_array(git_array_oid_t *out, const git_oidarray *array); + +int git_oidarray__add(git_array_oid_t *arr, git_oid *id); +bool git_oidarray__remove(git_array_oid_t *arr, git_oid *id); #endif diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index ef414209f42..fee2a7f3968 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2167,11 +2167,6 @@ void git_remote_free(git_remote *remote) remote->transport = NULL; } - if (remote->nego.shallow_roots) { - git_array_clear(remote->nego.shallow_roots->array); - git__free(remote->nego.shallow_roots); - } - git_vector_free(&remote->refs); free_refspecs(&remote->refspecs); diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 763b62375ab..8fcc4e2ba60 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3651,7 +3651,11 @@ int git_repository_state_cleanup(git_repository *repo) return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); } -int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { +int git_repository__shallow_roots( + git_oid **out, + size_t *out_len, + git_repository *repo) +{ int error = 0; if (!repo->shallow_grafts && (error = load_grafts(repo)) < 0) @@ -3660,19 +3664,18 @@ int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo) { if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0) return error; - if ((error = git_grafts_get_oids(out, repo->shallow_grafts)) < 0) + if ((error = git_grafts_oids(out, out_len, repo->shallow_grafts)) < 0) return error; return 0; } -int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots) +int git_repository__shallow_roots_write(git_repository *repo, git_oidarray *roots) { git_filebuf file = GIT_FILEBUF_INIT; git_str path = GIT_STR_INIT; char oid_str[GIT_OID_MAX_HEXSIZE + 1]; - size_t idx; - git_oid *oid; + size_t i; int filebuf_hash, error = 0; GIT_ASSERT_ARG(repo); @@ -3686,8 +3689,8 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro if ((error = git_filebuf_open(&file, git_str_cstr(&path), filebuf_hash, 0666)) < 0) goto on_error; - git_array_foreach(roots, idx, oid) { - git_oid_tostr(oid_str, sizeof(oid_str), oid); + for (i = 0; i < roots->count; i++) { + git_oid_tostr(oid_str, sizeof(oid_str), &roots->ids[i]); git_filebuf_write(&file, oid_str, git_oid_hexsize(repo->oid_type)); git_filebuf_write(&file, "\n", 1); } @@ -3699,7 +3702,7 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro goto on_error; } - if (git_array_size(roots) == 0) + if (!roots->count) remove(path.ptr); on_error: @@ -3727,6 +3730,7 @@ int git_repository_is_shallow(git_repository *repo) if (error < 0) return error; + return st.st_size == 0 ? 0 : 1; } diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index d86b3627142..8dc20324dcc 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -246,8 +246,8 @@ extern size_t git_repository__reserved_names_posix_len; bool git_repository__reserved_names( git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs); -int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo); -int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots); +int git_repository__shallow_roots(git_oid **out, size_t *out_len, git_repository *repo); +int git_repository__shallow_roots_write(git_repository *repo, git_oidarray *roots); /* * The default branch for the repository; the `init.defaultBranch` diff --git a/src/libgit2/transports/local.c b/src/libgit2/transports/local.c index f576682a77f..64c21afbd0d 100644 --- a/src/libgit2/transports/local.c +++ b/src/libgit2/transports/local.c @@ -320,6 +320,16 @@ static int local_negotiate_fetch( return 0; } +static int local_shallow_roots( + git_oidarray *out, + git_transport *transport) +{ + GIT_UNUSED(out); + GIT_UNUSED(transport); + + return 0; +} + static int local_push_update_remote_ref( git_repository *remote_repo, const char *lref, @@ -745,6 +755,7 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param) t->parent.oid_type = local_oid_type; #endif t->parent.negotiate_fetch = local_negotiate_fetch; + t->parent.shallow_roots = local_shallow_roots; t->parent.download_pack = local_download_pack; t->parent.push = local_push; t->parent.close = local_close; diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index da6dca0392a..a56524bff0a 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -416,6 +416,8 @@ static void git_smart__free(git_transport *transport) git_remote_connect_options_dispose(&t->connect_opts); + git_array_dispose(t->shallow_roots); + git__free(t->caps.object_format); git__free(t->caps.agent); git__free(t); @@ -490,6 +492,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) t->parent.close = git_smart__close; t->parent.free = git_smart__free; t->parent.negotiate_fetch = git_smart__negotiate_fetch; + t->parent.shallow_roots = git_smart__shallow_roots; t->parent.download_pack = git_smart__download_pack; t->parent.push = git_smart__push; t->parent.ls = git_smart__ls; @@ -517,49 +520,3 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) *out = (git_transport *) t; return 0; } - -size_t git_shallowarray_count(git_shallowarray *array) -{ - return git_array_size(array->array); -} - -const git_oid * git_shallowarray_get(git_shallowarray *array, size_t idx) -{ - return git_array_get(array->array, idx); -} - -int git_shallowarray_add(git_shallowarray *array, git_oid *oid) -{ - size_t oid_index; - - if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, oid) < 0) { - git_oid *tmp = git_array_alloc(array->array); - GIT_ERROR_CHECK_ALLOC(tmp); - - git_oid_cpy(tmp, oid); - } - - return 0; -} - -int git_shallowarray_remove(git_shallowarray *array, git_oid *oid) -{ - git_array_oid_t new_array = GIT_ARRAY_INIT; - git_oid *element; - git_oid *tmp; - size_t i; - - git_array_foreach(array->array, i, element) { - if (git_oid_cmp(oid, element)) { - tmp = git_array_alloc(new_array); - GIT_ERROR_CHECK_ALLOC(tmp); - - git_oid_cpy(tmp, element); - } - } - - git_array_clear(array->array); - array->array = new_array; - - return 0; -} diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 8e06d03ef6e..34e27ea8e05 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -163,6 +163,7 @@ typedef struct { git_vector refs; git_vector heads; git_vector common; + git_array_oid_t shallow_roots; git_atomic32 cancelled; packetsize_cb packetsize_cb; void *packetsize_payload; @@ -183,6 +184,8 @@ int git_smart__negotiate_fetch( git_repository *repo, const git_fetch_negotiation *wants); +int git_smart__shallow_roots(git_oidarray *out, git_transport *transport); + int git_smart__download_pack( git_transport *transport, git_repository *repo, @@ -208,8 +211,4 @@ int git_pkt_buffer_wants(const git_fetch_negotiation *wants, transport_smart_cap int git_pkt_buffer_have(git_oid *oid, git_str *buf); void git_pkt_free(git_pkt *pkt); -struct git_shallowarray { - git_array_oid_t array; -}; - #endif diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index f2c9eea8e5e..9127ad5fe43 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -770,7 +770,7 @@ int git_pkt_buffer_wants( size_t oid_hexsize, want_len, i = 0; #ifdef GIT_EXPERIMENTAL_SHA256 - oid_type = wants->count > 0 ? wants->refs[0]->oid.type : GIT_OID_SHA1; + oid_type = wants->refs_len > 0 ? wants->refs[0]->oid.type : GIT_OID_SHA1; #else oid_type = GIT_OID_SHA1; #endif @@ -781,7 +781,7 @@ int git_pkt_buffer_wants( oid_hexsize + 1 /* LF */; if (caps->common) { - for (; i < wants->count; ++i) { + for (; i < wants->refs_len; ++i) { head = wants->refs[i]; if (!head->local) break; @@ -793,7 +793,7 @@ int git_pkt_buffer_wants( i++; } - for (; i < wants->count; ++i) { + for (; i < wants->refs_len; ++i) { head = wants->refs[i]; if (head->local) @@ -810,12 +810,11 @@ int git_pkt_buffer_wants( } /* Tell the server about our shallow objects */ - for (i = 0; i < git_shallowarray_count(wants->shallow_roots); i++) { + for (i = 0; i < wants->shallow_roots_len; i++) { char oid[GIT_OID_MAX_HEXSIZE + 1]; git_str shallow_buf = GIT_STR_INIT; - git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, - git_shallowarray_get(wants->shallow_roots, i)); + git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, &wants->shallow_roots[i]); git_str_puts(&shallow_buf, "shallow "); git_str_puts(&shallow_buf, oid); git_str_putc(&shallow_buf, '\n'); @@ -835,7 +834,7 @@ int git_pkt_buffer_wants( git_str_printf(buf,"%04x%s", (unsigned int)git_str_len(&deepen_buf) + 4, git_str_cstr(&deepen_buf)); git_str_dispose(&deepen_buf); - + if (git_str_oom(buf)) return -1; } diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 6167a807409..488ef07c089 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -364,7 +364,9 @@ static int cap_not_sup_err(const char *cap_name) } /* Disables server capabilities we're not interested in */ -static int setup_caps(transport_smart_caps *caps, const git_fetch_negotiation *wants) +static int setup_caps( + transport_smart_caps *caps, + const git_fetch_negotiation *wants) { if (wants->depth > 0) { if (!caps->shallow) @@ -376,7 +378,27 @@ static int setup_caps(transport_smart_caps *caps, const git_fetch_negotiation *w return 0; } -int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_fetch_negotiation *wants) +static int setup_shallow_roots( + git_array_oid_t *out, + const git_fetch_negotiation *wants) +{ + git_array_clear(*out); + + if (wants->shallow_roots_len > 0) { + git_array_init_to_size(*out, wants->shallow_roots_len); + GIT_ERROR_CHECK_ALLOC(out->ptr); + + memcpy(out->ptr, wants->shallow_roots, + sizeof(git_oid) * wants->shallow_roots_len); + } + + return 0; +} + +int git_smart__negotiate_fetch( + git_transport *transport, + git_repository *repo, + const git_fetch_negotiation *wants) { transport_smart *t = (transport_smart *)transport; git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT; @@ -388,7 +410,8 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c unsigned int i; git_oid oid; - if ((error = setup_caps(&t->caps, wants)) < 0) + if ((error = setup_caps(&t->caps, wants)) < 0 || + (error = setup_shallow_roots(&t->shallow_roots, wants)) < 0) return error; if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0) @@ -411,9 +434,9 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c bool complete = false; if (pkt->type == GIT_PKT_SHALLOW) { - git_shallowarray_add(wants->shallow_roots, &pkt->oid); + error = git_oidarray__add(&t->shallow_roots, &pkt->oid); } else if (pkt->type == GIT_PKT_UNSHALLOW) { - git_shallowarray_remove(wants->shallow_roots, &pkt->oid); + git_oidarray__remove(&t->shallow_roots, &pkt->oid); } else if (pkt->type == GIT_PKT_FLUSH) { /* Server is done, stop processing shallow oids */ complete = true; @@ -431,6 +454,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c if (error < 0) goto on_error; } + /* * Our support for ACK extensions is simply to parse them. On * the first ACK we will accept that as enough common @@ -531,10 +555,11 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c goto on_error; if (t->cancelled.val) { - git_error_set(GIT_ERROR_NET, "The fetch was cancelled by the user"); + git_error_set(GIT_ERROR_NET, "the fetch was cancelled"); error = GIT_EUSER; goto on_error; } + if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; @@ -562,6 +587,25 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c return error; } +int git_smart__shallow_roots(git_oidarray *out, git_transport *transport) +{ + transport_smart *t = (transport_smart *)transport; + size_t len; + + GIT_ERROR_CHECK_ALLOC_MULTIPLY(&len, t->shallow_roots.size, sizeof(git_oid)); + + out->count = t->shallow_roots.size; + + if (len) { + out->ids = git__malloc(len); + memcpy(out->ids, t->shallow_roots.ptr, len); + } else { + out->ids = NULL; + } + + return 0; +} + static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_indexer_progress *stats) { int recvd; diff --git a/src/util/array.h b/src/util/array.h index bf66e1c5a55..633d598ee26 100644 --- a/src/util/array.h +++ b/src/util/array.h @@ -33,6 +33,9 @@ #define git_array_init_to_size(a, desired) \ do { (a).size = 0; (a).asize = desired; (a).ptr = git__calloc(desired, sizeof(*(a).ptr)); } while (0) +#define git_array_dispose(a) \ + do { git__free((a).ptr); } while (0) + #define git_array_clear(a) \ do { git__free((a).ptr); git_array_init(a); } while (0) diff --git a/tests/libgit2/core/oidarray.c b/tests/libgit2/core/oidarray.c new file mode 100644 index 00000000000..4a9e47c701d --- /dev/null +++ b/tests/libgit2/core/oidarray.c @@ -0,0 +1,98 @@ +#include "clar_libgit2.h" + +#include "git2/oid.h" +#include "git2/transport.h" + +#include "common.h" +#include "transports/smart.h" +#include "oid.h" +#include "oidarray.h" + +#include + +#define oid_0 "c070ad8c08840c8116da865b2d65593a6bb9cd2a" +#define oid_1 "0966a434eb1a025db6b71485ab63a3bfbea520b6" +#define oid_2 "83834a7afdaa1a1260568567f6ad90020389f664" +#define oid_3 "746fb4c91a7b6190bc4761adf7410afc4b59812c" + +void test_core_oidarray__add_and_remove_oid_from_shallowarray(void) +{ + git_oid oid_0_obj, oid_1_obj, oid_2_obj, oid_3_obj; + git_array_oid_t array = GIT_ARRAY_INIT; + + git_oid__fromstr(&oid_0_obj, oid_0, GIT_OID_SHA1); + git_oid__fromstr(&oid_1_obj, oid_1, GIT_OID_SHA1); + git_oid__fromstr(&oid_2_obj, oid_2, GIT_OID_SHA1); + git_oid__fromstr(&oid_3_obj, oid_3, GIT_OID_SHA1); + + /* add some initial ids */ + git_oidarray__add(&array, &oid_0_obj); + git_oidarray__add(&array, &oid_1_obj); + git_oidarray__add(&array, &oid_2_obj); + + cl_assert_equal_i(3, array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&array.ptr[2])); + + /* don't duplicate existing ids */ + git_oidarray__add(&array, &oid_1_obj); + + cl_assert_equal_i(3, array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&array.ptr[2])); + + /* remove the last id */ + cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_2_obj)); + + cl_assert_equal_i(2, array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1])); + + /* add another id */ + git_oidarray__add(&array, &oid_3_obj); + + cl_assert_equal_i(3, array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1])); + cl_assert_equal_s("746fb4c91a7b6190bc4761adf7410afc4b59812c", git_oid_tostr_s(&array.ptr[2])); + + /* remove the first id */ + cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_0_obj)); + + cl_assert_equal_i(2, array.size); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[0])); + cl_assert_equal_s("746fb4c91a7b6190bc4761adf7410afc4b59812c", git_oid_tostr_s(&array.ptr[1])); + + /* removing a nonexistent oid does nothing */ + cl_assert_equal_i(0, git_oidarray__remove(&array, &oid_2_obj)); + + /* add another id */ + git_oidarray__add(&array, &oid_0_obj); + + cl_assert_equal_i(3, array.size); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[0])); + cl_assert_equal_s("746fb4c91a7b6190bc4761adf7410afc4b59812c", git_oid_tostr_s(&array.ptr[1])); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[2])); + + /* remove another id */ + cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_3_obj)); + + cl_assert_equal_i(2, array.size); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[0])); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[1])); + + /* remove another id */ + cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_1_obj)); + + cl_assert_equal_i(1, array.size); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0])); + + /* remove the final id */ + cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_0_obj)); + + cl_assert_equal_i(0, array.size); + + git_array_clear(array); +} diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c index a889a68cd6f..12ef7748b1a 100644 --- a/tests/libgit2/online/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -16,7 +16,8 @@ void test_online_shallow__clone_depth_zero(void) git_str path = GIT_STR_INIT; git_repository *repo; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; - git_array_oid_t roots = GIT_ARRAY_INIT; + git_oid *roots; + size_t roots_len; clone_opts.fetch_opts.depth = 0; clone_opts.remote_cb = remote_single_branch; @@ -29,10 +30,10 @@ void test_online_shallow__clone_depth_zero(void) cl_assert_equal_b(false, git_repository_is_shallow(repo)); /* full clones do not have shallow roots. */ - cl_git_pass(git_repository__shallow_roots(&roots, repo)); - cl_assert_equal_i(0, roots.size); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(0, roots_len); - git_array_clear(roots); + git__free(roots); git_str_dispose(&path); git_repository_free(repo); } @@ -44,7 +45,8 @@ void test_online_shallow__clone_depth_one(void) git_revwalk *walk; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_oid oid; - git_array_oid_t roots = GIT_ARRAY_INIT; + git_oid *roots; + size_t roots_len; size_t num_commits = 0; int error = 0; @@ -57,9 +59,9 @@ void test_online_shallow__clone_depth_one(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); - cl_git_pass(git_repository__shallow_roots(&roots, repo)); - cl_assert_equal_i(1, roots.size); - cl_assert_equal_s("49322bb17d3acc9146f98c97d078513228bbf3c0", git_oid_tostr_s(&roots.ptr[0])); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(1, roots_len); + cl_assert_equal_s("49322bb17d3acc9146f98c97d078513228bbf3c0", git_oid_tostr_s(&roots[0])); git_revwalk_new(&walk, repo); @@ -72,7 +74,7 @@ void test_online_shallow__clone_depth_one(void) cl_assert_equal_i(num_commits, 1); cl_assert_equal_i(error, GIT_ITEROVER); - git_array_clear(roots); + git__free(roots); git_str_dispose(&path); git_revwalk_free(walk); git_repository_free(repo); @@ -85,7 +87,8 @@ void test_online_shallow__clone_depth_five(void) git_revwalk *walk; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_oid oid; - git_array_oid_t roots = GIT_ARRAY_INIT; + git_oid *roots; + size_t roots_len; size_t num_commits = 0; int error = 0; @@ -98,11 +101,11 @@ void test_online_shallow__clone_depth_five(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); - cl_git_pass(git_repository__shallow_roots(&roots, repo)); - cl_assert_equal_i(3, roots.size); - cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots.ptr[0])); - cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&roots.ptr[1])); - cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ptr[2])); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(3, roots_len); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&roots[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots[2])); git_revwalk_new(&walk, repo); @@ -115,7 +118,7 @@ void test_online_shallow__clone_depth_five(void) cl_assert_equal_i(num_commits, 13); cl_assert_equal_i(error, GIT_ITEROVER); - git_array_clear(roots); + git__free(roots); git_str_dispose(&path); git_revwalk_free(walk); git_repository_free(repo); diff --git a/tests/libgit2/transports/smart/shallowarray.c b/tests/libgit2/transports/smart/shallowarray.c deleted file mode 100644 index 34511c5f641..00000000000 --- a/tests/libgit2/transports/smart/shallowarray.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "clar_libgit2.h" - -#include "git2/oid.h" -#include "git2/transport.h" - -#include "common.h" -#include "transports/smart.h" -#include "oid.h" - -#include - -#define oid_0 "c070ad8c08840c8116da865b2d65593a6bb9cd2a" -#define oid_1 "0966a434eb1a025db6b71485ab63a3bfbea520b6" -#define oid_2 "83834a7afdaa1a1260568567f6ad90020389f664" - -void test_transports_smart_shallowarray__add_and_remove_oid_from_shallowarray(void) -{ - git_oid oid_0_obj, oid_1_obj, oid_2_obj; - git_shallowarray *shallow_roots = git__malloc(sizeof(git_shallowarray)); - git_array_init(shallow_roots->array); - - git_oid__fromstr(&oid_0_obj, oid_0, GIT_OID_SHA1); - git_oid__fromstr(&oid_1_obj, oid_1, GIT_OID_SHA1); - git_oid__fromstr(&oid_2_obj, oid_2, GIT_OID_SHA1); - - git_shallowarray_add(shallow_roots, &oid_0_obj); - git_shallowarray_add(shallow_roots, &oid_1_obj); - git_shallowarray_add(shallow_roots, &oid_2_obj); - - cl_assert_equal_i(3, shallow_roots->array.size); - cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); - cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1])); - cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&shallow_roots->array.ptr[2])); - - git_shallowarray_remove(shallow_roots, &oid_2_obj); - - cl_assert_equal_i(2, shallow_roots->array.size); - cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); - cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1])); - - git_shallowarray_remove(shallow_roots, &oid_1_obj); - - cl_assert_equal_i(1, shallow_roots->array.size); - cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0])); - - git_shallowarray_remove(shallow_roots, &oid_0_obj); - - cl_assert_equal_i(0, shallow_roots->array.size); - - git_array_clear(shallow_roots->array); - git__free(shallow_roots); -} From 437c5f5a0b6ae6068168081ac6422dba44cff31d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 8 May 2023 10:17:11 +0100 Subject: [PATCH 174/816] fetch: remove `unshallow` option The `depth` field is suitable to specify unshallowing; provide an enum to aide in specifying the `unshallow` value. --- include/git2/remote.h | 22 +++++++++++++--------- src/libgit2/fetch.c | 4 +--- tests/libgit2/online/shallow.c | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 8d612701416..e9065b250c1 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -702,6 +702,15 @@ typedef enum { GIT_REMOTE_DOWNLOAD_TAGS_ALL } git_remote_autotag_option_t; +/** Constants for fetch depth (shallowness of fetch). */ +typedef enum { + /** The fetch is "full" (not shallow). This is the default. */ + GIT_FETCH_DEPTH_FULL = 0, + + /** The fetch should "unshallow" and fetch missing data. */ + GIT_FETCH_DEPTH_UNSHALLOW = 2147483647 +} git_fetch_depth_t; + /** * Fetch options structure. * @@ -744,19 +753,14 @@ typedef struct { git_proxy_options proxy_opts; /** - * Depth of the fetch to perform, or 0 for full history. + * Depth of the fetch to perform, or `GIT_FETCH_DEPTH_FULL` + * (or `0`) for full history, or `GIT_FETCH_DEPTH_UNSHALLOW` + * to "unshallow" a shallow repository. * - * The default is 0. + * The default is full (`GIT_FETCH_DEPTH_FULL` or `0`). */ int depth; - /** - * Convert a shallow repository to a full repository. - * - * The default is 0, which means the flag is off. - */ - int unshallow; - /** * Whether to allow off-site redirects. If this is not * specified, the `http.followRedirects` configuration setting diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index b4342521591..5bbef87f4e0 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -174,10 +174,8 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) remote->need_pack = 0; if (opts) { - GIT_ASSERT_ARG(opts->unshallow == 0 || opts->depth == 0); GIT_ASSERT_ARG(opts->depth >= 0); - - remote->nego.depth = opts->unshallow ? INT_MAX : opts->depth; + remote->nego.depth = opts->depth; } if (filter_wants(remote, opts) < 0) diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c index 12ef7748b1a..5c0e6565b03 100644 --- a/tests/libgit2/online/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -143,7 +143,7 @@ void test_online_shallow__unshallow(void) cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); cl_assert_equal_b(true, git_repository_is_shallow(repo)); - fetch_opts.unshallow = 1; + fetch_opts.depth = GIT_FETCH_DEPTH_UNSHALLOW; cl_git_pass(git_remote_lookup(&origin, repo, "origin")); cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL)); From a821455ee430d28d0032b91ba89b414b4b724464 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 11 May 2023 21:43:38 +0100 Subject: [PATCH 175/816] util: add GIT_UNUSED_ARG Add `GIT_UNUSED_ARG` which is an attribute for arguments, for compatibility with dependencies. --- src/util/cc-compat.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/cc-compat.h b/src/util/cc-compat.h index a0971e86c98..ede6e9aa9a1 100644 --- a/src/util/cc-compat.h +++ b/src/util/cc-compat.h @@ -43,8 +43,10 @@ __typeof__(x) _unused __attribute__((unused)); \ _unused = (x); \ } while (0) +# define GIT_UNUSED_ARG __attribute__((unused)) #else # define GIT_UNUSED(x) ((void)(x)) +# define GIT_UNUSED_ARG #endif /* Define the printf format specifier to use for size_t output */ From 027630ddd42e5ab4f4f5a221f38a3fd5bda4e3d4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 11 May 2023 21:44:17 +0100 Subject: [PATCH 176/816] xdiff: update to xdiff from git 2.40.1 --- deps/xdiff/git-xdiff.h | 5 +++- deps/xdiff/xdiffi.c | 37 +++++++++++++++--------------- deps/xdiff/xdiffi.h | 6 ++--- deps/xdiff/xemit.c | 6 ++--- deps/xdiff/xhistogram.c | 25 ++++++-------------- deps/xdiff/xmacros.h | 19 ++++++++++++++- deps/xdiff/xmerge.c | 46 +++++++++++++++++++------------------ deps/xdiff/xpatience.c | 51 +++++++++++++++++------------------------ deps/xdiff/xprepare.c | 43 +++++++++++----------------------- deps/xdiff/xutils.c | 19 ++++++++++++++- deps/xdiff/xutils.h | 3 ++- 11 files changed, 131 insertions(+), 129 deletions(-) diff --git a/deps/xdiff/git-xdiff.h b/deps/xdiff/git-xdiff.h index b75dba8195a..1450ab3dd21 100644 --- a/deps/xdiff/git-xdiff.h +++ b/deps/xdiff/git-xdiff.h @@ -27,11 +27,14 @@ # endif #endif +#define XDL_UNUSED GIT_UNUSED_ARG + #define xdl_malloc(x) git__malloc(x) +#define xdl_calloc(n, sz) git__calloc(n, sz) #define xdl_free(ptr) git__free(ptr) #define xdl_realloc(ptr, x) git__realloc(ptr, x) -#define XDL_BUG(msg) GIT_ASSERT(msg) +#define XDL_BUG(msg) GIT_ASSERT(!msg) #define xdl_regex_t git_regexp #define xdl_regmatch_t git_regmatch diff --git a/deps/xdiff/xdiffi.c b/deps/xdiff/xdiffi.c index af31b7f4b39..ea36143af2c 100644 --- a/deps/xdiff/xdiffi.c +++ b/deps/xdiff/xdiffi.c @@ -315,16 +315,19 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, long *kvd, *kvdf, *kvdb; xdalgoenv_t xenv; diffdata_t dd1, dd2; + int res; - if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF) - return xdl_do_patience_diff(mf1, mf2, xpp, xe); - - if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF) - return xdl_do_histogram_diff(mf1, mf2, xpp, xe); + if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) + return -1; - if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) { + if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF) { + res = xdl_do_patience_diff(xpp, xe); + goto out; + } - return -1; + if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF) { + res = xdl_do_histogram_diff(xpp, xe); + goto out; } /* @@ -334,7 +337,7 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, * One is to store the forward path and one to store the backward path. */ ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3; - if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) { + if (!XDL_ALLOC_ARRAY(kvd, 2 * ndiags + 2)) { xdl_free_env(xe); return -1; @@ -359,17 +362,15 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, dd2.rchg = xe->xdf2.rchg; dd2.rindex = xe->xdf2.rindex; - if (xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec, - kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, &xenv) < 0) { - - xdl_free(kvd); - xdl_free_env(xe); - return -1; - } - + res = xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec, + kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, + &xenv); xdl_free(kvd); + out: + if (res < 0) + xdl_free_env(xe); - return 0; + return res; } @@ -972,7 +973,7 @@ void xdl_free_script(xdchange_t *xscr) { } } -static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, +static int xdl_call_hunk_func(xdfenv_t *xe XDL_UNUSED, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { xdchange_t *xch, *xche; diff --git a/deps/xdiff/xdiffi.h b/deps/xdiff/xdiffi.h index 8f1c7c8b044..126c9d8ff4e 100644 --- a/deps/xdiff/xdiffi.h +++ b/deps/xdiff/xdiffi.h @@ -56,9 +56,7 @@ int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr); void xdl_free_script(xdchange_t *xscr); int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); -int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, - xdfenv_t *env); -int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, - xdfenv_t *env); +int xdl_do_patience_diff(xpparam_t const *xpp, xdfenv_t *env); +int xdl_do_histogram_diff(xpparam_t const *xpp, xdfenv_t *env); #endif /* #if !defined(XDIFFI_H) */ diff --git a/deps/xdiff/xemit.c b/deps/xdiff/xemit.c index 1cbf2b9829e..75f0fe49866 100644 --- a/deps/xdiff/xemit.c +++ b/deps/xdiff/xemit.c @@ -65,7 +65,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) *xscr = xch; } - if (*xscr == NULL) + if (!*xscr) return NULL; lxch = *xscr; @@ -95,7 +95,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) } -static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) +static long def_ff(const char *rec, long len, char *buf, long sz) { if (len > 0 && (isalpha((unsigned char)*rec) || /* identifier? */ @@ -117,7 +117,7 @@ static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri, const char *rec; long len = xdl_get_rec(xdf, ri, &rec); if (!xecfg->find_func) - return def_ff(rec, len, buf, sz, xecfg->find_func_priv); + return def_ff(rec, len, buf, sz); return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv); } diff --git a/deps/xdiff/xhistogram.c b/deps/xdiff/xhistogram.c index 80794748b0d..16a8fe2f3f3 100644 --- a/deps/xdiff/xhistogram.c +++ b/deps/xdiff/xhistogram.c @@ -251,7 +251,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2) { int b_ptr; - int sz, ret = -1; + int ret = -1; struct histindex index; memset(&index, 0, sizeof(index)); @@ -265,23 +265,16 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env, index.rcha.head = NULL; index.table_bits = xdl_hashbits(count1); - sz = index.records_size = 1 << index.table_bits; - sz *= sizeof(struct record *); - if (!(index.records = (struct record **) xdl_malloc(sz))) + index.records_size = 1 << index.table_bits; + if (!XDL_CALLOC_ARRAY(index.records, index.records_size)) goto cleanup; - memset(index.records, 0, sz); - sz = index.line_map_size = count1; - sz *= sizeof(struct record *); - if (!(index.line_map = (struct record **) xdl_malloc(sz))) + index.line_map_size = count1; + if (!XDL_CALLOC_ARRAY(index.line_map, index.line_map_size)) goto cleanup; - memset(index.line_map, 0, sz); - sz = index.line_map_size; - sz *= sizeof(unsigned int); - if (!(index.next_ptrs = (unsigned int *) xdl_malloc(sz))) + if (!XDL_CALLOC_ARRAY(index.next_ptrs, index.line_map_size)) goto cleanup; - memset(index.next_ptrs, 0, sz); /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */ if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0) @@ -369,12 +362,8 @@ static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env, return result; } -int xdl_do_histogram_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env) +int xdl_do_histogram_diff(xpparam_t const *xpp, xdfenv_t *env) { - if (xdl_prepare_env(file1, file2, xpp, env) < 0) - return -1; - return histogram_diff(xpp, env, env->xdf1.dstart + 1, env->xdf1.dend - env->xdf1.dstart + 1, env->xdf2.dstart + 1, env->xdf2.dend - env->xdf2.dstart + 1); diff --git a/deps/xdiff/xmacros.h b/deps/xdiff/xmacros.h index 2809a28ca96..8487bb396fa 100644 --- a/deps/xdiff/xmacros.h +++ b/deps/xdiff/xmacros.h @@ -34,7 +34,6 @@ #define XDL_ADDBITS(v,b) ((v) + ((v) >> (b))) #define XDL_MASKBITS(b) ((1UL << (b)) - 1) #define XDL_HASHLONG(v,b) (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b)) -#define XDL_PTRFREE(p) do { if (p) { xdl_free(p); (p) = NULL; } } while (0) #define XDL_LE32_PUT(p, v) \ do { \ unsigned char *__p = (unsigned char *) (p); \ @@ -50,5 +49,23 @@ do { \ ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \ } while (0) +/* Allocate an array of nr elements, returns NULL on failure */ +#define XDL_ALLOC_ARRAY(p, nr) \ + ((p) = SIZE_MAX / sizeof(*(p)) >= (size_t)(nr) \ + ? xdl_malloc((nr) * sizeof(*(p))) \ + : NULL) + +/* Allocate an array of nr zeroed out elements, returns NULL on failure */ +#define XDL_CALLOC_ARRAY(p, nr) ((p) = xdl_calloc(nr, sizeof(*(p)))) + +/* + * Ensure array p can accommodate at least nr elements, growing the + * array and updating alloc (which is the number of allocated + * elements) as necessary. Frees p and returns -1 on failure, returns + * 0 on success + */ +#define XDL_ALLOC_GROW(p, nr, alloc) \ + (-!((nr) <= (alloc) || \ + ((p) = xdl_alloc_grow_helper((p), (nr), &(alloc), sizeof(*(p)))))) #endif /* #if !defined(XMACROS_H) */ diff --git a/deps/xdiff/xmerge.c b/deps/xdiff/xmerge.c index 433e2d74157..af40c88a5b3 100644 --- a/deps/xdiff/xmerge.c +++ b/deps/xdiff/xmerge.c @@ -88,7 +88,7 @@ static int xdl_cleanup_merge(xdmerge_t *c) if (c->mode == 0) count++; next_c = c->next; - xdl_free(c); + free(c); } return count; } @@ -456,7 +456,7 @@ static void xdl_merge_two_conflicts(xdmerge_t *m) m->chg1 = next_m->i1 + next_m->chg1 - m->i1; m->chg2 = next_m->i2 + next_m->chg2 - m->i2; m->next = next_m->next; - xdl_free(next_m); + free(next_m); } /* @@ -684,42 +684,42 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, xmparam_t const *xmp, mmbuffer_t *result) { - xdchange_t *xscr1, *xscr2; + xdchange_t *xscr1 = NULL, *xscr2 = NULL; xdfenv_t xe1, xe2; - int status; + int status = -1; xpparam_t const *xpp = &xmp->xpp; result->ptr = NULL; result->size = 0; - if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) { + if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) return -1; - } - if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) { - xdl_free_env(&xe1); - return -1; - } + + if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) + goto free_xe1; /* avoid double free of xe2 */ + if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe1.xdf2, &xe1.xdf1, xpp->flags) < 0 || - xdl_build_script(&xe1, &xscr1) < 0) { - xdl_free_env(&xe1); - return -1; - } + xdl_build_script(&xe1, &xscr1) < 0) + goto out; + if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 || - xdl_build_script(&xe2, &xscr2) < 0) { - xdl_free_script(xscr1); - xdl_free_env(&xe1); - xdl_free_env(&xe2); - return -1; - } - status = 0; + xdl_build_script(&xe2, &xscr2) < 0) + goto out; + if (!xscr1) { result->ptr = xdl_malloc(mf2->size); + if (!result->ptr) + goto out; + status = 0; memcpy(result->ptr, mf2->ptr, mf2->size); result->size = mf2->size; } else if (!xscr2) { result->ptr = xdl_malloc(mf1->size); + if (!result->ptr) + goto out; + status = 0; memcpy(result->ptr, mf1->ptr, mf1->size); result->size = mf1->size; } else { @@ -727,11 +727,13 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, &xe2, xscr2, xmp, result); } + out: xdl_free_script(xscr1); xdl_free_script(xscr2); - xdl_free_env(&xe1); xdl_free_env(&xe2); + free_xe1: + xdl_free_env(&xe1); return status; } diff --git a/deps/xdiff/xpatience.c b/deps/xdiff/xpatience.c index c5d48e80aef..a2d8955537f 100644 --- a/deps/xdiff/xpatience.c +++ b/deps/xdiff/xpatience.c @@ -69,7 +69,6 @@ struct hashmap { } *entries, *first, *last; /* were common records found? */ unsigned long has_matches; - mmfile_t *file1, *file2; xdfenv_t *env; xpparam_t const *xpp; }; @@ -139,23 +138,17 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map, * * It is assumed that env has been prepared using xdl_prepare(). */ -static int fill_hashmap(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env, +static int fill_hashmap(xpparam_t const *xpp, xdfenv_t *env, struct hashmap *result, int line1, int count1, int line2, int count2) { - result->file1 = file1; - result->file2 = file2; result->xpp = xpp; result->env = env; /* We know exactly how large we want the hash map */ result->alloc = count1 * 2; - result->entries = (struct entry *) - xdl_malloc(result->alloc * sizeof(struct entry)); - if (!result->entries) + if (!XDL_CALLOC_ARRAY(result->entries, result->alloc)) return -1; - memset(result->entries, 0, result->alloc * sizeof(struct entry)); /* First, fill with entries from the first file */ while (count1--) @@ -198,9 +191,9 @@ static int binary_search(struct entry **sequence, int longest, * item per sequence length: the sequence with the smallest last * element (in terms of line2). */ -static struct entry *find_longest_common_sequence(struct hashmap *map) +static int find_longest_common_sequence(struct hashmap *map, struct entry **res) { - struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *)); + struct entry **sequence; int longest = 0, i; struct entry *entry; @@ -211,6 +204,9 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) */ int anchor_i = -1; + if (!XDL_ALLOC_ARRAY(sequence, map->nr)) + return -1; + for (entry = map->first; entry; entry = entry->next) { if (!entry->line2 || entry->line2 == NON_UNIQUE) continue; @@ -230,8 +226,9 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) /* No common unique lines were found */ if (!longest) { + *res = NULL; xdl_free(sequence); - return NULL; + return 0; } /* Iterate starting at the last element, adjusting the "next" members */ @@ -241,8 +238,9 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) entry->previous->next = entry; entry = entry->previous; } + *res = entry; xdl_free(sequence); - return entry; + return 0; } static int match(struct hashmap *map, int line1, int line2) @@ -252,8 +250,7 @@ static int match(struct hashmap *map, int line1, int line2) return record1->ha == record2->ha; } -static int patience_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env, +static int patience_diff(xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2); static int walk_common_sequence(struct hashmap *map, struct entry *first, @@ -284,8 +281,7 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first, /* Recurse */ if (next1 > line1 || next2 > line2) { - if (patience_diff(map->file1, map->file2, - map->xpp, map->env, + if (patience_diff(map->xpp, map->env, line1, next1 - line1, line2, next2 - line2)) return -1; @@ -324,8 +320,7 @@ static int fall_back_to_classic_diff(struct hashmap *map, * * This function assumes that env was prepared with xdl_prepare_env(). */ -static int patience_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env, +static int patience_diff(xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2) { struct hashmap map; @@ -344,7 +339,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2, } memset(&map, 0, sizeof(map)); - if (fill_hashmap(file1, file2, xpp, env, &map, + if (fill_hashmap(xpp, env, &map, line1, count1, line2, count2)) return -1; @@ -358,25 +353,21 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2, return 0; } - first = find_longest_common_sequence(&map); + result = find_longest_common_sequence(&map, &first); + if (result) + goto out; if (first) result = walk_common_sequence(&map, first, line1, count1, line2, count2); else result = fall_back_to_classic_diff(&map, line1, count1, line2, count2); - + out: xdl_free(map.entries); return result; } -int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env) +int xdl_do_patience_diff(xpparam_t const *xpp, xdfenv_t *env) { - if (xdl_prepare_env(file1, file2, xpp, env) < 0) - return -1; - - /* environment is cleaned up in xdl_diff() */ - return patience_diff(file1, file2, xpp, env, - 1, env->xdf1.nrec, 1, env->xdf2.nrec); + return patience_diff(xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec); } diff --git a/deps/xdiff/xprepare.c b/deps/xdiff/xprepare.c index 4527a4a07c4..c84549f6c50 100644 --- a/deps/xdiff/xprepare.c +++ b/deps/xdiff/xprepare.c @@ -78,15 +78,14 @@ static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) { return -1; } - if (!(cf->rchash = (xdlclass_t **) xdl_malloc(cf->hsize * sizeof(xdlclass_t *)))) { + if (!XDL_CALLOC_ARRAY(cf->rchash, cf->hsize)) { xdl_cha_free(&cf->ncha); return -1; } - memset(cf->rchash, 0, cf->hsize * sizeof(xdlclass_t *)); cf->alloc = size; - if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) { + if (!XDL_ALLOC_ARRAY(cf->rcrecs, cf->alloc)) { xdl_free(cf->rchash); xdl_cha_free(&cf->ncha); @@ -112,7 +111,6 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t long hi; char const *line; xdlclass_t *rcrec; - xdlclass_t **rcrecs; line = rec->ptr; hi = (long) XDL_HASHLONG(rec->ha, cf->hbits); @@ -128,14 +126,8 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t return -1; } rcrec->idx = cf->count++; - if (cf->count > cf->alloc) { - cf->alloc *= 2; - if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) { - + if (XDL_ALLOC_GROW(cf->rcrecs, cf->count, cf->alloc)) return -1; - } - cf->rcrecs = rcrecs; - } cf->rcrecs[rcrec->idx] = rcrec; rcrec->line = line; rcrec->size = rec->size; @@ -164,7 +156,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ unsigned long hav; char const *blk, *cur, *top, *prev; xrecord_t *crec; - xrecord_t **recs, **rrecs; + xrecord_t **recs; xrecord_t **rhash; unsigned long *ha; char *rchg; @@ -178,26 +170,21 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0) goto abort; - if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *)))) + if (!XDL_ALLOC_ARRAY(recs, narec)) goto abort; hbits = xdl_hashbits((unsigned int) narec); hsize = 1 << hbits; - if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *)))) + if (!XDL_CALLOC_ARRAY(rhash, hsize)) goto abort; - memset(rhash, 0, hsize * sizeof(xrecord_t *)); nrec = 0; - if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) { + if ((cur = blk = xdl_mmfile_first(mf, &bsize))) { for (top = blk + bsize; cur < top; ) { prev = cur; hav = xdl_hash_record(&cur, top, xpp->flags); - if (nrec >= narec) { - narec *= 2; - if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *)))) - goto abort; - recs = rrecs; - } + if (XDL_ALLOC_GROW(recs, nrec + 1, narec)) + goto abort; if (!(crec = xdl_cha_alloc(&xdf->rcha))) goto abort; crec->ptr = prev; @@ -209,15 +196,14 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ } } - if (!(rchg = (char *) xdl_malloc((nrec + 2) * sizeof(char)))) + if (!XDL_CALLOC_ARRAY(rchg, nrec + 2)) goto abort; - memset(rchg, 0, (nrec + 2) * sizeof(char)); if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) && (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)) { - if (!(rindex = xdl_malloc((nrec + 1) * sizeof(*rindex)))) + if (!XDL_ALLOC_ARRAY(rindex, nrec + 1)) goto abort; - if (!(ha = xdl_malloc((nrec + 1) * sizeof(*ha)))) + if (!XDL_ALLOC_ARRAY(ha, nrec + 1)) goto abort; } @@ -383,11 +369,8 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xd xdlclass_t *rcrec; char *dis, *dis1, *dis2; - if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) { - + if (!XDL_CALLOC_ARRAY(dis, xdf1->nrec + xdf2->nrec + 2)) return -1; - } - memset(dis, 0, xdf1->nrec + xdf2->nrec + 2); dis1 = dis; dis2 = dis1 + xdf1->nrec + 1; diff --git a/deps/xdiff/xutils.c b/deps/xdiff/xutils.c index cfa6e2220ff..9e36f24875d 100644 --- a/deps/xdiff/xutils.c +++ b/deps/xdiff/xutils.c @@ -122,7 +122,7 @@ long xdl_guess_lines(mmfile_t *mf, long sample) { long nl = 0, size, tsize = 0; char const *data, *cur, *top; - if ((cur = data = xdl_mmfile_first(mf, &size)) != NULL) { + if ((cur = data = xdl_mmfile_first(mf, &size))) { for (top = data + size; nl < sample && cur < top; ) { nl++; if (!(cur = memchr(cur, '\n', top - cur))) @@ -432,3 +432,20 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, return 0; } + +void* xdl_alloc_grow_helper(void *p, long nr, long *alloc, size_t size) +{ + void *tmp = NULL; + size_t n = ((LONG_MAX - 16) / 2 >= *alloc) ? 2 * *alloc + 16 : LONG_MAX; + if (nr > n) + n = nr; + if (SIZE_MAX / size >= n) + tmp = xdl_realloc(p, n * size); + if (tmp) { + *alloc = n; + } else { + xdl_free(p); + *alloc = 0; + } + return tmp; +} diff --git a/deps/xdiff/xutils.h b/deps/xdiff/xutils.h index fba7bae03c7..fd0bba94e8b 100644 --- a/deps/xdiff/xutils.h +++ b/deps/xdiff/xutils.h @@ -42,6 +42,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, int line1, int count1, int line2, int count2); - +/* Do not call this function, use XDL_ALLOC_GROW instead */ +void* xdl_alloc_grow_helper(void* p, long nr, long* alloc, size_t size); #endif /* #if !defined(XUTILS_H) */ From 767a9a733ca64928d395318a9cda47822241b879 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 21:33:45 +0100 Subject: [PATCH 177/816] cmake: simplify QSORT names `QSORT_R` and `QSORT_S` -> `QSORT` --- src/CMakeLists.txt | 8 ++++---- src/util/git2_features.h.in | 8 ++++---- src/util/util.c | 22 ++++++++++++---------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db0fd10c75d..bdf513842c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,25 +69,25 @@ disable_warnings(unused-parameter) # of the comparison function: check_prototype_definition(qsort_r "void (qsort_r)(void *base, size_t nmemb, size_t size, void *context, int (*compar)(void *, const void *, const void *))" - "" "stdlib.h" GIT_QSORT_R_BSD) + "" "stdlib.h" GIT_QSORT_BSD) # GNU or POSIX qsort_r() has the 'context' parameter as the last argument of the # comparison function: check_prototype_definition(qsort_r "void (qsort_r)(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *context)" - "" "stdlib.h" GIT_QSORT_R_GNU) + "" "stdlib.h" GIT_QSORT_GNU) # C11 qsort_s() has the 'context' parameter as the last argument of the # comparison function, and returns an error status: check_prototype_definition(qsort_s "errno_t (qsort_s)(void *base, rsize_t nmemb, rsize_t size, int (*compar)(const void *, const void *, void *), void *context)" - "0" "stdlib.h" GIT_QSORT_S_C11) + "0" "stdlib.h" GIT_QSORT_C11) # MSC qsort_s() has the 'context' parameter as the first argument of the # comparison function, and as the last argument of qsort_s(): check_prototype_definition(qsort_s "void (qsort_s)(void *base, size_t num, size_t width, int (*compare )(void *, const void *, const void *), void *context)" - "" "stdlib.h" GIT_QSORT_S_MSC) + "" "stdlib.h" GIT_QSORT_MSC) # restore CMAKE_C_FLAGS set(CMAKE_C_FLAGS "${SAVED_CMAKE_C_FLAGS}") diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 5f606df8494..18644c3ccfc 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -24,10 +24,10 @@ #cmakedefine GIT_REGEX_PCRE2 #cmakedefine GIT_REGEX_BUILTIN 1 -#cmakedefine GIT_QSORT_R_BSD -#cmakedefine GIT_QSORT_R_GNU -#cmakedefine GIT_QSORT_S_C11 -#cmakedefine GIT_QSORT_S_MSC +#cmakedefine GIT_QSORT_BSD +#cmakedefine GIT_QSORT_GNU +#cmakedefine GIT_QSORT_C11 +#cmakedefine GIT_QSORT_MSC #cmakedefine GIT_SSH 1 #cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1 diff --git a/src/util/util.c b/src/util/util.c index f4eaf5835ab..c8e8303afe1 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -18,7 +18,7 @@ # endif # include -# ifdef GIT_QSORT_S_MSC +# ifdef GIT_QSORT_MSC # include # endif #endif @@ -673,7 +673,7 @@ size_t git__unescape(char *str) return (pos - str); } -#if defined(GIT_QSORT_S_MSC) || defined(GIT_QSORT_R_BSD) +#if defined(GIT_QSORT_MSC) || defined(GIT_QSORT_BSD) typedef struct { git__sort_r_cmp cmp; void *payload; @@ -688,10 +688,11 @@ static int GIT_LIBGIT2_CALL git__qsort_r_glue_cmp( #endif -#if !defined(GIT_QSORT_R_BSD) && \ - !defined(GIT_QSORT_R_GNU) && \ - !defined(GIT_QSORT_S_C11) && \ - !defined(GIT_QSORT_S_MSC) +#if !defined(GIT_QSORT_BSD) && \ + !defined(GIT_QSORT_GNU) && \ + !defined(GIT_QSORT_C11) && \ + !defined(GIT_QSORT_MSC) + static void swap(uint8_t *a, uint8_t *b, size_t elsize) { char tmp[256]; @@ -717,19 +718,20 @@ static void insertsort( for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize) swap(j, j - elsize, elsize); } + #endif void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { -#if defined(GIT_QSORT_R_GNU) +#if defined(GIT_QSORT_GNU) qsort_r(els, nel, elsize, cmp, payload); -#elif defined(GIT_QSORT_S_C11) +#elif defined(GIT_QSORT_C11) qsort_s(els, nel, elsize, cmp, payload); -#elif defined(GIT_QSORT_R_BSD) +#elif defined(GIT_QSORT_BSD) git__qsort_r_glue glue = { cmp, payload }; qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp); -#elif defined(GIT_QSORT_S_MSC) +#elif defined(GIT_QSORT_MSC) git__qsort_r_glue glue = { cmp, payload }; qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue); #else From 333573857960fa7260f01f38a2003bafa2313a87 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 21:49:29 +0100 Subject: [PATCH 178/816] cmake: refactor `check_prototype_definition` Introduce `check_prototype_definition_safe` that is safe for `Werror` usage. --- CMakeLists.txt | 2 +- cmake/CheckPrototypeDefinitionSafe.cmake | 16 ++++++++++++++++ src/CMakeLists.txt | 18 ++++-------------- 3 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 cmake/CheckPrototypeDefinitionSafe.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 30527b9280b..cfb5a7d6f4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,7 +94,7 @@ include(CheckLibraryExists) include(CheckFunctionExists) include(CheckSymbolExists) include(CheckStructHasMember) -include(CheckPrototypeDefinition) +include(CheckPrototypeDefinitionSafe) include(AddCFlagIfSupported) include(FindPkgLibraries) include(FindThreads) diff --git a/cmake/CheckPrototypeDefinitionSafe.cmake b/cmake/CheckPrototypeDefinitionSafe.cmake new file mode 100644 index 00000000000..f82603d3d72 --- /dev/null +++ b/cmake/CheckPrototypeDefinitionSafe.cmake @@ -0,0 +1,16 @@ +include(CheckPrototypeDefinition) + +function(check_prototype_definition_safe function prototype return header variable) + # temporarily save CMAKE_C_FLAGS and disable warnings about unused + # unused functions and parameters, otherwise they will always fail + # if ENABLE_WERROR is on + set(SAVED_CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + + disable_warnings(unused-function) + disable_warnings(unused-parameter) + + check_prototype_definition("${function}" "${prototype}" "${return}" "${header}" "${variable}") + + # restore CMAKE_C_FLAGS + set(CMAKE_C_FLAGS "${SAVED_CMAKE_C_FLAGS}") +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bdf513842c8..88d616cec1f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,40 +58,30 @@ add_feature_info(futimens GIT_USE_FUTIMENS "futimens support") # qsort -# for these tests, temporarily save CMAKE_C_FLAGS and disable warnings about -# unused functions and parameters, otherwise they will always fail if -# ENABLE_WERROR is on -set(SAVED_CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") -disable_warnings(unused-function) -disable_warnings(unused-parameter) - # old-style FreeBSD qsort_r() has the 'context' parameter as the first argument # of the comparison function: -check_prototype_definition(qsort_r +check_prototype_definition_safe(qsort_r "void (qsort_r)(void *base, size_t nmemb, size_t size, void *context, int (*compar)(void *, const void *, const void *))" "" "stdlib.h" GIT_QSORT_BSD) # GNU or POSIX qsort_r() has the 'context' parameter as the last argument of the # comparison function: -check_prototype_definition(qsort_r +check_prototype_definition_safe(qsort_r "void (qsort_r)(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *context)" "" "stdlib.h" GIT_QSORT_GNU) # C11 qsort_s() has the 'context' parameter as the last argument of the # comparison function, and returns an error status: -check_prototype_definition(qsort_s +check_prototype_definition_safe(qsort_s "errno_t (qsort_s)(void *base, rsize_t nmemb, rsize_t size, int (*compar)(const void *, const void *, void *), void *context)" "0" "stdlib.h" GIT_QSORT_C11) # MSC qsort_s() has the 'context' parameter as the first argument of the # comparison function, and as the last argument of qsort_s(): -check_prototype_definition(qsort_s +check_prototype_definition_safe(qsort_s "void (qsort_s)(void *base, size_t num, size_t width, int (*compare )(void *, const void *, const void *), void *context)" "" "stdlib.h" GIT_QSORT_MSC) -# restore CMAKE_C_FLAGS -set(CMAKE_C_FLAGS "${SAVED_CMAKE_C_FLAGS}") - # random / entropy data check_function_exists(getentropy GIT_RAND_GETENTROPY) From 4be63a68667d3c75a3da36b3bc8045459a360906 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 8 Dec 2020 18:01:03 +0000 Subject: [PATCH 179/816] errors: drop unneccessary g_git prefix --- src/libgit2/errors.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libgit2/errors.c b/src/libgit2/errors.c index 3614b9ce5f5..1b94a5cf403 100644 --- a/src/libgit2/errors.c +++ b/src/libgit2/errors.c @@ -16,12 +16,12 @@ * New error handling ********************************************/ -static git_error g_git_oom_error = { +static git_error oom_error = { "Out of memory", GIT_ERROR_NOMEMORY }; -static git_error g_git_uninitialized_error = { +static git_error uninitialized_error = { "libgit2 has not been initialized; you must call git_libgit2_init", GIT_ERROR_INVALID }; @@ -52,7 +52,7 @@ static void set_error(int error_class, char *string) void git_error_set_oom(void) { - GIT_THREADSTATE->last_error = &g_git_oom_error; + GIT_THREADSTATE->last_error = &oom_error; } void git_error_set(int error_class, const char *fmt, ...) @@ -134,7 +134,7 @@ const git_error *git_error_last(void) { /* If the library is not initialized, return a static error. */ if (!git_libgit2_init_count()) - return &g_git_uninitialized_error; + return &uninitialized_error; return GIT_THREADSTATE->last_error; } @@ -150,13 +150,13 @@ int git_error_state_capture(git_error_state *state, int error_code) return 0; state->error_code = error_code; - state->oom = (error == &g_git_oom_error); + state->oom = (error == &oom_error); if (error) { state->error_msg.klass = error->klass; if (state->oom) - state->error_msg.message = g_git_oom_error.message; + state->error_msg.message = oom_error.message; else state->error_msg.message = git_str_detach(error_buf); } From ce488be46e4cd2aeeb69c39a062fae1ba9a302f6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 8 Dec 2020 19:28:01 +0000 Subject: [PATCH 180/816] errors: don't rely on tls data working Thread-local storage data may fail to initialize; in this case, do not try to set the error message into it. When the thread state has not been initialized, return a hardcoded message to that affect. --- src/libgit2/errors.c | 81 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/src/libgit2/errors.c b/src/libgit2/errors.c index 1b94a5cf403..460dfa00f78 100644 --- a/src/libgit2/errors.c +++ b/src/libgit2/errors.c @@ -26,22 +26,41 @@ static git_error uninitialized_error = { GIT_ERROR_INVALID }; +static git_error tlsdata_error = { + "thread-local data initialization failure", + GIT_ERROR +}; + static void set_error_from_buffer(int error_class) { - git_error *error = &GIT_THREADSTATE->error_t; - git_str *buf = &GIT_THREADSTATE->error_buf; + git_threadstate *threadstate = GIT_THREADSTATE; + git_error *error; + git_str *buf; + + if (!threadstate) + return; + + error = &threadstate->error_t; + buf = &threadstate->error_buf; error->message = buf->ptr; error->klass = error_class; - GIT_THREADSTATE->last_error = error; + threadstate->last_error = error; } static void set_error(int error_class, char *string) { - git_str *buf = &GIT_THREADSTATE->error_buf; + git_threadstate *threadstate = GIT_THREADSTATE; + git_str *buf; + + if (!threadstate) + return; + + buf = &threadstate->error_buf; git_str_clear(buf); + if (string) { git_str_puts(buf, string); git__free(string); @@ -52,7 +71,12 @@ static void set_error(int error_class, char *string) void git_error_set_oom(void) { - GIT_THREADSTATE->last_error = &oom_error; + git_threadstate *threadstate = GIT_THREADSTATE; + + if (!threadstate) + return; + + threadstate->last_error = &oom_error; } void git_error_set(int error_class, const char *fmt, ...) @@ -69,10 +93,18 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) #ifdef GIT_WIN32 DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0; #endif + + git_threadstate *threadstate = GIT_THREADSTATE; int error_code = (error_class == GIT_ERROR_OS) ? errno : 0; - git_str *buf = &GIT_THREADSTATE->error_buf; + git_str *buf; + + if (!threadstate) + return; + + buf = &threadstate->error_buf; git_str_clear(buf); + if (fmt) { git_str_vprintf(buf, fmt, ap); if (error_class == GIT_ERROR_OS) @@ -81,7 +113,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) if (error_class == GIT_ERROR_OS) { #ifdef GIT_WIN32 - char * win32_error = git_win32_get_error_message(win32_error_code); + char *win32_error = git_win32_get_error_message(win32_error_code); if (win32_error) { git_str_puts(buf, win32_error); git__free(win32_error); @@ -103,10 +135,16 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) int git_error_set_str(int error_class, const char *string) { - git_str *buf = &GIT_THREADSTATE->error_buf; + git_threadstate *threadstate = GIT_THREADSTATE; + git_str *buf; GIT_ASSERT_ARG(string); + if (!threadstate) + return -1; + + buf = &threadstate->error_buf; + git_str_clear(buf); git_str_puts(buf, string); @@ -119,9 +157,14 @@ int git_error_set_str(int error_class, const char *string) void git_error_clear(void) { - if (GIT_THREADSTATE->last_error != NULL) { + git_threadstate *threadstate = GIT_THREADSTATE; + + if (!threadstate) + return; + + if (threadstate->last_error != NULL) { set_error(0, NULL); - GIT_THREADSTATE->last_error = NULL; + threadstate->last_error = NULL; } errno = 0; @@ -132,17 +175,29 @@ void git_error_clear(void) const git_error *git_error_last(void) { + git_threadstate *threadstate; + /* If the library is not initialized, return a static error. */ if (!git_libgit2_init_count()) return &uninitialized_error; - return GIT_THREADSTATE->last_error; + if ((threadstate = GIT_THREADSTATE) == NULL) + return &tlsdata_error; + + return threadstate->last_error; } int git_error_state_capture(git_error_state *state, int error_code) { - git_error *error = GIT_THREADSTATE->last_error; - git_str *error_buf = &GIT_THREADSTATE->error_buf; + git_threadstate *threadstate = GIT_THREADSTATE; + git_error *error; + git_str *error_buf; + + if (!threadstate) + return -1; + + error = threadstate->last_error; + error_buf = &threadstate->error_buf; memset(state, 0, sizeof(git_error_state)); From 4f76ef568d74c63031eb42fc10bf08b5641e5f0b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 8 Dec 2020 19:28:44 +0000 Subject: [PATCH 181/816] oid: don't assume thread local state was initialized git_oid_tostr_s could fail if thread-local state initialization fails. In that case, it will now return `NULL`. Callers should check for `NULL` and propagate the failure. --- include/git2/oid.h | 2 +- src/libgit2/indexer.c | 8 +++++++- src/libgit2/odb.c | 13 +++++++++---- src/libgit2/oid.c | 8 +++++++- src/libgit2/repository.c | 27 +++++++++++++++++++++------ 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/include/git2/oid.h b/include/git2/oid.h index 399b7b9071b..35b43ef183a 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -225,7 +225,7 @@ GIT_EXTERN(int) git_oid_pathfmt(char *out, const git_oid *id); * concurrent calls of the function. * * @param oid The oid structure to format - * @return the c-string + * @return the c-string or NULL on failure */ GIT_EXTERN(char *) git_oid_tostr_s(const git_oid *oid); diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index 7357a4aa56f..e559a194235 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -519,7 +519,13 @@ static int store_object(git_indexer *idx) pentry->offset = entry_start; if (git_oidmap_exists(idx->pack->idx_cache, &pentry->id)) { - git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", git_oid_tostr_s(&pentry->id)); + const char *idstr = git_oid_tostr_s(&pentry->id); + + if (!idstr) + git_error_set(GIT_ERROR_INDEXER, "failed to parse object id"); + else + git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", idstr); + git__free(pentry); goto on_error; } diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 68872e1a197..fec1e45b9d4 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -1494,11 +1494,16 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, if (found && git_oid__cmp(&full_oid, &found_full_oid)) { git_str buf = GIT_STR_INIT; + const char *idstr; - git_str_printf(&buf, "multiple matches for prefix: %s", - git_oid_tostr_s(&full_oid)); - git_str_printf(&buf, " %s", - git_oid_tostr_s(&found_full_oid)); + if ((idstr = git_oid_tostr_s(&full_oid)) == NULL) { + git_str_puts(&buf, "failed to parse object id"); + } else { + git_str_printf(&buf, "multiple matches for prefix: %s", idstr); + + if ((idstr = git_oid_tostr_s(&found_full_oid)) != NULL) + git_str_printf(&buf, " %s", idstr); + } error = git_odb__error_ambiguous(buf.ptr); git_str_dispose(&buf); diff --git a/src/libgit2/oid.c b/src/libgit2/oid.c index 6cc21641d70..ab758fff4cf 100644 --- a/src/libgit2/oid.c +++ b/src/libgit2/oid.c @@ -155,7 +155,13 @@ int git_oid_pathfmt(char *str, const git_oid *oid) char *git_oid_tostr_s(const git_oid *oid) { - char *str = GIT_THREADSTATE->oid_fmt; + git_threadstate *threadstate = GIT_THREADSTATE; + char *str; + + if (!threadstate) + return NULL; + + str = threadstate->oid_fmt; git_oid_nfmt(str, git_oid_hexsize(git_oid_type(oid)) + 1, oid); return str; } diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index d2fe1e6bbcc..97f776c4a34 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3422,12 +3422,18 @@ int git_repository_hashfile( static int checkout_message(git_str *out, git_reference *old, const char *new) { + const char *idstr; + git_str_puts(out, "checkout: moving from "); - if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC) + if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC) { git_str_puts(out, git_reference__shorthand(git_reference_symbolic_target(old))); - else - git_str_puts(out, git_oid_tostr_s(git_reference_target(old))); + } else { + if ((idstr = git_oid_tostr_s(git_reference_target(old))) == NULL) + return -1; + + git_str_puts(out, idstr); + } git_str_puts(out, " to "); @@ -3463,8 +3469,11 @@ static int detach(git_repository *repo, const git_oid *id, const char *new) if ((error = git_object_peel(&peeled, object, GIT_OBJECT_COMMIT)) < 0) goto cleanup; - if (new == NULL) - new = git_oid_tostr_s(git_object_id(peeled)); + if (new == NULL && + (new = git_oid_tostr_s(git_object_id(peeled))) == NULL) { + error = -1; + goto cleanup; + } if ((error = checkout_message(&log_message, current, new)) < 0) goto cleanup; @@ -3552,6 +3561,7 @@ int git_repository_detach_head(git_repository *repo) git_reference *old_head = NULL, *new_head = NULL, *current = NULL; git_object *object = NULL; git_str log_message = GIT_STR_INIT; + const char *idstr; int error; GIT_ASSERT_ARG(repo); @@ -3565,7 +3575,12 @@ int git_repository_detach_head(git_repository *repo) if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJECT_COMMIT)) < 0) goto cleanup; - if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0) + if ((idstr = git_oid_tostr_s(git_object_id(object))) == NULL) { + error = -1; + goto cleanup; + } + + if ((error = checkout_message(&log_message, current, idstr)) < 0) goto cleanup; error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), From ebf2991f06d8831ed23524a068210b8103b5f604 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 8 Dec 2020 19:46:25 +0000 Subject: [PATCH 182/816] threadstate: don't use an unnecessary macro Now that we've reduced the usage of GIT_THREADSTATE, remove it entirely in favor of git_threadstate_get(). --- src/libgit2/errors.c | 16 ++++++++-------- src/libgit2/oid.c | 2 +- src/libgit2/threadstate.h | 2 -- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/libgit2/errors.c b/src/libgit2/errors.c index 460dfa00f78..2e58948d2e4 100644 --- a/src/libgit2/errors.c +++ b/src/libgit2/errors.c @@ -33,7 +33,7 @@ static git_error tlsdata_error = { static void set_error_from_buffer(int error_class) { - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); git_error *error; git_str *buf; @@ -51,7 +51,7 @@ static void set_error_from_buffer(int error_class) static void set_error(int error_class, char *string) { - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); git_str *buf; if (!threadstate) @@ -71,7 +71,7 @@ static void set_error(int error_class, char *string) void git_error_set_oom(void) { - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); if (!threadstate) return; @@ -94,7 +94,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0; #endif - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); int error_code = (error_class == GIT_ERROR_OS) ? errno : 0; git_str *buf; @@ -135,7 +135,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) int git_error_set_str(int error_class, const char *string) { - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); git_str *buf; GIT_ASSERT_ARG(string); @@ -157,7 +157,7 @@ int git_error_set_str(int error_class, const char *string) void git_error_clear(void) { - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); if (!threadstate) return; @@ -181,7 +181,7 @@ const git_error *git_error_last(void) if (!git_libgit2_init_count()) return &uninitialized_error; - if ((threadstate = GIT_THREADSTATE) == NULL) + if ((threadstate = git_threadstate_get()) == NULL) return &tlsdata_error; return threadstate->last_error; @@ -189,7 +189,7 @@ const git_error *git_error_last(void) int git_error_state_capture(git_error_state *state, int error_code) { - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); git_error *error; git_str *error_buf; diff --git a/src/libgit2/oid.c b/src/libgit2/oid.c index ab758fff4cf..631a566ebaa 100644 --- a/src/libgit2/oid.c +++ b/src/libgit2/oid.c @@ -155,7 +155,7 @@ int git_oid_pathfmt(char *str, const git_oid *oid) char *git_oid_tostr_s(const git_oid *oid) { - git_threadstate *threadstate = GIT_THREADSTATE; + git_threadstate *threadstate = git_threadstate_get(); char *str; if (!threadstate) diff --git a/src/libgit2/threadstate.h b/src/libgit2/threadstate.h index 65edec71723..6ef04192ca9 100644 --- a/src/libgit2/threadstate.h +++ b/src/libgit2/threadstate.h @@ -19,6 +19,4 @@ typedef struct { extern int git_threadstate_global_init(void); extern git_threadstate *git_threadstate_get(void); -#define GIT_THREADSTATE (git_threadstate_get()) - #endif From 6c0d5b11c05254d91a2d0025d556251404f8f05f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:19 +0100 Subject: [PATCH 183/816] util: make monotonic time fn return ms `git__timer` is now `git_time_monotonic`, and returns milliseconds since an arbitrary epoch. Using a floating point to store the number of seconds elapsed was clever, as it better supports the wide range of precision from the different monotonic clocks of different systems. But we're a version control system, not a real-time clock. Milliseconds is a good enough precision for our work _and_ it's the units that system calls like `poll` take and that our users interact with. Make `git_time_monotonic` return the monotonically increasing number of milliseconds "ticked" since some arbitrary epoch. --- src/cli/progress.c | 17 ++++++----- src/cli/progress.h | 8 ++--- src/libgit2/pack-objects.c | 12 ++++---- src/libgit2/pack-objects.h | 4 ++- src/libgit2/transports/smart_protocol.c | 8 ++--- src/util/rand.c | 10 ++++--- src/util/util.h | 40 +++++++++++++++---------- tests/clar/clar_libgit2_timer.c | 8 ++--- tests/clar/clar_libgit2_timer.h | 10 +++---- tests/clar/clar_libgit2_trace.c | 2 +- 10 files changed, 66 insertions(+), 53 deletions(-) diff --git a/src/cli/progress.c b/src/cli/progress.c index ba52655e75e..ddfbafb73a4 100644 --- a/src/cli/progress.c +++ b/src/cli/progress.c @@ -15,10 +15,10 @@ /* * Show updates to the percentage and number of objects received * separately from the throughput to give an accurate progress while - * avoiding too much noise on the screen. + * avoiding too much noise on the screen. (In milliseconds.) */ -#define PROGRESS_UPDATE_TIME 0.10 -#define THROUGHPUT_UPDATE_TIME 1.00 +#define PROGRESS_UPDATE_TIME 60 +#define THROUGHPUT_UPDATE_TIME 500 #define is_nl(c) ((c) == '\r' || (c) == '\n') @@ -54,7 +54,7 @@ static int progress_write(cli_progress *progress, bool force, git_str *line) bool has_nl; size_t no_nl = no_nl_len(line->ptr, line->size); size_t nl = nl_len(&has_nl, line->ptr + no_nl, line->size - no_nl); - double now = git__timer(); + uint64_t now = git_time_monotonic(); size_t i; /* Avoid spamming the console with progress updates */ @@ -191,20 +191,21 @@ static int fetch_receiving( { char *recv_units[] = { "B", "KiB", "MiB", "GiB", "TiB", NULL }; char *rate_units[] = { "B/s", "KiB/s", "MiB/s", "GiB/s", "TiB/s", NULL }; + uint64_t now, elapsed; - double now, recv_len, rate, elapsed; + double recv_len, rate; size_t recv_unit_idx = 0, rate_unit_idx = 0; bool done = (stats->received_objects == stats->total_objects); if (!progress->action_start) - progress->action_start = git__timer(); + progress->action_start = git_time_monotonic(); if (done && progress->action_finish) now = progress->action_finish; else if (done) - progress->action_finish = now = git__timer(); + progress->action_finish = now = git_time_monotonic(); else - now = git__timer(); + now = git_time_monotonic(); if (progress->throughput_update && now - progress->throughput_update < THROUGHPUT_UPDATE_TIME) { diff --git a/src/cli/progress.h b/src/cli/progress.h index 7a445ec2966..886fef89d03 100644 --- a/src/cli/progress.h +++ b/src/cli/progress.h @@ -30,11 +30,11 @@ typedef struct { cli_progress_t action; /* Actions may time themselves (eg fetch) but are not required to */ - double action_start; - double action_finish; + uint64_t action_start; + uint64_t action_finish; /* Last console update, avoid too frequent updates. */ - double last_update; + uint64_t last_update; /* Accumulators for partial output and deferred updates. */ git_str sideband; @@ -42,7 +42,7 @@ typedef struct { git_str deferred; /* Last update about throughput */ - double throughput_update; + uint64_t throughput_update; double throughput_bytes; } cli_progress; diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index d6fd603268e..fc8efc65f5e 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -255,10 +255,10 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, pb->done = false; if (pb->progress_cb) { - double current_time = git__timer(); - double elapsed = current_time - pb->last_progress_report_time; + uint64_t current_time = git_time_monotonic(); + uint64_t elapsed = current_time - pb->last_progress_report_time; - if (elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { + if (elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { pb->last_progress_report_time = current_time; ret = pb->progress_cb( @@ -934,10 +934,10 @@ static int report_delta_progress( int ret; if (pb->progress_cb) { - double current_time = git__timer(); - double elapsed = current_time - pb->last_progress_report_time; + uint64_t current_time = git_time_monotonic(); + uint64_t elapsed = current_time - pb->last_progress_report_time; - if (force || elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { + if (force || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { pb->last_progress_report_time = current_time; ret = pb->progress_cb( diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h index c6bc52fdc5e..0ceebc23cab 100644 --- a/src/libgit2/pack-objects.h +++ b/src/libgit2/pack-objects.h @@ -96,7 +96,9 @@ struct git_packbuilder { git_packbuilder_progress progress_cb; void *progress_cb_payload; - double last_progress_report_time; /* the time progress was last reported */ + + /* the time progress was last reported, in millisecond ticks */ + uint64_t last_progress_report_time; bool done; }; diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 488ef07c089..f7a56782930 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -1114,7 +1114,7 @@ struct push_packbuilder_payload git_push_transfer_progress_cb cb; void *cb_payload; size_t last_bytes; - double last_progress_report_time; + uint64_t last_progress_report_time; }; static int stream_thunk(void *buf, size_t size, void *data) @@ -1126,11 +1126,11 @@ static int stream_thunk(void *buf, size_t size, void *data) return error; if (payload->cb) { - double current_time = git__timer(); - double elapsed = current_time - payload->last_progress_report_time; + uint64_t current_time = git_time_monotonic(); + uint64_t elapsed = current_time - payload->last_progress_report_time; payload->last_bytes += size; - if (elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { + if (elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { payload->last_progress_report_time = current_time; error = payload->cb(payload->pb->nr_written, payload->pb->nr_objects, payload->last_bytes, payload->cb_payload); } diff --git a/src/util/rand.c b/src/util/rand.c index 940faf94796..2ed0605738b 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -32,7 +32,6 @@ GIT_INLINE(int) getseed(uint64_t *seed) HCRYPTPROV provider; SYSTEMTIME systemtime; FILETIME filetime, idletime, kerneltime, usertime; - bits convert; if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { @@ -67,7 +66,7 @@ GIT_INLINE(int) getseed(uint64_t *seed) *seed ^= ((uint64_t)GetCurrentProcessId() << 32); *seed ^= ((uint64_t)GetCurrentThreadId() << 48); - convert.f = git__timer(); *seed ^= (convert.d); + *seed ^= git_time_monotonic(); /* Mix in the addresses of some functions and variables */ *seed ^= (((uint64_t)((uintptr_t)seed) << 32)); @@ -82,9 +81,12 @@ GIT_INLINE(int) getseed(uint64_t *seed) { struct timeval tv; double loadavg[3]; - bits convert; int fd; +# if defined(GIT_RAND_GETLOADAVG) + bits convert; +# endif + # if defined(GIT_RAND_GETENTROPY) GIT_UNUSED((fd = 0)); @@ -131,7 +133,7 @@ GIT_INLINE(int) getseed(uint64_t *seed) GIT_UNUSED(loadavg[0]); # endif - convert.f = git__timer(); *seed ^= (convert.d); + *seed ^= git_time_monotonic(); /* Mix in the addresses of some variables */ *seed ^= ((uint64_t)((size_t)((void *)seed)) << 32); diff --git a/src/util/util.h b/src/util/util.h index 63d6080f730..7f178b169fe 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -319,59 +319,67 @@ GIT_INLINE(void) git__memzero(void *data, size_t size) #ifdef GIT_WIN32 -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { /* GetTickCount64 returns the number of milliseconds that have * elapsed since the system was started. */ - return (double) GetTickCount64() / (double) 1000; + return GetTickCount64(); } #elif __APPLE__ #include +#include -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { - uint64_t time = mach_absolute_time(); - static double scaling_factor = 0; + static double scaling_factor = 0; + + if (scaling_factor == 0) { + mach_timebase_info_data_t info; - if (scaling_factor == 0) { - mach_timebase_info_data_t info; - (void)mach_timebase_info(&info); - scaling_factor = (double)info.numer / (double)info.denom; - } + scaling_factor = mach_timebase_info(&info) == KERN_SUCCESS ? + ((double)info.numer / (double)info.denom) / 1.0E6 : + -1; + } else if (scaling_factor < 0) { + struct timeval tv; + + /* mach_timebase_info failed; fall back to gettimeofday */ + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + } - return (double)time * scaling_factor / 1.0E9; + return (uint64_t)(mach_absolute_time() * scaling_factor); } #elif defined(__amigaos4__) #include -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { struct TimeVal tv; ITimer->GetUpTime(&tv); - return (double)tv.Seconds + (double)tv.Microseconds / 1.0E6; + return (tv.Seconds * 1000) + (tv.Microseconds / 1000); } #else #include -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { struct timeval tv; #ifdef CLOCK_MONOTONIC struct timespec tp; if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) - return (double) tp.tv_sec + (double) tp.tv_nsec / 1.0E9; + return (tp.tv_sec * 1000) + (tp.tv_nsec / 1.0E6); #endif /* Fall back to using gettimeofday */ gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec / 1.0E6; + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); } #endif diff --git a/tests/clar/clar_libgit2_timer.c b/tests/clar/clar_libgit2_timer.c index 2330f9351d1..6c75413be7e 100644 --- a/tests/clar/clar_libgit2_timer.c +++ b/tests/clar/clar_libgit2_timer.c @@ -8,23 +8,23 @@ void cl_perf_timer__init(cl_perf_timer *t) void cl_perf_timer__start(cl_perf_timer *t) { - t->time_started = git__timer(); + t->time_started = git_time_monotonic(); } void cl_perf_timer__stop(cl_perf_timer *t) { - double time_now = git__timer(); + uint64_t time_now = git_time_monotonic(); t->last = time_now - t->time_started; t->sum += t->last; } -double cl_perf_timer__last(const cl_perf_timer *t) +uint64_t cl_perf_timer__last(const cl_perf_timer *t) { return t->last; } -double cl_perf_timer__sum(const cl_perf_timer *t) +uint64_t cl_perf_timer__sum(const cl_perf_timer *t) { return t->sum; } diff --git a/tests/clar/clar_libgit2_timer.h b/tests/clar/clar_libgit2_timer.h index 7571a52e997..88706727884 100644 --- a/tests/clar/clar_libgit2_timer.h +++ b/tests/clar/clar_libgit2_timer.h @@ -4,13 +4,13 @@ struct cl_perf_timer { /* cumulative running time across all start..stop intervals */ - double sum; + uint64_t sum; /* value of last start..stop interval */ - double last; + uint64_t last; /* clock value at start */ - double time_started; + uint64_t time_started; }; #define CL_PERF_TIMER_INIT {0} @@ -24,12 +24,12 @@ void cl_perf_timer__stop(cl_perf_timer *t); /** * return value of last start..stop interval in seconds. */ -double cl_perf_timer__last(const cl_perf_timer *t); +uint64_t cl_perf_timer__last(const cl_perf_timer *t); /** * return cumulative running time across all start..stop * intervals in seconds. */ -double cl_perf_timer__sum(const cl_perf_timer *t); +uint64_t cl_perf_timer__sum(const cl_perf_timer *t); #endif /* __CLAR_LIBGIT2_TIMER__ */ diff --git a/tests/clar/clar_libgit2_trace.c b/tests/clar/clar_libgit2_trace.c index ebb0f41dda7..814a5fa9ee7 100644 --- a/tests/clar/clar_libgit2_trace.c +++ b/tests/clar/clar_libgit2_trace.c @@ -197,7 +197,7 @@ static void _cl_trace_cb__event_handler( case CL_TRACE__TEST__END: cl_perf_timer__stop(&s_timer_test); - git_trace(GIT_TRACE_TRACE, "%s::%s: End Test (%.3f %.3f)", suite_name, test_name, + git_trace(GIT_TRACE_TRACE, "%s::%s: End Test (%" PRIuZ " %" PRIuZ ")", suite_name, test_name, cl_perf_timer__last(&s_timer_run), cl_perf_timer__last(&s_timer_test)); break; From dbe343b6e3e957b5cffbd04832c6e7364b496ae7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:28 +0100 Subject: [PATCH 184/816] stransport: store error information We lose some error information from the read / write callbacks to stransport. Store our own error value in the object so that we can ensure that we rely upon it. --- src/libgit2/streams/stransport.c | 39 +++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 3f31d2541c7..74ee0d1eeb0 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -44,6 +44,7 @@ typedef struct { git_stream parent; git_stream *io; int owned; + int error; SSLContextRef ctx; CFDataRef der_data; git_cert_x509 cert_info; @@ -61,7 +62,10 @@ static int stransport_connect(git_stream *stream) return error; ret = SSLHandshake(st->ctx); - if (ret != errSSLServerAuthCompleted) { + + if (ret != errSSLServerAuthCompleted && st->error != 0) + return -1; + else if (ret != errSSLServerAuthCompleted) { git_error_set(GIT_ERROR_SSL, "unexpected return value from ssl handshake %d", (int)ret); return -1; } @@ -147,10 +151,18 @@ static int stransport_set_proxy( */ static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len) { - git_stream *io = (git_stream *) conn; + stransport_stream *st = (stransport_stream *)conn; + git_stream *io = st->io; + OSStatus ret; + + st->error = 0; + + ret = git_stream__write_full(io, data, *len, 0); - if (git_stream__write_full(io, data, *len, 0) < 0) - return -36; /* "ioErr" from MacErrors.h which is not available on iOS */ + if (ret < 0) { + st->error = ret; + return -36; /* ioErr */ + } return noErr; } @@ -182,18 +194,22 @@ static ssize_t stransport_write(git_stream *stream, const char *data, size_t len */ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) { - git_stream *io = (git_stream *) conn; + stransport_stream *st = (stransport_stream *)conn; + git_stream *io = st->io; OSStatus error = noErr; size_t off = 0; ssize_t ret; + st->error = 0; + do { ret = git_stream_read(io, data + off, *len - off); + if (ret < 0) { - error = -36; /* "ioErr" from MacErrors.h which is not available on iOS */ + st->error = ret; + error = -36; /* ioErr */ break; - } - if (ret == 0) { + } else if (ret == 0) { error = errSSLClosedGraceful; break; } @@ -207,12 +223,13 @@ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) static ssize_t stransport_read(git_stream *stream, void *data, size_t len) { - stransport_stream *st = (stransport_stream *) stream; + stransport_stream *st = (stransport_stream *)stream; size_t processed; OSStatus ret; - if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr) + if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr) { return stransport_error(ret); + } return processed; } @@ -269,7 +286,7 @@ static int stransport_wrap( } if ((ret = SSLSetIOFuncs(st->ctx, read_cb, write_cb)) != noErr || - (ret = SSLSetConnection(st->ctx, st->io)) != noErr || + (ret = SSLSetConnection(st->ctx, st)) != noErr || (ret = SSLSetSessionOption(st->ctx, kSSLSessionOptionBreakOnServerAuth, true)) != noErr || (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr || (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr || From 6e4bbf222d8c4babaff90aef40615546c8bc9cde Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:30 +0100 Subject: [PATCH 185/816] net: move rfc2818 hostname / wildcard matching to util --- src/libgit2/netops.c | 39 --------------------------- src/libgit2/netops.h | 13 --------- src/libgit2/streams/openssl.c | 19 +++++-------- src/util/net.c | 44 +++++++++++++++++++++++++++++++ src/util/net.h | 17 ++++++++++++ tests/libgit2/network/matchhost.c | 13 --------- tests/util/hostname.c | 13 +++++++++ 7 files changed, 80 insertions(+), 78 deletions(-) delete mode 100644 tests/libgit2/network/matchhost.c create mode 100644 tests/util/hostname.c diff --git a/src/libgit2/netops.c b/src/libgit2/netops.c index 00640c600ee..5cae374ad9a 100644 --- a/src/libgit2/netops.c +++ b/src/libgit2/netops.c @@ -83,42 +83,3 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons) memset(buf->data + cons, 0x0, buf->len - buf->offset); buf->offset -= cons; } - -/* Match host names according to RFC 2818 rules */ -int gitno__match_host(const char *pattern, const char *host) -{ - for (;;) { - char c = git__tolower(*pattern++); - - if (c == '\0') - return *host ? -1 : 0; - - if (c == '*') { - c = *pattern; - /* '*' at the end matches everything left */ - if (c == '\0') - return 0; - - /* - * We've found a pattern, so move towards the next matching - * char. The '.' is handled specially because wildcards aren't - * allowed to cross subdomains. - */ - - while(*host) { - char h = git__tolower(*host); - if (c == h) - return gitno__match_host(pattern, host++); - if (h == '.') - return gitno__match_host(pattern, host); - host++; - } - return -1; - } - - if (c != git__tolower(*host++)) - return -1; - } - - return -1; -} diff --git a/src/libgit2/netops.h b/src/libgit2/netops.h index 56f96853459..a3f4a0f9523 100644 --- a/src/libgit2/netops.h +++ b/src/libgit2/netops.h @@ -45,19 +45,6 @@ enum { GITNO_CONNECT_SSL = 1 }; -/** - * Check if the name in a cert matches the wanted hostname - * - * Check if a pattern from a certificate matches the hostname we - * wanted to connect to according to RFC2818 rules (which specifies - * HTTP over TLS). Mainly, an asterisk matches anything, but is - * limited to a single url component. - * - * Note that this does not set an error message. It expects the user - * to provide the message for the user. - */ -int gitno__match_host(const char *pattern, const char *host); - void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len); void gitno_buffer_setup_callback(gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data); int gitno_recv(gitno_buffer *buf); diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index 5e0e2c939db..58b2d1b2363 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -18,6 +18,7 @@ #include "settings.h" #include "posix.h" #include "stream.h" +#include "net.h" #include "streams/socket.h" #include "netops.h" #include "git2/transport.h" @@ -357,15 +358,10 @@ static int ssl_teardown(SSL *ssl) return ret; } -static int check_host_name(const char *name, const char *host) +static bool check_host_name(const char *host, const char *name) { - if (!strcasecmp(name, host)) - return 0; - - if (gitno__match_host(name, host) < 0) - return -1; - - return 0; + return !strcasecmp(host, name) || + git_net_hostname_matches_cert(host, name); } static int verify_server_cert(SSL *ssl, const char *host) @@ -425,10 +421,7 @@ static int verify_server_cert(SSL *ssl, const char *host) if (memchr(name, '\0', namelen)) continue; - if (check_host_name(name, host) < 0) - matched = 0; - else - matched = 1; + matched = !!check_host_name(host, name); } else if (type == GEN_IPADD) { /* Here name isn't so much a name but a binary representation of the IP */ matched = addr && !!memcmp(name, addr, namelen); @@ -481,7 +474,7 @@ static int verify_server_cert(SSL *ssl, const char *host) goto cert_fail_name; } - if (check_host_name((char *)peer_cn, host) < 0) + if (!check_host_name(host, (char *)peer_cn)) goto cert_fail_name; goto cleanup; diff --git a/src/util/net.c b/src/util/net.c index ac7befe0738..dd8a1ba4670 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -19,6 +19,50 @@ #define DEFAULT_PORT_GIT "9418" #define DEFAULT_PORT_SSH "22" +bool git_net_hostname_matches_cert( + const char *hostname, + const char *pattern) +{ + for (;;) { + char c = git__tolower(*pattern++); + + if (c == '\0') + return *hostname ? false : true; + + if (c == '*') { + c = *pattern; + + /* '*' at the end matches everything left */ + if (c == '\0') + return true; + + /* + * We've found a pattern, so move towards the + * next matching char. The '.' is handled + * specially because wildcards aren't allowed + * to cross subdomains. + */ + while(*hostname) { + char h = git__tolower(*hostname); + + if (h == c) + return git_net_hostname_matches_cert(hostname++, pattern); + else if (h == '.') + return git_net_hostname_matches_cert(hostname, pattern); + + hostname++; + } + + return false; + } + + if (c != git__tolower(*hostname++)) + return false; + } + + return false; +} + bool git_net_str_is_url(const char *str) { const char *c; diff --git a/src/util/net.h b/src/util/net.h index 17f0bc4f079..c9a84cb6cec 100644 --- a/src/util/net.h +++ b/src/util/net.h @@ -9,6 +9,23 @@ #include "git2_util.h" +/* + * Hostname handling + */ + +/* + * See if a given hostname matches a certificate name pattern, according + * to RFC2818 rules (which specifies HTTP over TLS). Mainly, an asterisk + * matches anything, but is limited to a single url component. + */ +extern bool git_net_hostname_matches_cert( + const char *hostname, + const char *pattern); + +/* + * URL handling + */ + typedef struct git_net_url { char *scheme; char *host; diff --git a/tests/libgit2/network/matchhost.c b/tests/libgit2/network/matchhost.c deleted file mode 100644 index 3100dc21d70..00000000000 --- a/tests/libgit2/network/matchhost.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "clar_libgit2.h" -#include "netops.h" - -void test_network_matchhost__match(void) -{ - cl_git_pass(gitno__match_host("*.example.org", "www.example.org")); - cl_git_pass(gitno__match_host("*.foo.example.org", "www.foo.example.org")); - cl_git_fail(gitno__match_host("*.foo.example.org", "foo.example.org")); - cl_git_fail(gitno__match_host("*.foo.example.org", "www.example.org")); - cl_git_fail(gitno__match_host("*.example.org", "example.org")); - cl_git_fail(gitno__match_host("*.example.org", "www.foo.example.org")); - cl_git_fail(gitno__match_host("*.example.org", "blah.www.www.example.org")); -} diff --git a/tests/util/hostname.c b/tests/util/hostname.c new file mode 100644 index 00000000000..5d8bfe2ac99 --- /dev/null +++ b/tests/util/hostname.c @@ -0,0 +1,13 @@ +#include "clar_libgit2.h" +#include "net.h" + +void test_hostname__matches_cert(void) +{ + cl_assert_equal_b(true, git_net_hostname_matches_cert("www.example.org", "*.example.org")); + cl_assert_equal_b(true, git_net_hostname_matches_cert("www.foo.example.org", "*.foo.example.org")); + cl_assert_equal_b(false, git_net_hostname_matches_cert("foo.example.org", "*.foo.example.org")); + cl_assert_equal_b(false, git_net_hostname_matches_cert("www.example.org", "*.foo.example.org")); + cl_assert_equal_b(false, git_net_hostname_matches_cert("example.org", "*.example.org")); + cl_assert_equal_b(false, git_net_hostname_matches_cert("www.foo.example.org", "*.example.org")); + cl_assert_equal_b(false, git_net_hostname_matches_cert("blah.www.www.example.org", "*.example.org")); +} From 11c89c386c8862f834097cdc5d9ed79634cf00f3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:30 +0100 Subject: [PATCH 186/816] net: move `gitno` buffer to `staticstr` The `gitno` buffer interface is another layer on top of socket reads. Abstract it a bit into a "static string" that has `git_str` like semantics but without heap allocation which moves the actual reading logic into the socket / stream code, and allows for easier future usage of a static / stack-allocated `git_str`-like interface. --- src/libgit2/fetch.c | 1 - src/libgit2/fetch.h | 2 - src/libgit2/netops.c | 85 ------------------------- src/libgit2/netops.h | 55 ---------------- src/libgit2/pack-objects.c | 1 - src/libgit2/pack-objects.h | 1 - src/libgit2/streams/mbedtls.c | 1 - src/libgit2/streams/openssl.c | 5 +- src/libgit2/streams/socket.c | 1 - src/libgit2/streams/socket.h | 2 +- src/libgit2/transports/auth.h | 3 +- src/libgit2/transports/git.c | 15 ++--- src/libgit2/transports/http.c | 1 - src/libgit2/transports/smart.c | 57 +++++++++-------- src/libgit2/transports/smart.h | 9 ++- src/libgit2/transports/smart_pkt.c | 1 - src/libgit2/transports/smart_protocol.c | 78 +++++++++++------------ src/libgit2/transports/ssh.c | 1 - src/libgit2/transports/winhttp.c | 1 - src/util/staticstr.h | 66 +++++++++++++++++++ tests/util/url/joinpath.c | 1 - tests/util/url/redirect.c | 1 - 22 files changed, 151 insertions(+), 237 deletions(-) delete mode 100644 src/libgit2/netops.c delete mode 100644 src/libgit2/netops.h create mode 100644 src/util/staticstr.h diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 5bbef87f4e0..d74abb4a847 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -17,7 +17,6 @@ #include "remote.h" #include "refspec.h" #include "pack.h" -#include "netops.h" #include "repository.h" #include "refs.h" #include "transports/smart.h" diff --git a/src/libgit2/fetch.h b/src/libgit2/fetch.h index 10b6731f0a2..493366dedf1 100644 --- a/src/libgit2/fetch.h +++ b/src/libgit2/fetch.h @@ -11,8 +11,6 @@ #include "git2/remote.h" -#include "netops.h" - int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts); int git_fetch_download_pack(git_remote *remote); diff --git a/src/libgit2/netops.c b/src/libgit2/netops.c deleted file mode 100644 index 5cae374ad9a..00000000000 --- a/src/libgit2/netops.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "netops.h" - -#include -#include "git2/errors.h" - -#include "posix.h" -#include "str.h" -#include "runtime.h" - -int gitno_recv(gitno_buffer *buf) -{ - return buf->recv(buf); -} - -void gitno_buffer_setup_callback( - gitno_buffer *buf, - char *data, - size_t len, - int (*recv)(gitno_buffer *buf), void *cb_data) -{ - memset(data, 0x0, len); - buf->data = data; - buf->len = len; - buf->offset = 0; - buf->recv = recv; - buf->cb_data = cb_data; -} - -static int recv_stream(gitno_buffer *buf) -{ - git_stream *io = (git_stream *) buf->cb_data; - size_t readlen = buf->len - buf->offset; - ssize_t ret; - - readlen = min(readlen, INT_MAX); - - ret = git_stream_read(io, buf->data + buf->offset, (int)readlen); - if (ret < 0) - return -1; - - buf->offset += ret; - return (int)ret; -} - -void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len) -{ - memset(data, 0x0, len); - buf->data = data; - buf->len = len; - buf->offset = 0; - buf->recv = recv_stream; - buf->cb_data = st; -} - -/* Consume up to ptr and move the rest of the buffer to the beginning */ -int gitno_consume(gitno_buffer *buf, const char *ptr) -{ - size_t consumed; - - GIT_ASSERT(ptr - buf->data >= 0); - GIT_ASSERT(ptr - buf->data <= (int) buf->len); - - consumed = ptr - buf->data; - - memmove(buf->data, ptr, buf->offset - consumed); - memset(buf->data + buf->offset, 0x0, buf->len - buf->offset); - buf->offset -= consumed; - - return 0; -} - -/* Consume const bytes and move the rest of the buffer to the beginning */ -void gitno_consume_n(gitno_buffer *buf, size_t cons) -{ - memmove(buf->data, buf->data + cons, buf->len - buf->offset); - memset(buf->data + cons, 0x0, buf->len - buf->offset); - buf->offset -= cons; -} diff --git a/src/libgit2/netops.h b/src/libgit2/netops.h deleted file mode 100644 index a3f4a0f9523..00000000000 --- a/src/libgit2/netops.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_netops_h__ -#define INCLUDE_netops_h__ - -#include "common.h" - -#include "posix.h" -#include "stream.h" -#include "net.h" - -#ifdef GIT_OPENSSL -# include "streams/openssl.h" -#endif - -typedef struct gitno_ssl { -#ifdef GIT_OPENSSL - SSL *ssl; -#else - size_t dummy; -#endif -} gitno_ssl; - -/* Represents a socket that may or may not be using SSL */ -typedef struct gitno_socket { - GIT_SOCKET socket; - gitno_ssl ssl; -} gitno_socket; - -typedef struct gitno_buffer { - char *data; - size_t len; - size_t offset; - int (*recv)(struct gitno_buffer *buffer); - void *cb_data; -} gitno_buffer; - -/* Flags to gitno_connect */ -enum { - /* Attempt to create an SSL connection. */ - GITNO_CONNECT_SSL = 1 -}; - -void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len); -void gitno_buffer_setup_callback(gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data); -int gitno_recv(gitno_buffer *buf); - -int gitno_consume(gitno_buffer *buf, const char *ptr); -void gitno_consume_n(gitno_buffer *buf, size_t cons); - -#endif diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index fc8efc65f5e..b2d80cba954 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -11,7 +11,6 @@ #include "zstream.h" #include "delta.h" #include "iterator.h" -#include "netops.h" #include "pack.h" #include "thread.h" #include "tree.h" diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h index 0ceebc23cab..bbc8b9430ee 100644 --- a/src/libgit2/pack-objects.h +++ b/src/libgit2/pack-objects.h @@ -13,7 +13,6 @@ #include "str.h" #include "hash.h" #include "oidmap.h" -#include "netops.h" #include "zstream.h" #include "pool.h" #include "indexer.h" diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index 0cf5c8af1fb..49aa76c3ed8 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -14,7 +14,6 @@ #include "runtime.h" #include "stream.h" #include "streams/socket.h" -#include "netops.h" #include "git2/transport.h" #include "util.h" diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index 58b2d1b2363..9db911e39b3 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -20,7 +20,6 @@ #include "stream.h" #include "net.h" #include "streams/socket.h" -#include "netops.h" #include "git2/transport.h" #include "git2/sys/openssl.h" @@ -71,14 +70,14 @@ static void *git_openssl_malloc(size_t bytes, const char *file, int line) GIT_UNUSED(line); return git__calloc(1, bytes); } - + static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line) { GIT_UNUSED(file); GIT_UNUSED(line); return git__realloc(mem, size); } - + static void git_openssl_free(void *mem, const char *file, int line) { GIT_UNUSED(file); diff --git a/src/libgit2/streams/socket.c b/src/libgit2/streams/socket.c index 8f23e746e51..6994d58f268 100644 --- a/src/libgit2/streams/socket.c +++ b/src/libgit2/streams/socket.c @@ -8,7 +8,6 @@ #include "streams/socket.h" #include "posix.h" -#include "netops.h" #include "registry.h" #include "runtime.h" #include "stream.h" diff --git a/src/libgit2/streams/socket.h b/src/libgit2/streams/socket.h index 300e708937f..73e8de099a6 100644 --- a/src/libgit2/streams/socket.h +++ b/src/libgit2/streams/socket.h @@ -9,7 +9,7 @@ #include "common.h" -#include "netops.h" +#include "stream.h" typedef struct { git_stream parent; diff --git a/src/libgit2/transports/auth.h b/src/libgit2/transports/auth.h index 64680cc5358..9f6f8fd3b2d 100644 --- a/src/libgit2/transports/auth.h +++ b/src/libgit2/transports/auth.h @@ -9,8 +9,7 @@ #define INCLUDE_transports_auth_h__ #include "common.h" - -#include "netops.h" +#include "net.h" typedef enum { GIT_HTTP_AUTH_BASIC = 1, diff --git a/src/libgit2/transports/git.c b/src/libgit2/transports/git.c index 591e2ab0352..53611f2a7a6 100644 --- a/src/libgit2/transports/git.c +++ b/src/libgit2/transports/git.c @@ -7,7 +7,7 @@ #include "common.h" -#include "netops.h" +#include "net.h" #include "stream.h" #include "streams/socket.h" #include "git2/sys/transport.h" @@ -95,22 +95,21 @@ static int git_proto_stream_read( size_t buf_size, size_t *bytes_read) { - int error; git_proto_stream *s = (git_proto_stream *)stream; - gitno_buffer buf; + ssize_t ret; + int error; *bytes_read = 0; if (!s->sent_command && (error = send_command(s)) < 0) return error; - gitno_buffer_setup_fromstream(s->io, &buf, buffer, buf_size); + ret = git_stream_read(s->io, buffer, min(buf_size, INT_MAX)); - if ((error = gitno_recv(&buf)) < 0) - return error; - - *bytes_read = buf.offset; + if (ret < 0) + return -1; + *bytes_read = (size_t)ret; return 0; } diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index cda76ae6199..0534503bf25 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -11,7 +11,6 @@ #include "http_parser.h" #include "net.h" -#include "netops.h" #include "remote.h" #include "smart.h" #include "auth.h" diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index a56524bff0a..53727282850 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -13,30 +13,42 @@ #include "refspec.h" #include "proxy.h" -static int git_smart__recv_cb(gitno_buffer *buf) +int git_smart__recv(transport_smart *t) { - transport_smart *t = (transport_smart *) buf->cb_data; - size_t old_len, bytes_read; - int error; + size_t bytes_read; + int ret; + GIT_ASSERT_ARG(t); GIT_ASSERT(t->current_stream); - old_len = buf->offset; + if (git_staticstr_remain(&t->buffer) == 0) { + git_error_set(GIT_ERROR_NET, "out of buffer space"); + return -1; + } - if ((error = t->current_stream->read(t->current_stream, buf->data + buf->offset, buf->len - buf->offset, &bytes_read)) < 0) - return error; + ret = t->current_stream->read(t->current_stream, + git_staticstr_offset(&t->buffer), + git_staticstr_remain(&t->buffer), + &bytes_read); - buf->offset += bytes_read; + if (ret < 0) + return ret; + + GIT_ASSERT(bytes_read <= INT_MAX); + GIT_ASSERT(bytes_read <= git_staticstr_remain(&t->buffer)); + + git_staticstr_increase(&t->buffer, bytes_read); if (t->packetsize_cb && !t->cancelled.val) { - error = t->packetsize_cb(bytes_read, t->packetsize_payload); - if (error) { + ret = t->packetsize_cb(bytes_read, t->packetsize_payload); + + if (ret) { git_atomic32_set(&t->cancelled, 1); return GIT_EUSER; } } - return (int)(buf->offset - old_len); + return (int)bytes_read; } GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransport) @@ -155,8 +167,6 @@ static int git_smart__connect( /* Save off the current stream (i.e. socket) that we are working with */ t->current_stream = stream; - gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); - /* 2 flushes for RPC; 1 for stateful */ if ((error = git_smart__store_refs(t, t->rpc ? 2 : 1)) < 0) return error; @@ -313,8 +323,6 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len if ((error = stream->write(stream, (const char *)data, len)) < 0) return error; - gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); - return 0; } @@ -339,8 +347,6 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream /* Save off the current stream (i.e. socket) that we are working with */ t->current_stream = *stream; - gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); - return 0; } @@ -502,20 +508,17 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) t->owner = owner; t->rpc = definition->rpc; - if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0) { + if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0 || + git_vector_init(&t->heads, 16, ref_name_cmp) < 0 || + definition->callback(&t->wrapped, &t->parent, definition->param) < 0) { + git_vector_free(&t->refs); + git_vector_free(&t->heads); + t->wrapped->free(t->wrapped); git__free(t); return -1; } - if (git_vector_init(&t->heads, 16, ref_name_cmp) < 0) { - git__free(t); - return -1; - } - - if (definition->callback(&t->wrapped, &t->parent, definition->param) < 0) { - git__free(t); - return -1; - } + git_staticstr_init(&t->buffer, GIT_SMART_BUFFER_SIZE); *out = (git_transport *) t; return 0; diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 34e27ea8e05..52c7553a1d7 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -11,12 +11,14 @@ #include "git2.h" #include "vector.h" -#include "netops.h" #include "push.h" #include "str.h" #include "oidarray.h" +#include "staticstr.h" #include "git2/sys/transport.h" +#define GIT_SMART_BUFFER_SIZE 65536 + #define GIT_SIDE_BAND_DATA 1 #define GIT_SIDE_BAND_PROGRESS 2 #define GIT_SIDE_BAND_ERROR 3 @@ -170,8 +172,7 @@ typedef struct { unsigned rpc : 1, have_refs : 1, connected : 1; - gitno_buffer buffer; - char buffer_data[65536]; + git_staticstr_with_size(GIT_SMART_BUFFER_SIZE) buffer; } transport_smart; /* smart_protocol.c */ @@ -192,6 +193,8 @@ int git_smart__download_pack( git_indexer_progress *stats); /* smart.c */ +int git_smart__recv(transport_smart *t); + int git_smart__negotiation_step(git_transport *transport, void *data, size_t len); int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **out); diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 9127ad5fe43..7805f332377 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -9,7 +9,6 @@ #include "smart.h" #include "util.h" -#include "netops.h" #include "posix.h" #include "str.h" #include "oid.h" diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index f7a56782930..c9c422d4c85 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -27,7 +27,6 @@ bool git_smart__ofs_delta_enabled = true; int git_smart__store_refs(transport_smart *t, int flushes) { - gitno_buffer *buf = &t->buffer; git_vector *refs = &t->refs; int error, flush = 0, recvd; const char *line_end = NULL; @@ -45,8 +44,10 @@ int git_smart__store_refs(transport_smart *t, int flushes) pkt = NULL; do { - if (buf->offset > 0) - error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset, &pkt_parse_data); + if (t->buffer.len > 0) + error = git_pkt_parse_line(&pkt, &line_end, + t->buffer.data, t->buffer.len, + &pkt_parse_data); else error = GIT_EBUFS; @@ -54,7 +55,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) return error; if (error == GIT_EBUFS) { - if ((recvd = gitno_recv(buf)) < 0) + if ((recvd = git_smart__recv(t)) < 0) return recvd; if (recvd == 0) { @@ -65,8 +66,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) continue; } - if (gitno_consume(buf, line_end) < 0) - return -1; + git_staticstr_consume(&t->buffer, line_end); if (pkt->type == GIT_PKT_ERR) { git_error_set(GIT_ERROR_NET, "remote error: %s", ((git_pkt_err *)pkt)->error); @@ -259,10 +259,9 @@ int git_smart__detect_caps( static int recv_pkt( git_pkt **out_pkt, git_pkt_type *out_type, - transport_smart *t, - gitno_buffer *buf) + transport_smart *t) { - const char *ptr = buf->data, *line_end = ptr; + const char *ptr = t->buffer.data, *line_end = ptr; git_pkt *pkt = NULL; git_pkt_parse_data pkt_parse_data = { 0 }; int error = 0, ret; @@ -271,8 +270,9 @@ static int recv_pkt( pkt_parse_data.seen_capabilities = 1; do { - if (buf->offset > 0) - error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset, &pkt_parse_data); + if (t->buffer.len > 0) + error = git_pkt_parse_line(&pkt, &line_end, ptr, + t->buffer.len, &pkt_parse_data); else error = GIT_EBUFS; @@ -282,7 +282,7 @@ static int recv_pkt( if (error < 0 && error != GIT_EBUFS) return error; - if ((ret = gitno_recv(buf)) < 0) { + if ((ret = git_smart__recv(t)) < 0) { return ret; } else if (ret == 0) { git_error_set(GIT_ERROR_NET, "early EOF"); @@ -290,8 +290,7 @@ static int recv_pkt( } } while (error); - if (gitno_consume(buf, line_end) < 0) - return -1; + git_staticstr_consume(&t->buffer, line_end); if (out_type != NULL) *out_type = pkt->type; @@ -306,11 +305,10 @@ static int recv_pkt( static int store_common(transport_smart *t) { git_pkt *pkt = NULL; - gitno_buffer *buf = &t->buffer; int error; do { - if ((error = recv_pkt(&pkt, NULL, t, buf)) < 0) + if ((error = recv_pkt(&pkt, NULL, t)) < 0) return error; if (pkt->type != GIT_PKT_ACK) { @@ -327,7 +325,7 @@ static int store_common(transport_smart *t) return 0; } -static int wait_while_ack(transport_smart *t, gitno_buffer *buf) +static int wait_while_ack(transport_smart *t) { int error; git_pkt *pkt = NULL; @@ -336,7 +334,7 @@ static int wait_while_ack(transport_smart *t, gitno_buffer *buf) while (1) { git_pkt_free(pkt); - if ((error = recv_pkt(&pkt, NULL, t, buf)) < 0) + if ((error = recv_pkt(&pkt, NULL, t)) < 0) return error; if (pkt->type == GIT_PKT_NAK) @@ -402,7 +400,6 @@ int git_smart__negotiate_fetch( { transport_smart *t = (transport_smart *)transport; git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT; - gitno_buffer *buf = &t->buffer; git_str data = GIT_STR_INIT; git_revwalk *walk = NULL; int error = -1; @@ -430,7 +427,7 @@ int git_smart__negotiate_fetch( if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; - while ((error = recv_pkt((git_pkt **)&pkt, NULL, t, buf)) == 0) { + while ((error = recv_pkt((git_pkt **)&pkt, NULL, t)) == 0) { bool complete = false; if (pkt->type == GIT_PKT_SHALLOW) { @@ -495,7 +492,7 @@ int git_smart__negotiate_fetch( if ((error = store_common(t)) < 0) goto on_error; } else { - if ((error = recv_pkt(NULL, &pkt_type, t, buf)) < 0) + if ((error = recv_pkt(NULL, &pkt_type, t)) < 0) goto on_error; if (pkt_type == GIT_PKT_ACK) { @@ -568,7 +565,7 @@ int git_smart__negotiate_fetch( /* Now let's eat up whatever the server gives us */ if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) { - if ((error = recv_pkt(NULL, &pkt_type, t, buf)) < 0) + if ((error = recv_pkt(NULL, &pkt_type, t)) < 0) return error; if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) { @@ -576,7 +573,7 @@ int git_smart__negotiate_fetch( return -1; } } else { - error = wait_while_ack(t, buf); + error = wait_while_ack(t); } return error; @@ -606,7 +603,10 @@ int git_smart__shallow_roots(git_oidarray *out, git_transport *transport) return 0; } -static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_indexer_progress *stats) +static int no_sideband( + transport_smart *t, + struct git_odb_writepack *writepack, + git_indexer_progress *stats) { int recvd; @@ -616,12 +616,12 @@ static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, return GIT_EUSER; } - if (writepack->append(writepack, buf->data, buf->offset, stats) < 0) + if (writepack->append(writepack, t->buffer.data, t->buffer.len, stats) < 0) return -1; - gitno_consume_n(buf, buf->offset); + git_staticstr_clear(&t->buffer); - if ((recvd = gitno_recv(buf)) < 0) + if ((recvd = git_smart__recv(t)) < 0) return recvd; } while(recvd > 0); @@ -663,7 +663,6 @@ int git_smart__download_pack( git_indexer_progress *stats) { transport_smart *t = (transport_smart *)transport; - gitno_buffer *buf = &t->buffer; git_odb *odb; struct git_odb_writepack *writepack = NULL; int error = 0; @@ -682,9 +681,10 @@ int git_smart__download_pack( t->packetsize_payload = &npp; /* We might have something in the buffer already from negotiate_fetch */ - if (t->buffer.offset > 0 && !t->cancelled.val) - if (t->packetsize_cb(t->buffer.offset, t->packetsize_payload)) + if (t->buffer.len > 0 && !t->cancelled.val) { + if (t->packetsize_cb(t->buffer.len, t->packetsize_payload)) git_atomic32_set(&t->cancelled, 1); + } } if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 || @@ -697,7 +697,7 @@ int git_smart__download_pack( * check which one belongs there. */ if (!t->caps.side_band && !t->caps.side_band_64k) { - error = no_sideband(t, writepack, buf, stats); + error = no_sideband(t, writepack, stats); goto done; } @@ -711,7 +711,7 @@ int git_smart__download_pack( goto done; } - if ((error = recv_pkt(&pkt, NULL, t, buf)) >= 0) { + if ((error = recv_pkt(&pkt, NULL, t)) >= 0) { /* Check cancellation after network call */ if (t->cancelled.val) { git_error_clear(); @@ -916,15 +916,15 @@ static int parse_report(transport_smart *transport, git_push *push) git_pkt *pkt = NULL; git_pkt_parse_data pkt_parse_data = { 0 }; const char *line_end = NULL; - gitno_buffer *buf = &transport->buffer; int error, recvd; git_str data_pkt_buf = GIT_STR_INIT; for (;;) { - if (buf->offset > 0) + if (transport->buffer.len > 0) error = git_pkt_parse_line(&pkt, &line_end, - buf->data, buf->offset, - &pkt_parse_data); + transport->buffer.data, + transport->buffer.len, + &pkt_parse_data); else error = GIT_EBUFS; @@ -934,7 +934,7 @@ static int parse_report(transport_smart *transport, git_push *push) } if (error == GIT_EBUFS) { - if ((recvd = gitno_recv(buf)) < 0) { + if ((recvd = git_smart__recv(transport)) < 0) { error = recvd; goto done; } @@ -947,9 +947,7 @@ static int parse_report(transport_smart *transport, git_push *push) continue; } - if (gitno_consume(buf, line_end) < 0) - return -1; - + git_staticstr_consume(&transport->buffer, line_end); error = 0; switch (pkt->type) { diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c index 5500ea100bd..af618e1a6ed 100644 --- a/src/libgit2/transports/ssh.c +++ b/src/libgit2/transports/ssh.c @@ -13,7 +13,6 @@ #include "runtime.h" #include "net.h" -#include "netops.h" #include "smart.h" #include "streams/socket.h" #include "sysdir.h" diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index de24a2a41c1..27e0fb6f7e9 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -13,7 +13,6 @@ #include "git2/transport.h" #include "posix.h" #include "str.h" -#include "netops.h" #include "smart.h" #include "remote.h" #include "repository.h" diff --git a/src/util/staticstr.h b/src/util/staticstr.h new file mode 100644 index 00000000000..b7d0790c4fd --- /dev/null +++ b/src/util/staticstr.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_stackstr_h__ +#define INCLUDE_stackstr_h__ + +#include "git2_util.h" + +typedef struct { + /* Length of / number of bytes used by `data`. */ + size_t len; + + /* Size of the allocated `data` buffer. */ + size_t size; + + /* The actual string buffer data. */ + char data[GIT_FLEX_ARRAY]; +} git_staticstr; + +#define git_staticstr_with_size(__size) \ + struct { \ + size_t len; \ + size_t size; \ + char data[__size]; \ + } + +#define git_staticstr_init(__str, __size) \ + do { \ + (__str)->len = 0; \ + (__str)->size = __size; \ + (__str)->data[0] = '\0'; \ + } while(0) + +#define git_staticstr_offset(__str) \ + ((__str)->data + (__str)->len) + +#define git_staticstr_remain(__str) \ + ((__str)->len > (__str)->size ? 0 : ((__str)->size - (__str)->len)) + +#define git_staticstr_increase(__str, __len) \ + do { ((__str)->len += __len); } while(0) + +#define git_staticstr_consume_bytes(__str, __len) \ + do { git_staticstr_consume(__str, (__str)->data + __len); } while(0) + +#define git_staticstr_consume(__str, __end) \ + do { \ + if (__end > (__str)->data && \ + __end <= (__str)->data + (__str)->len) { \ + size_t __consumed = __end - (__str)->data; \ + memmove((__str)->data, __end, (__str)->len - __consumed); \ + (__str)->len -= __consumed; \ + (__str)->data[(__str)->len] = '\0'; \ + } \ + } while(0) + +#define git_staticstr_clear(__str) \ + do { \ + (__str)->len = 0; \ + (__str)->data[0] = 0; \ + } while(0) + +#endif diff --git a/tests/util/url/joinpath.c b/tests/util/url/joinpath.c index 9fc02cde4a9..6027093e492 100644 --- a/tests/util/url/joinpath.c +++ b/tests/util/url/joinpath.c @@ -1,6 +1,5 @@ #include "clar_libgit2.h" #include "net.h" -#include "netops.h" static git_net_url source, target; diff --git a/tests/util/url/redirect.c b/tests/util/url/redirect.c index 5401778618f..a6f99dcdf09 100644 --- a/tests/util/url/redirect.c +++ b/tests/util/url/redirect.c @@ -1,6 +1,5 @@ #include "clar_libgit2.h" #include "net.h" -#include "netops.h" static git_net_url conndata; From 933b04c219b49d0f9cd779d024bfa39d806839ac Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:30 +0100 Subject: [PATCH 187/816] ci: update to poxygit v0.6.0 v0.6.0 of poxygit add support for throttling connections to test timeouts and low-bandwidth situations. --- ci/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index c46cf0dc437..a6735231f21 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -171,7 +171,7 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then fi if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then - curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.5.1/poxygit-0.5.1.jar >poxygit.jar + curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.6.0/poxygit-0.6.0.jar >poxygit.jar echo "Starting HTTP server..." HTTP_DIR=`mktemp -d ${TMPDIR}/http.XXXXXXXX` From fad90428970e332153027773b517a1606c0efa1f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:30 +0100 Subject: [PATCH 188/816] streams: sockets are non-blocking and can timeout Make socket I/O non-blocking and add optional timeouts. Users may now set `GIT_OPT_SET_SERVER_CONNECT_TIMEOUT` to set a shorter connection timeout. (The connect timeout cannot be longer than the operating system default.) Users may also now configure the socket read and write timeouts with `GIT_OPT_SET_SERVER_TIMEOUT`. By default, connects still timeout based on the operating system defaults (typically 75 seconds) and socket read and writes block. Add a test against our custom testing git server that ensures that we can timeout reads against a slow server. --- ci/test.sh | 4 + include/git2/common.h | 27 ++++- include/git2/errors.h | 3 +- include/git2/sys/stream.h | 18 ++- src/libgit2/libgit2.c | 36 ++++++ src/libgit2/streams/socket.c | 198 +++++++++++++++++++++++++++---- src/libgit2/streams/stransport.c | 17 ++- tests/libgit2/CMakeLists.txt | 2 +- tests/libgit2/online/clone.c | 60 ++++++++++ 9 files changed, 335 insertions(+), 30 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index a6735231f21..ee6801a79a2 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -271,9 +271,13 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then export GITTEST_REMOTE_REDIRECT_INITIAL="http://localhost:9000/initial-redirect/libgit2/TestGitRepository" export GITTEST_REMOTE_REDIRECT_SUBSEQUENT="http://localhost:9000/subsequent-redirect/libgit2/TestGitRepository" + export GITTEST_REMOTE_SPEED_SLOW="http://localhost:9000/speed-9600/test.git" + export GITTEST_REMOTE_SPEED_TIMESOUT="http://localhost:9000/speed-0.5/test.git" run_test online unset GITTEST_REMOTE_REDIRECT_INITIAL unset GITTEST_REMOTE_REDIRECT_SUBSEQUENT + unset GITTEST_REMOTE_SPEED_SLOW + unset GITTEST_REMOTE_SPEED_TIMESOUT # Run the online tests that immutably change global state separately # to avoid polluting the test environment. diff --git a/include/git2/common.h b/include/git2/common.h index f968deb233a..ab6bc1333b3 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -224,7 +224,11 @@ typedef enum { GIT_OPT_GET_OWNER_VALIDATION, GIT_OPT_SET_OWNER_VALIDATION, GIT_OPT_GET_HOMEDIR, - GIT_OPT_SET_HOMEDIR + GIT_OPT_SET_HOMEDIR, + GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, + GIT_OPT_GET_SERVER_CONNECT_TIMEOUT, + GIT_OPT_SET_SERVER_TIMEOUT, + GIT_OPT_GET_SERVER_TIMEOUT } git_libgit2_opt_t; /** @@ -480,6 +484,27 @@ typedef enum { * > * > - `path` directory of home directory. * + * opts(GIT_OPT_GET_SERVER_CONNECT_TIMEOUT, int *timeout) + * > Gets the timeout (in milliseconds) to attempt connections to + * > a remote server. + * + * opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, int timeout) + * > Sets the timeout (in milliseconds) to attempt connections to + * > a remote server. This is supported only for HTTP(S) connections + * > and is not supported by SSH. Set to 0 to use the system default. + * > Note that this may not be able to be configured longer than the + * > system default, typically 75 seconds. + * + * opts(GIT_OPT_GET_SERVER_TIMEOUT, int *timeout) + * > Gets the timeout (in milliseconds) for reading from and writing + * > to a remote server. + * + * opts(GIT_OPT_SET_SERVER_TIMEOUT, int timeout) + * > Sets the timeout (in milliseconds) for reading from and writing + * > to a remote server. This is supported only for HTTP(S) + * > connections and is not supported by SSH. Set to 0 to use the + * > system default. + * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure diff --git a/include/git2/errors.h b/include/git2/errors.h index e634a97c176..7180852f95c 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -58,7 +58,8 @@ typedef enum { GIT_EMISMATCH = -33, /**< Hashsum mismatch in object */ GIT_EINDEXDIRTY = -34, /**< Unsaved changes in the index would be overwritten */ GIT_EAPPLYFAIL = -35, /**< Patch application failed */ - GIT_EOWNER = -36 /**< The object is not owned by the current user */ + GIT_EOWNER = -36, /**< The object is not owned by the current user */ + GIT_TIMEOUT = -37 /**< The operation timed out */ } git_error_code; /** diff --git a/include/git2/sys/stream.h b/include/git2/sys/stream.h index e0e03a2d764..3d28d09b321 100644 --- a/include/git2/sys/stream.h +++ b/include/git2/sys/stream.h @@ -29,8 +29,22 @@ GIT_BEGIN_DECL typedef struct git_stream { int version; - int encrypted; - int proxy_support; + int encrypted : 1, + proxy_support : 1; + + /** + * Timeout for read and write operations; can be set to `0` to + * block indefinitely. + */ + int timeout; + + /** + * Timeout to connect to the remote server; can be set to `0` + * to use the system defaults. This can be shorter than the + * system default - often 75 seconds - but cannot be longer. + */ + int connect_timeout; + int GIT_CALLBACK(connect)(struct git_stream *); int GIT_CALLBACK(certificate)(git_cert **, struct git_stream *); int GIT_CALLBACK(set_proxy)(struct git_stream *, const git_proxy_options *proxy_opts); diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 178880c9eb9..ce287147a70 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -48,6 +48,8 @@ extern size_t git_indexer__max_objects; extern bool git_disable_pack_keep_file_checks; extern int git_odb__packed_priority; extern int git_odb__loose_priority; +extern int git_socket_stream__connect_timeout; +extern int git_socket_stream__timeout; char *git__user_agent; char *git__ssl_ciphers; @@ -436,6 +438,40 @@ int git_libgit2_opts(int key, ...) error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *)); break; + case GIT_OPT_GET_SERVER_CONNECT_TIMEOUT: + *(va_arg(ap, int *)) = git_socket_stream__connect_timeout; + break; + + case GIT_OPT_SET_SERVER_CONNECT_TIMEOUT: + { + int timeout = va_arg(ap, int); + + if (timeout < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid connect timeout"); + error = -1; + } else { + git_socket_stream__connect_timeout = timeout; + } + } + break; + + case GIT_OPT_GET_SERVER_TIMEOUT: + *(va_arg(ap, int *)) = git_socket_stream__timeout; + break; + + case GIT_OPT_SET_SERVER_TIMEOUT: + { + int timeout = va_arg(ap, int); + + if (timeout < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid timeout"); + error = -1; + } else { + git_socket_stream__timeout = timeout; + } + } + break; + default: git_error_set(GIT_ERROR_INVALID, "invalid option key"); error = -1; diff --git a/src/libgit2/streams/socket.c b/src/libgit2/streams/socket.c index 6994d58f268..0e0aa69349b 100644 --- a/src/libgit2/streams/socket.c +++ b/src/libgit2/streams/socket.c @@ -20,6 +20,7 @@ # include # include # include +# include #else # include # include @@ -28,6 +29,9 @@ # endif #endif +int git_socket_stream__connect_timeout = 0; +int git_socket_stream__timeout = 0; + #ifdef GIT_WIN32 static void net_set_error(const char *str) { @@ -66,21 +70,105 @@ static int close_socket(GIT_SOCKET s) } +static int set_nonblocking(GIT_SOCKET s) +{ +#ifdef GIT_WIN32 + unsigned long nonblocking = 1; + + if (ioctlsocket(s, FIONBIO, &nonblocking) != 0) { + net_set_error("could not set socket non-blocking"); + return -1; + } +#else + int flags; + + if ((flags = fcntl(s, F_GETFL, 0)) == -1) { + net_set_error("could not query socket flags"); + return -1; + } + + flags |= O_NONBLOCK; + + if (fcntl(s, F_SETFL, flags) != 0) { + net_set_error("could not set socket non-blocking"); + return -1; + } +#endif + + return 0; +} + +/* Promote a sockerr to an errno for our error handling routines */ +static int handle_sockerr(GIT_SOCKET socket) +{ + int sockerr; + socklen_t errlen = sizeof(sockerr); + + if (getsockopt(socket, SOL_SOCKET, SO_ERROR, &sockerr, &errlen) < 0) + return -1; + + if (sockerr == ETIMEDOUT) + return GIT_TIMEOUT; + + errno = sockerr; + return -1; +} + +static int connect_with_timeout( + GIT_SOCKET socket, + const struct sockaddr *address, + socklen_t address_len, + int timeout) +{ + struct pollfd fd; + int error; + + if (timeout && (error = set_nonblocking(socket)) < 0) + return error; + + error = connect(socket, address, address_len); + + if (error == 0 || (error == -1 && errno != EINPROGRESS)) + return error; + + fd.fd = socket; + fd.events = POLLOUT; + fd.revents = 0; + + error = poll(&fd, 1, timeout); + + if (error == 0) { + return GIT_TIMEOUT; + } else if (error != 1) { + return -1; + } else if ((fd.revents & (POLLHUP | POLLERR))) { + return handle_sockerr(socket); + } else if ((fd.revents & POLLOUT) != POLLOUT) { + git_error_set(GIT_ERROR_NET, + "unknown error while polling for connect: %d", + fd.revents); + return -1; + } + + return 0; +} + static int socket_connect(git_stream *stream) { - struct addrinfo *info = NULL, *p; - struct addrinfo hints; git_socket_stream *st = (git_socket_stream *) stream; GIT_SOCKET s = INVALID_SOCKET; - int ret; + struct addrinfo *info = NULL, *p; + struct addrinfo hints; + int error; memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; - if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) { + if ((error = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) { git_error_set(GIT_ERROR_NET, - "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret)); + "failed to resolve address for %s: %s", + st->host, p_gai_strerror(error)); return -1; } @@ -90,51 +178,115 @@ static int socket_connect(git_stream *stream) if (s == INVALID_SOCKET) continue; - if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) + error = connect_with_timeout(s, p->ai_addr, + (socklen_t)p->ai_addrlen, + st->parent.connect_timeout); + + if (error == 0) break; /* If we can't connect, try the next one */ close_socket(s); s = INVALID_SOCKET; + + if (error == GIT_TIMEOUT) + break; } /* Oops, we couldn't connect to any address */ - if (s == INVALID_SOCKET && p == NULL) { - git_error_set(GIT_ERROR_OS, "failed to connect to %s", st->host); - p_freeaddrinfo(info); - return -1; + if (s == INVALID_SOCKET) { + if (error == GIT_TIMEOUT) + git_error_set(GIT_ERROR_NET, "failed to connect to %s: Operation timed out", st->host); + else + git_error_set(GIT_ERROR_OS, "failed to connect to %s", st->host); + error = -1; + goto done; } + if (st->parent.timeout && !st->parent.connect_timeout && + (error = set_nonblocking(s)) < 0) + return error; + st->s = s; + error = 0; + +done: p_freeaddrinfo(info); - return 0; + return error; } -static ssize_t socket_write(git_stream *stream, const char *data, size_t len, int flags) +static ssize_t socket_write( + git_stream *stream, + const char *data, + size_t len, + int flags) { git_socket_stream *st = (git_socket_stream *) stream; - ssize_t written; + struct pollfd fd; + ssize_t ret; GIT_ASSERT(flags == 0); GIT_UNUSED(flags); - errno = 0; + ret = p_send(st->s, data, len, 0); + + if (st->parent.timeout && ret < 0 && + (errno == EAGAIN || errno != EWOULDBLOCK)) { + fd.fd = st->s; + fd.events = POLLOUT; + fd.revents = 0; + + ret = poll(&fd, 1, st->parent.timeout); - if ((written = p_send(st->s, data, len, 0)) < 0) { - net_set_error("error sending data"); + if (ret == 1) { + ret = p_send(st->s, data, len, 0); + } else if (ret == 0) { + git_error_set(GIT_ERROR_NET, + "could not write to socket: timed out"); + return GIT_TIMEOUT; + } + } + + if (ret < 0) { + net_set_error("error receiving data from socket"); return -1; } - return written; + return ret; } -static ssize_t socket_read(git_stream *stream, void *data, size_t len) +static ssize_t socket_read( + git_stream *stream, + void *data, + size_t len) { - ssize_t ret; git_socket_stream *st = (git_socket_stream *) stream; + struct pollfd fd; + ssize_t ret; + + ret = p_recv(st->s, data, len, 0); + + if (st->parent.timeout && ret < 0 && + (errno == EAGAIN || errno != EWOULDBLOCK)) { + fd.fd = st->s; + fd.events = POLLIN; + fd.revents = 0; - if ((ret = p_recv(st->s, data, len, 0)) < 0) - net_set_error("error receiving socket data"); + ret = poll(&fd, 1, st->parent.timeout); + + if (ret == 1) { + ret = p_recv(st->s, data, len, 0); + } else if (ret == 0) { + git_error_set(GIT_ERROR_NET, + "could not read from socket: timed out"); + return GIT_TIMEOUT; + } + } + + if (ret < 0) { + net_set_error("error receiving data from socket"); + return -1; + } return ret; } @@ -182,6 +334,8 @@ static int default_socket_stream_new( } st->parent.version = GIT_STREAM_VERSION; + st->parent.timeout = git_socket_stream__timeout; + st->parent.connect_timeout = git_socket_stream__connect_timeout; st->parent.connect = socket_connect; st->parent.write = socket_write; st->parent.read = socket_read; @@ -248,7 +402,7 @@ int git_socket_stream_global_init(void) return git_runtime_shutdown_register(socket_stream_global_shutdown); } - + #else #include "stream.h" diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 74ee0d1eeb0..d956df84d10 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -161,7 +161,9 @@ static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len) if (ret < 0) { st->error = ret; - return -36; /* ioErr */ + return (ret == GIT_TIMEOUT) ? + errSSLNetworkTimeout : + -36 /* ioErr */; } return noErr; @@ -176,8 +178,12 @@ static ssize_t stransport_write(git_stream *stream, const char *data, size_t len GIT_UNUSED(flags); data_len = min(len, SSIZE_MAX); - if ((ret = SSLWrite(st->ctx, data, data_len, &processed)) != noErr) + if ((ret = SSLWrite(st->ctx, data, data_len, &processed)) != noErr) { + if (st->error == GIT_TIMEOUT) + return GIT_TIMEOUT; + return stransport_error(ret); + } GIT_ASSERT(processed < SSIZE_MAX); return (ssize_t)processed; @@ -207,7 +213,9 @@ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) if (ret < 0) { st->error = ret; - error = -36; /* ioErr */ + error = (ret == GIT_TIMEOUT) ? + errSSLNetworkTimeout : + -36 /* ioErr */; break; } else if (ret == 0) { error = errSSLClosedGraceful; @@ -228,6 +236,9 @@ static ssize_t stransport_read(git_stream *stream, void *data, size_t len) OSStatus ret; if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr) { + if (st->error == GIT_TIMEOUT) + return GIT_TIMEOUT; + return stransport_error(ret); } diff --git a/tests/libgit2/CMakeLists.txt b/tests/libgit2/CMakeLists.txt index 866122d1c8c..af70f55a78b 100644 --- a/tests/libgit2/CMakeLists.txt +++ b/tests/libgit2/CMakeLists.txt @@ -65,7 +65,7 @@ endif() include(AddClarTest) add_clar_test(libgit2_tests offline -v -xonline) -add_clar_test(libgit2_tests invasive -v -sfilter::stream::bigfile -sodb::largefiles -siterator::workdir::filesystem_gunk -srepo::init -srepo::init::at_filesystem_root) +add_clar_test(libgit2_tests invasive -v -sfilter::stream::bigfile -sodb::largefiles -siterator::workdir::filesystem_gunk -srepo::init -srepo::init::at_filesystem_root -sonline::clone::connect_timeout_default) add_clar_test(libgit2_tests online -v -sonline -xonline::customcert) add_clar_test(libgit2_tests online_customcert -v -sonline::customcert) add_clar_test(libgit2_tests gitdaemon -v -sonline::push) diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index b635739b676..92fa4d35133 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -35,6 +35,8 @@ static char *_remote_proxy_selfsigned = NULL; static char *_remote_expectcontinue = NULL; static char *_remote_redirect_initial = NULL; static char *_remote_redirect_subsequent = NULL; +static char *_remote_speed_timesout = NULL; +static char *_remote_speed_slow = NULL; static char *_github_ssh_pubkey = NULL; static char *_github_ssh_privkey = NULL; @@ -89,6 +91,8 @@ void test_online_clone__initialize(void) _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE"); _remote_redirect_initial = cl_getenv("GITTEST_REMOTE_REDIRECT_INITIAL"); _remote_redirect_subsequent = cl_getenv("GITTEST_REMOTE_REDIRECT_SUBSEQUENT"); + _remote_speed_timesout = cl_getenv("GITTEST_REMOTE_SPEED_TIMESOUT"); + _remote_speed_slow = cl_getenv("GITTEST_REMOTE_SPEED_SLOW"); _github_ssh_pubkey = cl_getenv("GITTEST_GITHUB_SSH_PUBKEY"); _github_ssh_privkey = cl_getenv("GITTEST_GITHUB_SSH_KEY"); @@ -128,6 +132,8 @@ void test_online_clone__cleanup(void) git__free(_remote_expectcontinue); git__free(_remote_redirect_initial); git__free(_remote_redirect_subsequent); + git__free(_remote_speed_timesout); + git__free(_remote_speed_slow); git__free(_github_ssh_pubkey); git__free(_github_ssh_privkey); @@ -145,6 +151,8 @@ void test_online_clone__cleanup(void) } git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL); + git_libgit2_opts(GIT_OPT_SET_SERVER_TIMEOUT, 0); + git_libgit2_opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, 0); } void test_online_clone__network_full(void) @@ -1207,3 +1215,55 @@ void test_online_clone__sha256(void) git_reference_free(head); #endif } + +void test_online_clone__connect_timeout_configurable(void) +{ + uint64_t start, finish; + + start = git_time_monotonic(); + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, 1)); + cl_git_fail(git_clone(&g_repo, "http://www.google.com:8000/", "./timedout", NULL)); + cl_assert(git_error_last() && strstr(git_error_last()->message, "timed out")); + + finish = git_time_monotonic(); + + cl_assert(finish - start < 1000); +} + +void test_online_clone__connect_timeout_default(void) +{ + /* This test takes ~ 75 seconds on Unix. */ + if (!cl_is_env_set("GITTEST_INVASIVE_SPEED")) + cl_skip(); + + /* + * Use a host/port pair that blackholes packets and does not + * send an RST. + */ + cl_git_fail_with(GIT_TIMEOUT, git_clone(&g_repo, "http://www.google.com:8000/", "./refused", NULL)); + cl_assert(git_error_last() && strstr(git_error_last()->message, "timed out")); +} + +void test_online_clone__timeout_configurable_times_out(void) +{ + git_repository *failed_repo; + + if (!_remote_speed_timesout) + cl_skip(); + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SERVER_TIMEOUT, 1000)); + + cl_git_fail_with(GIT_TIMEOUT, git_clone(&failed_repo, _remote_speed_timesout, "./timedout", NULL)); + cl_assert(git_error_last() && strstr(git_error_last()->message, "timed out")); +} + +void test_online_clone__timeout_configurable_succeeds_slowly(void) +{ + if (!_remote_speed_slow) + cl_skip(); + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SERVER_TIMEOUT, 1000)); + + cl_git_pass(git_clone(&g_repo, _remote_speed_slow, "./slow-but-successful", NULL)); +} From 94f98400bf950aa9835ff9b04c724f2aa3ebd0fc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:31 +0100 Subject: [PATCH 189/816] posix: introduce p_poll emulation with select Not all systems have poll(2); emulate it with select(2). --- src/CMakeLists.txt | 5 ++++ src/libgit2/streams/socket.c | 9 +++--- src/util/git2_features.h.in | 3 ++ src/util/posix.c | 54 ++++++++++++++++++++++++++++++++++++ src/util/posix.h | 19 +++++++++++++ 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88d616cec1f..a00ab600a2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,6 +87,11 @@ check_prototype_definition_safe(qsort_s check_function_exists(getentropy GIT_RAND_GETENTROPY) check_function_exists(getloadavg GIT_RAND_GETLOADAVG) +# poll + +check_symbol_exists(poll poll.h GIT_IO_POLL) +check_symbol_exists(select sys/select.h GIT_IO_SELECT) + # determine architecture of the machine if(CMAKE_SIZEOF_VOID_P EQUAL 8) diff --git a/src/libgit2/streams/socket.c b/src/libgit2/streams/socket.c index 0e0aa69349b..ecbdf7b7d6d 100644 --- a/src/libgit2/streams/socket.c +++ b/src/libgit2/streams/socket.c @@ -20,7 +20,6 @@ # include # include # include -# include #else # include # include @@ -135,13 +134,13 @@ static int connect_with_timeout( fd.events = POLLOUT; fd.revents = 0; - error = poll(&fd, 1, timeout); + error = p_poll(&fd, 1, timeout); if (error == 0) { return GIT_TIMEOUT; } else if (error != 1) { return -1; - } else if ((fd.revents & (POLLHUP | POLLERR))) { + } else if ((fd.revents & (POLLPRI | POLLHUP | POLLERR))) { return handle_sockerr(socket); } else if ((fd.revents & POLLOUT) != POLLOUT) { git_error_set(GIT_ERROR_NET, @@ -236,7 +235,7 @@ static ssize_t socket_write( fd.events = POLLOUT; fd.revents = 0; - ret = poll(&fd, 1, st->parent.timeout); + ret = p_poll(&fd, 1, st->parent.timeout); if (ret == 1) { ret = p_send(st->s, data, len, 0); @@ -272,7 +271,7 @@ static ssize_t socket_read( fd.events = POLLIN; fd.revents = 0; - ret = poll(&fd, 1, st->parent.timeout); + ret = p_poll(&fd, 1, st->parent.timeout); if (ret == 1) { ret = p_recv(st->s, data, len, 0); diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 18644c3ccfc..cf955122c2b 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -61,4 +61,7 @@ #cmakedefine GIT_RAND_GETENTROPY 1 #cmakedefine GIT_RAND_GETLOADAVG 1 +#cmakedefine GIT_IO_POLL 1 +#cmakedefine GIT_IO_SELECT 1 + #endif diff --git a/src/util/posix.c b/src/util/posix.c index b1f85dc9412..cfc0e0751be 100644 --- a/src/util/posix.c +++ b/src/util/posix.c @@ -301,3 +301,57 @@ int p_munmap(git_map *map) } #endif + +#if defined(GIT_IO_POLL) || defined(GIT_IO_WSAPOLL) + +/* Handled by posix.h; this test simplifies the final else */ + +#elif defined(GIT_IO_SELECT) + +int p_poll(struct pollfd *fds, unsigned int nfds, int timeout_ms) +{ + fd_set read_fds, write_fds, except_fds; + struct timeval timeout = { 0, 0 }; + unsigned int i; + int max_fd = -1, ret; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_ZERO(&except_fds); + + for (i = 0; i < nfds; i++) { + if ((fds[i].events & POLLIN)) + FD_SET(fds[i].fd, &read_fds); + + if ((fds[i].events & POLLOUT)) + FD_SET(fds[i].fd, &write_fds); + + if ((fds[i].events & POLLPRI)) + FD_SET(fds[i].fd, &except_fds); + + max_fd = MAX(max_fd, fds[i].fd); + } + + if (timeout_ms > 0) { + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + } + + if ((ret = select(max_fd + 1, &read_fds, &write_fds, &except_fds, + timeout_ms < 0 ? NULL : &timeout)) < 0) + goto done; + + for (i = 0; i < nfds; i++) { + fds[i].revents = 0 | + FD_ISSET(fds[i].fd, &read_fds) ? POLLIN : 0 | + FD_ISSET(fds[i].fd, &write_fds) ? POLLOUT : 0 | + FD_ISSET(fds[i].fd, &except_fds) ? POLLPRI : 0; + } + +done: + return ret; +} + +#else +# error no poll compatible implementation +#endif diff --git a/src/util/posix.h b/src/util/posix.h index 607aa9dceb3..f516bb3ccd1 100644 --- a/src/util/posix.h +++ b/src/util/posix.h @@ -195,4 +195,23 @@ extern const char *p_gai_strerror(int ret); # define p_gai_strerror(c) gai_strerror(c) #endif /* NO_ADDRINFO */ +#ifdef GIT_IO_POLL +# include +# define p_poll poll +#else +# define POLLIN 0x01 +# define POLLPRI 0x02 +# define POLLOUT 0x04 +# define POLLERR 0x08 +# define POLLHUP 0x10 + +struct pollfd { + int fd; + short events; + short revents; +}; + +extern int p_poll(struct pollfd *fds, unsigned int nfds, int timeout); +#endif + #endif From 9908c076ab3fafa18f00c866840819d52bc6b00f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:31 +0100 Subject: [PATCH 190/816] posix: use WSAPoll on win32 --- src/CMakeLists.txt | 8 ++++++-- src/util/git2_features.h.in | 1 + src/util/posix.h | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a00ab600a2b..e9de94b52aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,8 +89,12 @@ check_function_exists(getloadavg GIT_RAND_GETLOADAVG) # poll -check_symbol_exists(poll poll.h GIT_IO_POLL) -check_symbol_exists(select sys/select.h GIT_IO_SELECT) +if(WIN32) + set(GIT_IO_WSAPOLL 1) +else() + check_symbol_exists(poll poll.h GIT_IO_POLL) + check_symbol_exists(select sys/select.h GIT_IO_SELECT) +endif() # determine architecture of the machine diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index cf955122c2b..a84ea895635 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -62,6 +62,7 @@ #cmakedefine GIT_RAND_GETLOADAVG 1 #cmakedefine GIT_IO_POLL 1 +#cmakedefine GIT_IO_WSAPOLL 1 #cmakedefine GIT_IO_SELECT 1 #endif diff --git a/src/util/posix.h b/src/util/posix.h index f516bb3ccd1..74707453a6d 100644 --- a/src/util/posix.h +++ b/src/util/posix.h @@ -198,6 +198,9 @@ extern const char *p_gai_strerror(int ret); #ifdef GIT_IO_POLL # include # define p_poll poll +#elif GIT_IO_WSAPOLL +# include +# define p_poll WSAPoll #else # define POLLIN 0x01 # define POLLPRI 0x02 From 02ab53ce051df9a6b70b8f075956ed3a41f9979e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:31 +0100 Subject: [PATCH 191/816] cmake: use `check_symbol_exists` for rand functions `check_symbol_exists` is superior to `check_function_exists`; use it consistently in our cmake configuration --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e9de94b52aa..8525acdd803 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,8 +84,8 @@ check_prototype_definition_safe(qsort_s # random / entropy data -check_function_exists(getentropy GIT_RAND_GETENTROPY) -check_function_exists(getloadavg GIT_RAND_GETLOADAVG) +check_symbol_exists(getentropy unistd.h GIT_RAND_GETENTROPY) +check_symbol_exists(getloadavg stdlib.h GIT_RAND_GETLOADAVG) # poll From 03eebab8a9fc353e96b2f6932d28defd5d868bca Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:32 +0100 Subject: [PATCH 192/816] win32: getsockopt takes a `char *` instead of a `void *` Monsters. --- src/libgit2/streams/socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libgit2/streams/socket.c b/src/libgit2/streams/socket.c index ecbdf7b7d6d..3bfc3fd0f95 100644 --- a/src/libgit2/streams/socket.c +++ b/src/libgit2/streams/socket.c @@ -103,7 +103,8 @@ static int handle_sockerr(GIT_SOCKET socket) int sockerr; socklen_t errlen = sizeof(sockerr); - if (getsockopt(socket, SOL_SOCKET, SO_ERROR, &sockerr, &errlen) < 0) + if (getsockopt(socket, SOL_SOCKET, SO_ERROR, + (void *)&sockerr, &errlen) < 0) return -1; if (sockerr == ETIMEDOUT) From 14c820b191a7083bf9a54792e09afcd83e0f0206 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 11 Apr 2023 20:55:22 +0100 Subject: [PATCH 193/816] win32: use WSAGetLastError to determine blocking --- src/libgit2/streams/socket.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libgit2/streams/socket.c b/src/libgit2/streams/socket.c index 3bfc3fd0f95..a463312fd85 100644 --- a/src/libgit2/streams/socket.c +++ b/src/libgit2/streams/socket.c @@ -114,6 +114,19 @@ static int handle_sockerr(GIT_SOCKET socket) return -1; } +GIT_INLINE(bool) connect_would_block(int error) +{ +#ifdef GIT_WIN32 + if (error == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + return true; +#endif + + if (error == -1 && errno == EINPROGRESS) + return true; + + return false; +} + static int connect_with_timeout( GIT_SOCKET socket, const struct sockaddr *address, @@ -128,7 +141,7 @@ static int connect_with_timeout( error = connect(socket, address, address_len); - if (error == 0 || (error == -1 && errno != EINPROGRESS)) + if (error == 0 || !connect_would_block(error)) return error; fd.fd = socket; From 8f695c806bac2b044f102c55b802e44f2d30ca01 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 11 Apr 2023 20:59:30 +0100 Subject: [PATCH 194/816] clone: skip timeout tests on WinHTTP --- tests/libgit2/online/clone.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 92fa4d35133..dbcac50ae6e 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -1218,6 +1218,9 @@ void test_online_clone__sha256(void) void test_online_clone__connect_timeout_configurable(void) { +#ifdef GIT_WINHTTP + cl_skip(); +#else uint64_t start, finish; start = git_time_monotonic(); @@ -1229,10 +1232,14 @@ void test_online_clone__connect_timeout_configurable(void) finish = git_time_monotonic(); cl_assert(finish - start < 1000); +#endif } void test_online_clone__connect_timeout_default(void) { +#ifdef GIT_WINHTTP + cl_skip(); +#else /* This test takes ~ 75 seconds on Unix. */ if (!cl_is_env_set("GITTEST_INVASIVE_SPEED")) cl_skip(); @@ -1243,10 +1250,14 @@ void test_online_clone__connect_timeout_default(void) */ cl_git_fail_with(GIT_TIMEOUT, git_clone(&g_repo, "http://www.google.com:8000/", "./refused", NULL)); cl_assert(git_error_last() && strstr(git_error_last()->message, "timed out")); +#endif } void test_online_clone__timeout_configurable_times_out(void) { +#ifdef GIT_WINHTTP + cl_skip(); +#else git_repository *failed_repo; if (!_remote_speed_timesout) @@ -1256,14 +1267,19 @@ void test_online_clone__timeout_configurable_times_out(void) cl_git_fail_with(GIT_TIMEOUT, git_clone(&failed_repo, _remote_speed_timesout, "./timedout", NULL)); cl_assert(git_error_last() && strstr(git_error_last()->message, "timed out")); +#endif } void test_online_clone__timeout_configurable_succeeds_slowly(void) { +#ifdef GIT_WINHTTP + cl_skip(); +#else if (!_remote_speed_slow) cl_skip(); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SERVER_TIMEOUT, 1000)); cl_git_pass(git_clone(&g_repo, _remote_speed_slow, "./slow-but-successful", NULL)); +#endif } From 9dd1bfe81c3aba6ce35ed85bf62fa75d9c61e1a6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 14 May 2023 14:07:59 +0100 Subject: [PATCH 195/816] alloc: simplify pluggable allocators Remove the number of functions that custom allocator users need to provide; nobody should need to implement `substrdup`. Keep it to the basics that are actually _needed_ for allocation (malloc, realloc, free) and reimplement the rest ourselves. In addition, move the failure check and error setting _out_ of the custom allocators and into a wrapper so that users don't need to deal with this. This also allows us to call our allocator (without the wrapper) early so that it does not try to set an error on failure, which may be important for bootstrapping. --- include/git2/sys/alloc.h | 34 -------- src/util/alloc.c | 71 +++++++++++++++-- src/util/alloc.h | 43 ++++++++--- src/util/allocators/failalloc.c | 60 --------------- src/util/allocators/failalloc.h | 6 -- src/util/allocators/stdalloc.c | 107 +------------------------- src/util/allocators/win32_leakcheck.c | 68 ---------------- 7 files changed, 101 insertions(+), 288 deletions(-) diff --git a/include/git2/sys/alloc.h b/include/git2/sys/alloc.h index c295807bcf2..e7f85b890c8 100644 --- a/include/git2/sys/alloc.h +++ b/include/git2/sys/alloc.h @@ -24,28 +24,6 @@ typedef struct { /** Allocate `n` bytes of memory */ void * GIT_CALLBACK(gmalloc)(size_t n, const char *file, int line); - /** - * Allocate memory for an array of `nelem` elements, where each element - * has a size of `elsize`. Returned memory shall be initialized to - * all-zeroes - */ - void * GIT_CALLBACK(gcalloc)(size_t nelem, size_t elsize, const char *file, int line); - - /** Allocate memory for the string `str` and duplicate its contents. */ - char * GIT_CALLBACK(gstrdup)(const char *str, const char *file, int line); - - /** - * Equivalent to the `gstrdup` function, but only duplicating at most - * `n + 1` bytes - */ - char * GIT_CALLBACK(gstrndup)(const char *str, size_t n, const char *file, int line); - - /** - * Equivalent to `gstrndup`, but will always duplicate exactly `n` bytes - * of `str`. Thus, out of bounds reads at `str` may happen. - */ - char * GIT_CALLBACK(gsubstrdup)(const char *str, size_t n, const char *file, int line); - /** * This function shall deallocate the old object `ptr` and return a * pointer to a new object that has the size specified by `size`. In @@ -53,18 +31,6 @@ typedef struct { */ void * GIT_CALLBACK(grealloc)(void *ptr, size_t size, const char *file, int line); - /** - * This function shall be equivalent to `grealloc`, but allocating - * `neleme * elsize` bytes. - */ - void * GIT_CALLBACK(greallocarray)(void *ptr, size_t nelem, size_t elsize, const char *file, int line); - - /** - * This function shall allocate a new array of `nelem` elements, where - * each element has a size of `elsize` bytes. - */ - void * GIT_CALLBACK(gmallocarray)(size_t nelem, size_t elsize, const char *file, int line); - /** * This function shall free the memory pointed to by `ptr`. In case * `ptr` is `NULL`, this shall be a no-op. diff --git a/src/util/alloc.c b/src/util/alloc.c index 2820d84a219..6ec173d04a4 100644 --- a/src/util/alloc.c +++ b/src/util/alloc.c @@ -15,16 +15,75 @@ /* Fail any allocation until git_libgit2_init is called. */ git_allocator git__allocator = { git_failalloc_malloc, - git_failalloc_calloc, - git_failalloc_strdup, - git_failalloc_strndup, - git_failalloc_substrdup, git_failalloc_realloc, - git_failalloc_reallocarray, - git_failalloc_mallocarray, git_failalloc_free }; +void *git__calloc(size_t nelem, size_t elsize) +{ + size_t newsize; + void *ptr; + + if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) + return NULL; + + if ((ptr = git__malloc(newsize))) + memset(ptr, 0, newsize); + + return ptr; +} + +void *git__reallocarray(void *ptr, size_t nelem, size_t elsize) +{ + size_t newsize; + + if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) + return NULL; + + return git__realloc(ptr, newsize); +} + +void *git__mallocarray(size_t nelem, size_t elsize) +{ + return git__reallocarray(NULL, nelem, elsize); +} + +char *git__strdup(const char *str) +{ + size_t len = strlen(str) + 1; + void *ptr = git__malloc(len); + + if (ptr) + memcpy(ptr, str, len); + + return ptr; +} + +char *git__strndup(const char *str, size_t n) +{ + size_t len = p_strnlen(str, n); + char *ptr = git__malloc(len + 1); + + if (ptr) { + memcpy(ptr, str, len); + ptr[len] = '\0'; + } + + return ptr; +} + +char *git__substrdup(const char *str, size_t n) +{ + char *ptr = git__malloc(n + 1); + + if (ptr) { + memcpy(ptr, str, n); + ptr[n] = '\0'; + } + + return ptr; +} + static int setup_default_allocator(void) { #if defined(GIT_WIN32_LEAKCHECK) diff --git a/src/util/alloc.h b/src/util/alloc.h index 04fb7e10175..32b614b25cc 100644 --- a/src/util/alloc.h +++ b/src/util/alloc.h @@ -10,17 +10,42 @@ #include "git2/sys/alloc.h" +#include "git2_util.h" + extern git_allocator git__allocator; -#define git__malloc(len) git__allocator.gmalloc(len, __FILE__, __LINE__) -#define git__calloc(nelem, elsize) git__allocator.gcalloc(nelem, elsize, __FILE__, __LINE__) -#define git__strdup(str) git__allocator.gstrdup(str, __FILE__, __LINE__) -#define git__strndup(str, n) git__allocator.gstrndup(str, n, __FILE__, __LINE__) -#define git__substrdup(str, n) git__allocator.gsubstrdup(str, n, __FILE__, __LINE__) -#define git__realloc(ptr, size) git__allocator.grealloc(ptr, size, __FILE__, __LINE__) -#define git__reallocarray(ptr, nelem, elsize) git__allocator.greallocarray(ptr, nelem, elsize, __FILE__, __LINE__) -#define git__mallocarray(nelem, elsize) git__allocator.gmallocarray(nelem, elsize, __FILE__, __LINE__) -#define git__free git__allocator.gfree +GIT_INLINE(void *) git__malloc(size_t len) +{ + void *p = git__allocator.gmalloc(len, __FILE__, __LINE__); + + if (!p) + git_error_set_oom(); + + return p; +} + +GIT_INLINE(void *) git__realloc(void *ptr, size_t size) +{ + void *p = git__allocator.grealloc(ptr, size, __FILE__, __LINE__); + + if (!p) + git_error_set_oom(); + + return p; +} + +GIT_INLINE(void) git__free(void *ptr) +{ + git__allocator.gfree(ptr); +} + +extern void *git__calloc(size_t nelem, size_t elsize); +extern void *git__mallocarray(size_t nelem, size_t elsize); +extern void *git__reallocarray(void *ptr, size_t nelem, size_t elsize); + +extern char *git__strdup(const char *str); +extern char *git__strndup(const char *str, size_t n); +extern char *git__substrdup(const char *str, size_t n); /** * This function is being called by our global setup routines to diff --git a/src/util/allocators/failalloc.c b/src/util/allocators/failalloc.c index 5257d1dece0..c1025e32fef 100644 --- a/src/util/allocators/failalloc.c +++ b/src/util/allocators/failalloc.c @@ -16,45 +16,6 @@ void *git_failalloc_malloc(size_t len, const char *file, int line) return NULL; } -void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line) -{ - GIT_UNUSED(nelem); - GIT_UNUSED(elsize); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -char *git_failalloc_strdup(const char *str, const char *file, int line) -{ - GIT_UNUSED(str); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line) -{ - GIT_UNUSED(str); - GIT_UNUSED(n); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line) -{ - GIT_UNUSED(start); - GIT_UNUSED(n); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line) { GIT_UNUSED(ptr); @@ -65,27 +26,6 @@ void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line) return NULL; } -void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line) -{ - GIT_UNUSED(ptr); - GIT_UNUSED(nelem); - GIT_UNUSED(elsize); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line) -{ - GIT_UNUSED(nelem); - GIT_UNUSED(elsize); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - void git_failalloc_free(void *ptr) { GIT_UNUSED(ptr); diff --git a/src/util/allocators/failalloc.h b/src/util/allocators/failalloc.h index 91264a0bb91..a3788e634ee 100644 --- a/src/util/allocators/failalloc.h +++ b/src/util/allocators/failalloc.h @@ -11,13 +11,7 @@ #include "git2_util.h" extern void *git_failalloc_malloc(size_t len, const char *file, int line); -extern void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line); -extern char *git_failalloc_strdup(const char *str, const char *file, int line); -extern char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line); -extern char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line); extern void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line); -extern void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line); -extern void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line); extern void git_failalloc_free(void *ptr); #endif diff --git a/src/util/allocators/stdalloc.c b/src/util/allocators/stdalloc.c index 2b36d9f3df3..f2d72a7e6c9 100644 --- a/src/util/allocators/stdalloc.c +++ b/src/util/allocators/stdalloc.c @@ -9,8 +9,6 @@ static void *stdalloc__malloc(size_t len, const char *file, int line) { - void *ptr; - GIT_UNUSED(file); GIT_UNUSED(line); @@ -19,86 +17,11 @@ static void *stdalloc__malloc(size_t len, const char *file, int line) return NULL; #endif - ptr = malloc(len); - - if (!ptr) - git_error_set_oom(); - - return ptr; -} - -static void *stdalloc__calloc(size_t nelem, size_t elsize, const char *file, int line) -{ - void *ptr; - - GIT_UNUSED(file); - GIT_UNUSED(line); - -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!elsize || !nelem) - return NULL; -#endif - - ptr = calloc(nelem, elsize); - - if (!ptr) - git_error_set_oom(); - - return ptr; -} - -static char *stdalloc__strdup(const char *str, const char *file, int line) -{ - char *ptr; - - GIT_UNUSED(file); - GIT_UNUSED(line); - - ptr = strdup(str); - - if (!ptr) - git_error_set_oom(); - - return ptr; -} - -static char *stdalloc__strndup(const char *str, size_t n, const char *file, int line) -{ - size_t length = 0, alloclength; - char *ptr; - - length = p_strnlen(str, n); - - if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) || - !(ptr = stdalloc__malloc(alloclength, file, line))) - return NULL; - - if (length) - memcpy(ptr, str, length); - - ptr[length] = '\0'; - - return ptr; -} - -static char *stdalloc__substrdup(const char *start, size_t n, const char *file, int line) -{ - char *ptr; - size_t alloclen; - - if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) || - !(ptr = stdalloc__malloc(alloclen, file, line))) - return NULL; - - memcpy(ptr, start, n); - ptr[n] = '\0'; - return ptr; + return malloc(len); } static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line) { - void *new_ptr; - GIT_UNUSED(file); GIT_UNUSED(line); @@ -107,27 +30,7 @@ static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int lin return NULL; #endif - new_ptr = realloc(ptr, size); - - if (!new_ptr) - git_error_set_oom(); - - return new_ptr; -} - -static void *stdalloc__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line) -{ - size_t newsize; - - if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) - return NULL; - - return stdalloc__realloc(ptr, newsize, file, line); -} - -static void *stdalloc__mallocarray(size_t nelem, size_t elsize, const char *file, int line) -{ - return stdalloc__reallocarray(NULL, nelem, elsize, file, line); + return realloc(ptr, size); } static void stdalloc__free(void *ptr) @@ -138,13 +41,7 @@ static void stdalloc__free(void *ptr) int git_stdalloc_init_allocator(git_allocator *allocator) { allocator->gmalloc = stdalloc__malloc; - allocator->gcalloc = stdalloc__calloc; - allocator->gstrdup = stdalloc__strdup; - allocator->gstrndup = stdalloc__strndup; - allocator->gsubstrdup = stdalloc__substrdup; allocator->grealloc = stdalloc__realloc; - allocator->greallocarray = stdalloc__reallocarray; - allocator->gmallocarray = stdalloc__mallocarray; allocator->gfree = stdalloc__free; return 0; } diff --git a/src/util/allocators/win32_leakcheck.c b/src/util/allocators/win32_leakcheck.c index fe06a14af73..cdf16d34880 100644 --- a/src/util/allocators/win32_leakcheck.c +++ b/src/util/allocators/win32_leakcheck.c @@ -18,53 +18,6 @@ static void *leakcheck_malloc(size_t len, const char *file, int line) return ptr; } -static void *leakcheck_calloc(size_t nelem, size_t elsize, const char *file, int line) -{ - void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); - if (!ptr) git_error_set_oom(); - return ptr; -} - -static char *leakcheck_strdup(const char *str, const char *file, int line) -{ - char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); - if (!ptr) git_error_set_oom(); - return ptr; -} - -static char *leakcheck_strndup(const char *str, size_t n, const char *file, int line) -{ - size_t length = 0, alloclength; - char *ptr; - - length = p_strnlen(str, n); - - if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) || - !(ptr = leakcheck_malloc(alloclength, file, line))) - return NULL; - - if (length) - memcpy(ptr, str, length); - - ptr[length] = '\0'; - - return ptr; -} - -static char *leakcheck_substrdup(const char *start, size_t n, const char *file, int line) -{ - char *ptr; - size_t alloclen; - - if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) || - !(ptr = leakcheck_malloc(alloclen, file, line))) - return NULL; - - memcpy(ptr, start, n); - ptr[n] = '\0'; - return ptr; -} - static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int line) { void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); @@ -72,21 +25,6 @@ static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int lin return new_ptr; } -static void *leakcheck_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line) -{ - size_t newsize; - - if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) - return NULL; - - return leakcheck_realloc(ptr, newsize, file, line); -} - -static void *leakcheck_mallocarray(size_t nelem, size_t elsize, const char *file, int line) -{ - return leakcheck_reallocarray(NULL, nelem, elsize, file, line); -} - static void leakcheck_free(void *ptr) { free(ptr); @@ -95,13 +33,7 @@ static void leakcheck_free(void *ptr) int git_win32_leakcheck_init_allocator(git_allocator *allocator) { allocator->gmalloc = leakcheck_malloc; - allocator->gcalloc = leakcheck_calloc; - allocator->gstrdup = leakcheck_strdup; - allocator->gstrndup = leakcheck_strndup; - allocator->gsubstrdup = leakcheck_substrdup; allocator->grealloc = leakcheck_realloc; - allocator->greallocarray = leakcheck_reallocarray; - allocator->gmallocarray = leakcheck_mallocarray; allocator->gfree = leakcheck_free; return 0; } From 90cc07711c43b12a4bb270583026cbc71db3823e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 11 Oct 2019 10:57:28 +0200 Subject: [PATCH 196/816] tests: add allocator with limited number of bytes In several circumstances, we get bug reports about things that happen in situations where the environment is quite limited with regards to available memory. While it's expected that functionality will fail if memory allocations fail, the assumption is that we should do so in a controlled way. Most importantly, we do not want to crash hard due to e.g. accessing NULL pointers. Naturally, it is quite hard to debug such situations. But since our addition of pluggable allocators, we are able to implement allocators that fail in deterministic ways, e.g. after a certain amount of bytes has been allocated. This commit does exactly that. To be able to properly keep track of the amount of bytes currently allocated, allocated pointers contain tracking information. This tracking information is currently limited to the number of bytes allocated, so that we can correctly replenish them on calling `free` on the pointer. In the future, it would be feasible to extend the tracked information even further, e.g. by adding information about file and line where the allocation has been performed. As this introduced some overhead to allocations though, only information essential to limited allocations is currently tracked. --- src/libgit2/threadstate.c | 17 ++++- tests/clar/clar_libgit2_alloc.c | 106 ++++++++++++++++++++++++++++++++ tests/clar/clar_libgit2_alloc.h | 11 ++++ tests/util/alloc.c | 68 ++++++++++++++++++++ 4 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 tests/clar/clar_libgit2_alloc.c create mode 100644 tests/clar/clar_libgit2_alloc.h create mode 100644 tests/util/alloc.c diff --git a/src/libgit2/threadstate.c b/src/libgit2/threadstate.c index 9e3ef581849..ed9bb9b96ff 100644 --- a/src/libgit2/threadstate.c +++ b/src/libgit2/threadstate.c @@ -75,10 +75,23 @@ git_threadstate *git_threadstate_get(void) if ((threadstate = git_tlsdata_get(tls_key)) != NULL) return threadstate; - if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL || - git_str_init(&threadstate->error_buf, 0) < 0) + /* + * Avoid git__malloc here, since if it fails, it sets an error + * message, which requires thread state, which would allocate + * here, which would fail, which would set an error message... + */ + + if ((threadstate = git__allocator.gmalloc(sizeof(git_threadstate), + __FILE__, __LINE__)) == NULL) return NULL; + memset(threadstate, 0, sizeof(git_threadstate)); + + if (git_str_init(&threadstate->error_buf, 0) < 0) { + git__allocator.gfree(threadstate); + return NULL; + } + git_tlsdata_set(tls_key, threadstate); return threadstate; } diff --git a/tests/clar/clar_libgit2_alloc.c b/tests/clar/clar_libgit2_alloc.c new file mode 100644 index 00000000000..7abc998cea0 --- /dev/null +++ b/tests/clar/clar_libgit2_alloc.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "clar_libgit2_alloc.h" + +static size_t bytes_available; + +/* + * The clar allocator uses a tagging mechanism for pointers that + * prepends the actual pointer's number bytes as `size_t`. + * + * First, this is required in order to be able to implement + * proper bookkeeping of allocated bytes in both `free` and + * `realloc`. + * + * Second, it may also be able to spot bugs that are + * otherwise hard to grasp, as the returned pointer cannot be + * free'd directly via free(3P). Instead, one is forced to use + * the tandem of `cl__malloc` and `cl__free`, as otherwise the + * code is going to crash hard. This is considered to be a + * feature, as it helps e.g. in finding cases where by accident + * malloc(3P) and free(3P) were used instead of git__malloc and + * git__free, respectively. + * + * The downside is obviously that each allocation grows by + * sizeof(size_t) bytes. As the allocator is for testing purposes + * only, this tradeoff is considered to be perfectly fine, + * though. + */ + +static void *cl__malloc(size_t len, const char *file, int line) +{ + char *ptr = NULL; + size_t alloclen; + + GIT_UNUSED(file); + GIT_UNUSED(line); + + if (len > bytes_available) + goto out; + + if (GIT_ADD_SIZET_OVERFLOW(&alloclen, len, sizeof(size_t)) || + (ptr = malloc(alloclen)) == NULL) + goto out; + memcpy(ptr, &len, sizeof(size_t)); + + bytes_available -= len; + +out: + return ptr ? ptr + sizeof(size_t) : NULL; +} + +static void cl__free(void *ptr) +{ + if (ptr) { + char *p = ptr; + size_t len; + memcpy(&len, p - sizeof(size_t), sizeof(size_t)); + free(p - sizeof(size_t)); + bytes_available += len; + } +} + +static void *cl__realloc(void *ptr, size_t size, const char *file, int line) +{ + size_t copybytes = 0; + char *p = ptr; + void *new; + + if (p) + memcpy(©bytes, p - sizeof(size_t), sizeof(size_t)); + if (copybytes > size) + copybytes = size; + + if ((new = cl__malloc(size, file, line)) == NULL) + goto out; + memcpy(new, p, copybytes); + cl__free(p); + +out: + return new; +} + +void cl_alloc_limit(size_t bytes) +{ + git_allocator alloc; + + alloc.gmalloc = cl__malloc; + alloc.grealloc = cl__realloc; + alloc.gfree = cl__free; + + git_allocator_setup(&alloc); + + bytes_available = bytes; +} + +void cl_alloc_reset(void) +{ + git_allocator stdalloc; + git_stdalloc_init_allocator(&stdalloc); + git_allocator_setup(&stdalloc); +} diff --git a/tests/clar/clar_libgit2_alloc.h b/tests/clar/clar_libgit2_alloc.h new file mode 100644 index 00000000000..78a18b67d16 --- /dev/null +++ b/tests/clar/clar_libgit2_alloc.h @@ -0,0 +1,11 @@ +#ifndef __CLAR_LIBGIT2_ALLOC__ +#define __CLAR_LIBGIT2_ALLOC__ + +#include "clar.h" +#include "common.h" +#include "git2/sys/alloc.h" + +void cl_alloc_limit(size_t bytes); +void cl_alloc_reset(void); + +#endif diff --git a/tests/util/alloc.c b/tests/util/alloc.c new file mode 100644 index 00000000000..492394a52c0 --- /dev/null +++ b/tests/util/alloc.c @@ -0,0 +1,68 @@ +#include "clar_libgit2.h" +#include "clar_libgit2_alloc.h" +#include "alloc.h" + +void test_alloc__cleanup(void) +{ + cl_alloc_reset(); +} + +void test_alloc__oom(void) +{ + void *ptr = NULL; + + cl_alloc_limit(0); + + cl_assert(git__malloc(1) == NULL); + cl_assert(git__calloc(1, 1) == NULL); + cl_assert(git__realloc(ptr, 1) == NULL); + cl_assert(git__strdup("test") == NULL); + cl_assert(git__strndup("test", 4) == NULL); +} + +void test_alloc__single_byte_is_exhausted(void) +{ + void *ptr; + + cl_alloc_limit(1); + + cl_assert(ptr = git__malloc(1)); + cl_assert(git__malloc(1) == NULL); + git__free(ptr); +} + +void test_alloc__free_replenishes_byte(void) +{ + void *ptr; + + cl_alloc_limit(1); + + cl_assert(ptr = git__malloc(1)); + cl_assert(git__malloc(1) == NULL); + git__free(ptr); + cl_assert(ptr = git__malloc(1)); + git__free(ptr); +} + +void test_alloc__realloc(void) +{ + char *ptr = NULL; + + cl_alloc_limit(3); + + cl_assert(ptr = git__realloc(ptr, 1)); + *ptr = 'x'; + + cl_assert(ptr = git__realloc(ptr, 1)); + cl_assert_equal_i(*ptr, 'x'); + + cl_assert(ptr = git__realloc(ptr, 2)); + cl_assert_equal_i(*ptr, 'x'); + + cl_assert(git__realloc(ptr, 2) == NULL); + + cl_assert(ptr = git__realloc(ptr, 1)); + cl_assert_equal_i(*ptr, 'x'); + + git__free(ptr); +} From 8e5281c88b860cce7a6a2f4a00c28b6fb00720b0 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 11 Oct 2019 11:38:14 +0200 Subject: [PATCH 197/816] tests: add allocation failure test for buffers Test that `git_buf` correctly fails if no more bytes can be allocated. This is mostly for demonstration purposes. --- tests/util/str/oom.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/util/str/oom.c b/tests/util/str/oom.c index dd3796674f6..810c1f25a7a 100644 --- a/tests/util/str/oom.c +++ b/tests/util/str/oom.c @@ -1,4 +1,5 @@ #include "clar_libgit2.h" +#include "clar_libgit2_alloc.h" /* Override default allocators with ones that will fail predictably. */ @@ -56,3 +57,15 @@ void test_str_oom__grow_by(void) cl_assert(git_str_grow_by(&buf, 101) == -1); cl_assert(git_str_oom(&buf)); } + +void test_str_oom__allocation_failure(void) +{ + git_str buf = GIT_STR_INIT; + + cl_alloc_limit(10); + + cl_git_pass(git_str_puts(&buf, "foobar")); + cl_git_fail(git_str_puts(&buf, "foobar")); + + cl_alloc_reset(); +} From 27576416206f696edb16cf2e22271953903e731f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 15 May 2023 11:04:37 +0100 Subject: [PATCH 198/816] tests: only copy when `ptr` is non-NULL Avoid passing a `NULL` ptr to `memcpy` -- that's UB (even if size is 0) --- tests/clar/clar_libgit2_alloc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/clar/clar_libgit2_alloc.c b/tests/clar/clar_libgit2_alloc.c index 7abc998cea0..e9303792382 100644 --- a/tests/clar/clar_libgit2_alloc.c +++ b/tests/clar/clar_libgit2_alloc.c @@ -73,13 +73,17 @@ static void *cl__realloc(void *ptr, size_t size, const char *file, int line) if (p) memcpy(©bytes, p - sizeof(size_t), sizeof(size_t)); + if (copybytes > size) copybytes = size; if ((new = cl__malloc(size, file, line)) == NULL) goto out; - memcpy(new, p, copybytes); - cl__free(p); + + if (p) { + memcpy(new, p, copybytes); + cl__free(p); + } out: return new; From 0fd80681f90ae23d5a74b469fefd3409d924ddae Mon Sep 17 00:00:00 2001 From: Reginald McLean Date: Tue, 24 Nov 2020 18:32:50 -0500 Subject: [PATCH 199/816] Added missing is_prunable test --- tests/libgit2/worktree/worktree.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/libgit2/worktree/worktree.c b/tests/libgit2/worktree/worktree.c index 9fd27f49c5f..fed5c9259ca 100644 --- a/tests/libgit2/worktree/worktree.c +++ b/tests/libgit2/worktree/worktree.c @@ -645,3 +645,16 @@ void test_worktree_worktree__validate_invalid_worktreedir(void) git_worktree_free(wt); } + +void test_worktree_worktree__is_prunable_missing_repo(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + p_rename("testrepo", "testrepo-tmp"); + /* Should not be prunable since the repository moved */ + cl_assert(!git_worktree_is_prunable(wt, NULL)); + p_rename("testrepo-tmp", "testrepo"); + + git_worktree_free(wt); +} From 86db1ad5dc9d878f463ac6c9d5ee412b62b74340 Mon Sep 17 00:00:00 2001 From: Reginald McLean Date: Tue, 24 Nov 2020 18:45:55 -0500 Subject: [PATCH 200/816] Added check if gitdir exists in is_prunable() Fixes #5598 --- src/libgit2/worktree.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libgit2/worktree.c b/src/libgit2/worktree.c index 82e1d2d7e18..a8460380ff9 100644 --- a/src/libgit2/worktree.c +++ b/src/libgit2/worktree.c @@ -565,6 +565,7 @@ int git_worktree_is_prunable(git_worktree *wt, git_worktree_prune_options *opts) { git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_buf path = GIT_BUF_INIT; GIT_ERROR_CHECK_VERSION( opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, @@ -595,6 +596,14 @@ int git_worktree_is_prunable(git_worktree *wt, return 0; } + if (git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name) < 0) + return 0; + if (!git_path_exists(path.ptr)) + { + git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir '%s' does not exist", path.ptr); + return 0; + } + return 1; } From 05719c55ff6a8780d7d3b5ae5c55d81f981fe7b3 Mon Sep 17 00:00:00 2001 From: Reginald McLean Date: Tue, 24 Nov 2020 19:42:54 -0500 Subject: [PATCH 201/816] Refactor git_worktree_is_prunable slightly to fix memory leak --- src/libgit2/worktree.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libgit2/worktree.c b/src/libgit2/worktree.c index a8460380ff9..702b7b774f8 100644 --- a/src/libgit2/worktree.c +++ b/src/libgit2/worktree.c @@ -566,6 +566,7 @@ int git_worktree_is_prunable(git_worktree *wt, { git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; git_buf path = GIT_BUF_INIT; + int ret = 0; GIT_ERROR_CHECK_VERSION( opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, @@ -576,35 +577,40 @@ int git_worktree_is_prunable(git_worktree *wt, if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0) { git_str reason = GIT_STR_INIT; - int error; - if ((error = git_worktree__is_locked(&reason, wt)) < 0) - return error; + if ((ret = git_worktree_is_locked(&reason, wt)) < 0) + goto out; - if (error) { + if (ret) { if (!reason.size) git_str_attach_notowned(&reason, "no reason given", 15); git_error_set(GIT_ERROR_WORKTREE, "not pruning locked working tree: '%s'", reason.ptr); git_str_dispose(&reason); - return 0; + ret = 0; + goto out; } } if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 && git_worktree_validate(wt) == 0) { git_error_set(GIT_ERROR_WORKTREE, "not pruning valid working tree"); - return 0; + goto out; } - if (git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name) < 0) - return 0; + if ((ret = git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name) < 0)) + goto out; if (!git_path_exists(path.ptr)) { git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir '%s' does not exist", path.ptr); - return 0; + goto out; } - return 1; + ret = 1; + +out: + + git_buf_dispose(&path); + return ret; } int git_worktree_prune(git_worktree *wt, From 372143244dc82551eccb0503ef58d9850d530346 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 16 May 2023 12:38:24 +0100 Subject: [PATCH 202/816] worktree: update prunable to reflect refactorings PR #5712 predates several refactorings to move the utility code into a more general purpose codebase. Update to reflect the refactorings. --- src/libgit2/worktree.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libgit2/worktree.c b/src/libgit2/worktree.c index 702b7b774f8..a878634ca84 100644 --- a/src/libgit2/worktree.c +++ b/src/libgit2/worktree.c @@ -565,7 +565,7 @@ int git_worktree_is_prunable(git_worktree *wt, git_worktree_prune_options *opts) { git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; - git_buf path = GIT_BUF_INIT; + git_str path = GIT_STR_INIT; int ret = 0; GIT_ERROR_CHECK_VERSION( @@ -578,13 +578,14 @@ int git_worktree_is_prunable(git_worktree *wt, if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0) { git_str reason = GIT_STR_INIT; - if ((ret = git_worktree_is_locked(&reason, wt)) < 0) + if ((ret = git_worktree__is_locked(&reason, wt)) < 0) goto out; if (ret) { - if (!reason.size) - git_str_attach_notowned(&reason, "no reason given", 15); - git_error_set(GIT_ERROR_WORKTREE, "not pruning locked working tree: '%s'", reason.ptr); + git_error_set(GIT_ERROR_WORKTREE, + "not pruning locked working tree: '%s'", + reason.size ? reason.ptr : "is locked"); + git_str_dispose(&reason); ret = 0; goto out; @@ -597,19 +598,18 @@ int git_worktree_is_prunable(git_worktree *wt, goto out; } - if ((ret = git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name) < 0)) + if ((ret = git_str_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name) < 0)) goto out; - if (!git_path_exists(path.ptr)) - { - git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir '%s' does not exist", path.ptr); + + if (!git_fs_path_exists(path.ptr)) { + git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir ('%s') does not exist", path.ptr); goto out; } ret = 1; out: - - git_buf_dispose(&path); + git_str_dispose(&path); return ret; } From 12b54ae00948a7a8422af53a8e98a5aa4d51f1f7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 16 May 2023 12:40:16 +0100 Subject: [PATCH 203/816] worktree: document that is_prunable sets error messages When a worktree is not prunable, an error message will be set with information about why. Document that. --- include/git2/worktree.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/git2/worktree.h b/include/git2/worktree.h index bb024dc940e..9193eaf347b 100644 --- a/include/git2/worktree.h +++ b/include/git2/worktree.h @@ -237,7 +237,9 @@ GIT_EXTERN(int) git_worktree_prune_options_init( * * If the worktree is not valid and not locked or if the above * flags have been passed in, this function will return a - * positive value. + * positive value. If the worktree is not prunable, an error + * message will be set (visible in `giterr_last`) with details about + * why. * * @param wt Worktree to check. * @param opts The prunable options. From 3b750a887b8ee32dee82adc7c1877c4f5baf59bc Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 31 May 2023 14:20:20 +0100 Subject: [PATCH 204/816] Git blame buffer gives the wrong result in many cases where there are multiple local edits. I added multiple failing tests cases to tests/libgit2/blame/buffer.c to cover the test cases. blame.c has been updated to get these tests to pass. Fixes include: shift_hunks_by now no longer shifts hunks before the start line. Adjusting the wedge line in the case where a new hunk deletes and adds lines. In buffer_line_cb for addions humks are now shifted after the current diff line. Fixing the logic for removing a line in buffer_line_cb to work with multi-line deletions. --- src/libgit2/blame.c | 22 ++-- tests/libgit2/blame/buffer.c | 236 ++++++++++++++++++++++++++++++++++- 2 files changed, 244 insertions(+), 14 deletions(-) diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index d93dd5e76b1..2cb09355e42 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -119,8 +119,11 @@ static void shift_hunks_by(git_vector *v, size_t start_line, int shift_by) size_t i; if (!git_vector_bsearch2(&i, v, hunk_byfinalline_search_cmp, &start_line)) { - for (; i < v->length; i++) { + for (i = 0; i < v->length; i++) { git_blame_hunk *hunk = (git_blame_hunk*)v->contents[i]; + if(hunk->final_start_line_number < start_line){ + continue; + } hunk->final_start_line_number += shift_by; } } @@ -444,21 +447,20 @@ static int buffer_hunk_cb( GIT_UNUSED(delta); - wedge_line = (hunk->old_lines == 0) ? hunk->new_start : hunk->old_start; + wedge_line = (hunk->new_start >= hunk->old_start || hunk->old_lines==0) ? hunk->new_start : hunk->old_start; blame->current_diff_line = wedge_line; - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byline(blame, wedge_line); if (!blame->current_hunk) { /* Line added at the end of the file */ blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path, blame); + blame->current_diff_line++; GIT_ERROR_CHECK_ALLOC(blame->current_hunk); - git_vector_insert(&blame->hunks, blame->current_hunk); } else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ /* If this hunk doesn't start between existing hunks, split a hunk up so it does */ blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk, - wedge_line - blame->current_hunk->orig_start_line_number, true, + wedge_line - blame->current_hunk->final_start_line_number, true, blame); GIT_ERROR_CHECK_ALLOC(blame->current_hunk); } @@ -484,13 +486,12 @@ static int buffer_line_cb( hunk_ends_at_or_before_line(blame->current_hunk, blame->current_diff_line)) { /* Append to the current buffer-blame hunk */ blame->current_hunk->lines_in_hunk++; - shift_hunks_by(&blame->hunks, blame->current_diff_line+1, 1); + shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); } else { /* Create a new buffer-blame hunk with this line */ shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); blame->current_hunk = new_hunk(blame->current_diff_line, 1, 0, blame->path, blame); GIT_ERROR_CHECK_ALLOC(blame->current_hunk); - git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL); } blame->current_diff_line++; @@ -498,15 +499,16 @@ static int buffer_line_cb( if (line->origin == GIT_DIFF_LINE_DELETION) { /* Trim the line from the current hunk; remove it if it's now empty */ - size_t shift_base = blame->current_diff_line + blame->current_hunk->lines_in_hunk+1; + size_t shift_base = blame->current_diff_line + blame->current_hunk->lines_in_hunk; if (--(blame->current_hunk->lines_in_hunk) == 0) { size_t i; - shift_base--; + size_t i_next; if (!git_vector_search2(&i, &blame->hunks, ptrs_equal_cmp, blame->current_hunk)) { git_vector_remove(&blame->hunks, i); free_hunk(blame->current_hunk); - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i); + i_next = min( i , blame->hunks.length -1); + blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i_next); } } shift_hunks_by(&blame->hunks, shift_base, -1); diff --git a/tests/libgit2/blame/buffer.c b/tests/libgit2/blame/buffer.c index 06d5042dd05..456402c4e8b 100644 --- a/tests/libgit2/blame/buffer.c +++ b/tests/libgit2/blame/buffer.c @@ -17,15 +17,204 @@ void test_blame_buffer__cleanup(void) git_repository_free(g_repo); } + +void test_blame_buffer__4_edits(void) +{ + + const char *buffer = "\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +x\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n"; + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 2, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 1, 3, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 2, 4, 1, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 3, 5, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 4, 6, 1, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 5, 7, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 6, 8, 1, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 7, 9, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 8, 10, 1, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 9, 11, 5, 0, "aa06ecca", "b.txt"); +} + +void test_blame_buffer__two_added_lines_and_one_modified(void) +{ + + const char *buffer = "\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +x\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +x\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n"; + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 3, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 1, 4, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 2, 5, 1, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 3, 6, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 4, 7, 1, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 5, 8, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 6, 9, 3, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 7, 12, 5, 0, "aa06ecca", "b.txt"); +} + +void test_blame_buffer__two_added_lines(void) +{ + + const char *buffer = "\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +abc\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +def\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n"; + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 3, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 1, 4, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 2, 5, 1, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 3, 6, 1, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 4, 7, 5, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 5, 12, 5, 0, "aa06ecca", "b.txt"); +} + +void test_blame_buffer__added_blocks(void) +{ + + const char *buffer = "\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +\n\ +abcdefg\n\ +hijlmno\n\ +pqrstuv\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +abcdefg\n\ +hijlmno\n\ +pqrstuv\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +\n\ +abcdefg\n\ +hijlmno\n\ +pqrstuv\n"; + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 4, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 3, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 3, 9, 4, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 4, 13, 3, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 5, 16, 5, 0, "aa06ecca", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 6, 21, 3, 0, "000000", "b.txt"); + + +} + +void test_blame_buffer__overlapping_blocks(void) +{ + const char *buffer = "\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +abcdefg\n\ +hijlmno\n\ +pqrstuv\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +\n\ +"; + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + + check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 3, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 1, 4, 3, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 2, 7, 4, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 3, 11, 5, 0, "aa06ecca", "b.txt"); + +} + +void test_blame_buffer__2_add_splits_hunk(void) +{ + const char *buffer = "\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +abc\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +abc\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n"; + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 2, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 1, 3, 1, 0, "00000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 2, 4, 2, 0, "da237394", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 3, 6, 1, 1, "b99f7ac0", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 4, 7, 2, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 5, 9, 1, 0, "00000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 6, 10, 3, 0, "63d671eb", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 7, 13, 5, 0, "aa06ecca", "b.txt"); +} + void test_blame_buffer__index(void) { const git_blame_hunk *hunk; const char *buffer = "Hello\nWorld!"; - /* - * We need to open a different file from the ones used in other tests. Close - * the one opened in test_blame_buffer__initialize() to avoid a leak. - */ git_blame_free(g_fileblame); g_fileblame = NULL; cl_git_pass(git_blame_file(&g_fileblame, g_repo, "file.txt", NULL)); @@ -43,6 +232,8 @@ void test_blame_buffer__index(void) cl_assert(hunk->final_signature == NULL); } + + void test_blame_buffer__added_line(void) { const git_blame_hunk *hunk; @@ -73,6 +264,43 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC cl_assert_equal_s("Ben Straub", hunk->final_signature->name); } +void test_blame_buffer__added_lines(void) +{ + + const char *buffer = "\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n\ +\n\ +\n\ +\n\ +\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n\ +\n\ +\n\ +\n\ +\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\ +\n\ +\n\ +\n\ +\n"; + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + cl_assert_equal_i(7, git_blame_get_hunk_count(g_bufferblame)); + check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 3, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 4, 14, 3, 0, "000000", "b.txt"); + check_blame_hunk_index(g_repo, g_bufferblame, 6, 22, 3, 0, "000000", "b.txt"); + +} + void test_blame_buffer__deleted_line(void) { const char *buffer = "\ From 3b6288af7ecf6ce7df499025bffec053009f2342 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 31 May 2023 15:29:01 +0100 Subject: [PATCH 205/816] Removing redundant call to find start line. --- src/libgit2/blame.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index 2cb09355e42..2ed7d2011f7 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -117,15 +117,12 @@ static git_blame_hunk *dup_hunk(git_blame_hunk *hunk, git_blame *blame) static void shift_hunks_by(git_vector *v, size_t start_line, int shift_by) { size_t i; - - if (!git_vector_bsearch2(&i, v, hunk_byfinalline_search_cmp, &start_line)) { - for (i = 0; i < v->length; i++) { - git_blame_hunk *hunk = (git_blame_hunk*)v->contents[i]; - if(hunk->final_start_line_number < start_line){ - continue; - } - hunk->final_start_line_number += shift_by; + for (i = 0; i < v->length; i++) { + git_blame_hunk *hunk = (git_blame_hunk*)v->contents[i]; + if(hunk->final_start_line_number < start_line){ + continue; } + hunk->final_start_line_number += shift_by; } } From 4a2c4cc93f86e832696a3067a6f24d42727bc6f5 Mon Sep 17 00:00:00 2001 From: Miguel Arroz <750683+arroz@users.noreply.github.com> Date: Fri, 9 Jun 2023 18:21:13 -0700 Subject: [PATCH 206/816] #6576 git_diff_index_to_workdir reverse now loads untracked content --- src/libgit2/diff_file.c | 2 +- tests/libgit2/diff/workdir.c | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/libgit2/diff_file.c b/src/libgit2/diff_file.c index c2d08675ab0..85296ca5be3 100644 --- a/src/libgit2/diff_file.c +++ b/src/libgit2/diff_file.c @@ -112,7 +112,7 @@ int git_diff_file_content__init_from_diff( case GIT_DELTA_DELETED: has_data = use_old; break; case GIT_DELTA_UNTRACKED: - has_data = !use_old && + has_data = (use_old == (diff->opts.flags & GIT_DIFF_REVERSE)) && (diff->opts.flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) != 0; break; case GIT_DELTA_UNREADABLE: diff --git a/tests/libgit2/diff/workdir.c b/tests/libgit2/diff/workdir.c index 21c5b0de9a2..c433b75cedc 100644 --- a/tests/libgit2/diff/workdir.c +++ b/tests/libgit2/diff/workdir.c @@ -2278,3 +2278,50 @@ void test_diff_workdir__ignore_blank_lines(void) git_patch_free(patch); git_diff_free(diff); } + +void test_diff_workdir__to_index_reversed_content_loads(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff = NULL; + diff_expects exp; + int use_iterator; + char *pathspec = "new_file"; + + g_repo = cl_git_sandbox_init("status"); + + opts.context_lines = 3; + opts.interhunk_lines = 1; + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED | + GIT_DIFF_SHOW_UNTRACKED_CONTENT | GIT_DIFF_REVERSE; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + for (use_iterator = 0; use_iterator <= 1; use_iterator++) { + memset(&exp, 0, sizeof(exp)); + + if (use_iterator) + cl_git_pass(diff_foreach_via_iterator( + diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); + else + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); + + cl_assert_equal_i(1, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + cl_assert_equal_i(1, exp.hunks); + + cl_assert_equal_i(1, exp.lines); + cl_assert_equal_i(0, exp.line_ctxt); + cl_assert_equal_i(0, exp.line_adds); + cl_assert_equal_i(1, exp.line_dels); + } + + git_diff_free(diff); +} From 1e2ea79e78be135f47dfc3fcf65d7572c0ad1e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20R=C3=B6hling?= Date: Mon, 19 Jun 2023 20:44:09 +0200 Subject: [PATCH 207/816] Use #!/bin/bash for script with bash-specific commands The test/Resources/push.sh calls pushd/popd, which is not a POSIX shell feature but a Bash extension. --- tests/resources/push.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/push.sh b/tests/resources/push.sh index 3e77fb5307f..54ef3ddf27c 100644 --- a/tests/resources/push.sh +++ b/tests/resources/push.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash #creates push_src repo for libgit2 push tests. set -eu From f576b7dd0228a8e3b203d66bf77cf3b71c780f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 22 Jun 2023 09:54:11 +0200 Subject: [PATCH 208/816] midx: allow unknown chunk ids in multi-pack index files These chunks work like extensions where it's fine not to know what one means. We can skip over it and keep processing the file instead of erroring out. --- src/libgit2/midx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index f6071f0bbbd..2072a8c8099 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -185,7 +185,8 @@ int git_midx_parse( chunk_oid_fanout = {0}, chunk_oid_lookup = {0}, chunk_object_offsets = {0}, - chunk_object_large_offsets = {0}; + chunk_object_large_offsets = {0}, + chunk_unknown = {0}; GIT_ASSERT_ARG(idx); @@ -264,7 +265,9 @@ int git_midx_parse( break; default: - return midx_error("unrecognized chunk ID"); + chunk_unknown.offset = last_chunk_offset; + last_chunk = &chunk_unknown; + break; } } last_chunk->length = (size_t)(trailer_offset - last_chunk_offset); From 1bbe0dd89dd1a63c4cf5f1cb1f925336408f0f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 22 Jun 2023 11:03:36 +0200 Subject: [PATCH 209/816] pack: cast the number of objects to size_t Similar to a previous change where we had to change the casting when loading the index file, we also need to make sure we don't restrict the numbers to 32-bit when looking up objects in packfiles. This was done about three years ago in git itself, but we never got he update in this library. --- src/libgit2/pack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index d59973aa937..eff73988278 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -1268,13 +1268,13 @@ static off64_t nth_packed_object_offset_locked(struct git_pack_file *p, uint32_t end = index + p->index_map.len; index += 4 * 256; if (p->index_version == 1) - return ntohl(*((uint32_t *)(index + (p->oid_size + 4) * n))); + return ntohl(*((uint32_t *)(index + (p->oid_size + 4) * (size_t) n))); - index += 8 + p->num_objects * (p->oid_size + 4); + index += 8 + (size_t) p->num_objects * (p->oid_size + 4); off32 = ntohl(*((uint32_t *)(index + 4 * n))); if (!(off32 & 0x80000000)) return off32; - index += p->num_objects * 4 + (off32 & 0x7fffffff) * 8; + index += (size_t) p->num_objects * 4 + (off32 & 0x7fffffff) * 8; /* Make sure we're not being sent out of bounds */ if (index >= end - 8) From c1aa0213e11c4cc5c5ba72eb5daf9b0664a1045c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 22 Jun 2023 12:08:31 +0200 Subject: [PATCH 210/816] midx: do not try to look at every object in the index Similar to previous issues around doing way too much verification at loading time, checking whether the object index chunk is monotonic is better left for git-fsck instead of every single time we want to look at something in the repository. As midx files grow, this starts taking more and more times. As an example, I went looking for this because it's taking about 1.5s to do a single object lookup in a repository that's ended up with a 7G multi-pack-index file. --- src/libgit2/midx.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index f6071f0bbbd..a70725d6c52 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -114,8 +114,6 @@ static int midx_parse_oid_lookup( const unsigned char *data, struct git_midx_chunk *chunk_oid_lookup) { - uint32_t i; - unsigned char *oid, *prev_oid, zero_oid[GIT_OID_MAX_SIZE] = {0}; size_t oid_size = git_oid_size(idx->oid_type); if (chunk_oid_lookup->offset == 0) @@ -125,13 +123,7 @@ static int midx_parse_oid_lookup( if (chunk_oid_lookup->length != idx->num_objects * oid_size) return midx_error("OID Lookup chunk has wrong length"); - idx->oid_lookup = oid = (unsigned char *)(data + chunk_oid_lookup->offset); - prev_oid = zero_oid; - for (i = 0; i < idx->num_objects; ++i, oid += oid_size) { - if (git_oid_raw_cmp(prev_oid, oid, oid_size) >= 0) - return midx_error("OID Lookup index is non-monotonic"); - prev_oid = oid; - } + idx->oid_lookup = (unsigned char *)(data + chunk_oid_lookup->offset); return 0; } From 933c09dbec8bece0a33d9b1792fcc9adeba28045 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Sun, 25 Jun 2023 05:12:57 +0200 Subject: [PATCH 211/816] CMake: Search for ssh2 instead of libssh2. Fixes "CMake Error: could not resolve ssh2" on Windows-MSVC. --- cmake/SelectSSH.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/SelectSSH.cmake b/cmake/SelectSSH.cmake index 23dfc978521..968a63114f3 100644 --- a/cmake/SelectSSH.cmake +++ b/cmake/SelectSSH.cmake @@ -1,6 +1,6 @@ # Optional external dependency: libssh2 if(USE_SSH) - find_pkglibraries(LIBSSH2 libssh2) + find_pkglibraries(LIBSSH2 ssh2) if(NOT LIBSSH2_FOUND) find_package(LibSSH2) set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR}) From 27b40287a077a1c650ff4c761ae11e3c5bbdbe99 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Sun, 9 Jul 2023 16:49:32 +0200 Subject: [PATCH 212/816] docs: fix IRC server from freenode to libera This commit update the contributing documents with the new IRC server and remove the old freenode. Signed-off-by: Vincenzo Palazzo --- docs/contributing.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 03e0017093b..382d9555ef5 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -24,9 +24,8 @@ by the following licenses: ## Discussion & Chat -We hang out in the -[`#libgit2`](http://webchat.freenode.net/?channels=#libgit2)) channel on -irc.freenode.net. +We hang out in the [#libgit2](https://web.libera.chat/#libgit2) channel on +[libera](https://libera.chat). Also, feel free to open an [Issue](https://github.com/libgit2/libgit2/issues/new) to start a discussion From 9b3d9c65a590fe2dfa803f89a7ae810001ca8107 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 15 Jul 2023 15:43:51 +0100 Subject: [PATCH 213/816] meta: update GitHub release labels --- .github/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/release.yml b/.github/release.yml index 79158f492d9..c7850749119 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -3,6 +3,9 @@ changelog: - title: New features labels: - feature + - title: Performance improvements + labels: + - performance issues - title: Bug fixes labels: - bug @@ -18,6 +21,9 @@ changelog: - title: Documentation improvements labels: - documentation + - title: Git compatibility fixes + labels: + - git compatibility - title: Other changes labels: - '*' From 2b55e59f60b807e6bc9e8663446d01ea88183dab Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 15 Jul 2023 15:46:02 +0100 Subject: [PATCH 214/816] meta: update GitHub release labels --- .github/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/release.yml b/.github/release.yml index c7850749119..7a0032113db 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -5,7 +5,7 @@ changelog: - feature - title: Performance improvements labels: - - performance issues + - performance - title: Bug fixes labels: - bug From c02fe8d2799a2c58ce8632870be263e99e884908 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 15 Jul 2023 16:16:48 +0100 Subject: [PATCH 215/816] deps: update pcre to 8.45 --- deps/pcre/LICENCE | 10 +++++----- deps/pcre/pcre.h | 4 ++-- deps/pcre/pcre_compile.c | 9 ++++++--- deps/pcre/pcre_exec.c | 4 ++-- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/deps/pcre/LICENCE b/deps/pcre/LICENCE index 57a544814c8..803b4119e50 100644 --- a/deps/pcre/LICENCE +++ b/deps/pcre/LICENCE @@ -19,13 +19,13 @@ THE BASIC LIBRARY FUNCTIONS --------------------------- Written by: Philip Hazel -Email local part: ph10 -Email domain: cam.ac.uk +Email local part: Philip.Hazel +Email domain: gmail.com University of Cambridge Computing Service, Cambridge, England. -Copyright (c) 1997-2020 University of Cambridge +Copyright (c) 1997-2021 University of Cambridge All rights reserved. @@ -36,7 +36,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Email domain: freemail.hu -Copyright(c) 2010-2020 Zoltan Herczeg +Copyright(c) 2010-2021 Zoltan Herczeg All rights reserved. @@ -47,7 +47,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Email domain: freemail.hu -Copyright(c) 2009-2020 Zoltan Herczeg +Copyright(c) 2009-2021 Zoltan Herczeg All rights reserved. diff --git a/deps/pcre/pcre.h b/deps/pcre/pcre.h index 5b147b9f8b5..821b50e88a9 100644 --- a/deps/pcre/pcre.h +++ b/deps/pcre/pcre.h @@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE. /* The current PCRE version information. */ #define PCRE_MAJOR 8 -#define PCRE_MINOR 44 +#define PCRE_MINOR 45 #define PCRE_PRERELEASE -#define PCRE_DATE 2020-02-12 +#define PCRE_DATE 2021-06-15 #define PCRE_EXP_DECL extern diff --git a/deps/pcre/pcre_compile.c b/deps/pcre/pcre_compile.c index a3f20fd35d0..43f852f4627 100644 --- a/deps/pcre/pcre_compile.c +++ b/deps/pcre/pcre_compile.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2020 University of Cambridge + Copyright (c) 1997-2021 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -9104,6 +9104,8 @@ pcre_uchar cworkspace[COMPILE_WORK_SIZE]; similar way to cworkspace, it can be expanded using malloc() if necessary. */ named_group named_groups[NAMED_GROUP_LIST_SIZE]; +cd->named_groups = named_groups; +cd->named_group_list_size = NAMED_GROUP_LIST_SIZE; /* Set this early so that early errors get offset 0. */ @@ -9377,8 +9379,6 @@ cd->hwm = cworkspace; cd->iscondassert = FALSE; cd->start_workspace = cworkspace; cd->workspace_size = COMPILE_WORK_SIZE; -cd->named_groups = named_groups; -cd->named_group_list_size = NAMED_GROUP_LIST_SIZE; cd->start_pattern = (const pcre_uchar *)pattern; cd->end_pattern = (const pcre_uchar *)(pattern + STRLEN_UC((const pcre_uchar *)pattern)); cd->req_varyopt = 0; @@ -9489,6 +9489,7 @@ if (cd->names_found > 0) add_name(cd, ng->name, ng->length, ng->number); if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) (PUBL(free))((void *)cd->named_groups); + cd->named_group_list_size = 0; /* So we don't free it twice */ } /* Set up a starting, non-extracting bracket, then compile the expression. On @@ -9639,6 +9640,8 @@ if (errorcode != 0) { (PUBL(free))(re); PCRE_EARLY_ERROR_RETURN: + if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) + (PUBL(free))((void *)cd->named_groups); *erroroffset = (int)(ptr - (const pcre_uchar *)pattern); PCRE_EARLY_ERROR_RETURN2: *errorptr = find_error_text(errorcode); diff --git a/deps/pcre/pcre_exec.c b/deps/pcre/pcre_exec.c index 3fd58cbe31c..5b96954fcd9 100644 --- a/deps/pcre/pcre_exec.c +++ b/deps/pcre/pcre_exec.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2018 University of Cambridge + Copyright (c) 1997-2021 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -758,7 +758,7 @@ for (;;) md->mark = NULL; /* In case previously set by assertion */ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md, eptrb, RM55); - if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && + if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT || rrc == MATCH_KETRPOS) && md->mark == NULL) md->mark = ecode + 2; /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an From bdd031576b0ef3f3333270bead63e91a735d94d9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 17 Jul 2023 10:33:15 +0100 Subject: [PATCH 216/816] v1.7: update version numbers --- README.md | 2 +- include/git2/version.h | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 93476f9c0cd..711e848e0a5 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | | **main** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) | +| **v1.7 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.7) | | **v1.6 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.6&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.6) | -| **v1.5 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.5&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.5) | | **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/workflows/Nightly%20Build/badge.svg)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Nightly+Build%22) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | `libgit2` is a portable, pure C implementation of the Git core methods diff --git a/include/git2/version.h b/include/git2/version.h index bed47f51e49..088ba6b07b1 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,7 +11,7 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.7.0-alpha" +#define LIBGIT2_VERSION "1.7.0" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 @@ -31,7 +31,7 @@ * a prerelease name like "beta" or "rc1". For final releases, this will * be `NULL`. */ -#define LIBGIT2_VER_PRERELEASE "alpha" +#define LIBGIT2_VER_PRERELEASE NULL /** The library ABI soversion for this version of libgit2. */ #define LIBGIT2_SOVERSION "1.7" diff --git a/package.json b/package.json index 398446ea5f4..8c6f4ef6e80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.7.0-alpha", + "version": "1.7.0", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From c375d0b7c84243fe1cc1a3903b048d8a05c40d1b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 17 Jul 2023 10:33:28 +0100 Subject: [PATCH 217/816] v1.7: update changelog --- docs/changelog.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 20e48a084de..f733102356a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,131 @@ +v1.7 +---- + +This is release v1.7.0, "Kleine Raupe Nimmersatt". This release adds +shallow clone support, completes the experimental SHA256 support, +adds Schannel support for Windows, and includes many other new +features and bugfixes. + +## Major changes + +* **Shallow clone support** + libgit2 now supports shallow clone and shallow repositories, thanks + to a significant investment from many community members -- hundreds + of commits by many contributors. + + * Shallow (#6396) with some fixes from review by @ethomson in + https://github.com/libgit2/libgit2/pull/6557 + * Shallow Clone Support by @lya001 in + https://github.com/libgit2/libgit2/pull/6396 + * Shallow support v2 by @pks-t in + https://github.com/libgit2/libgit2/pull/5254 + +* **SHA256 support** + libgit2 should now support SHA256 repositories using the + `extensions.objectFormat` configuration option when the library is + built with `EXPERIMENTAL_SHA256=ON`. Users are encouraged to begin + testing their applications with this option and provide bug reports + and feedback. This _is_ a breaking API change; SHA256 support will + be enabled by default in libgit2 v2.0. + + * sha256: less hardcoded SHA1 types and lengths by @ethomson in + https://github.com/libgit2/libgit2/pull/6549 + * Support SHA256 in git_repository_wrap_odb by @ethomson in + https://github.com/libgit2/libgit2/pull/6556 + +* **Schannel and SSPI for Windows** + libgit2 now supports the Windows Schannel and SSPI APIs for HTTPS + support on Windows, when configured with `USE_HTTPS=Schannel`. + Setting this option will not use the existing WinHTTP support, but + will use libgit2's standard HTTP client stack with Windows TLS + primitives. Windows users are encouraged to begin testing their + applications with this option and provide bug reports and feedback. + This will be enabled by default in a future version of libgit2. + + * Introduce Schannel and SSPI for Windows by @ethomson in + https://github.com/libgit2/libgit2/pull/6533 + +## Breaking changes + +* **Simplify custom pluggable allocator** (System API / ABI breaking change) + The `git_allocator` structure (configurable by the + `GIT_OPT_SET_ALLOCATOR` option) now only contains `gmalloc`, + `grealloc` and `gfree` members. This simplifies both the work needed + by an implementer _and_ allows more flexibility and correctness in + libgit2 itself, especially during out-of-memory situations and + errors during bootstrapping. + + * tests: add allocator with limited number of bytes by @ethomson in + https://github.com/libgit2/libgit2/pull/6563 + +## Other changes + +### New features +* repo: honor environment variables for more scenarios by @ethomson in + https://github.com/libgit2/libgit2/pull/6544 +* Introduce timeouts on sockets by @ethomson in + https://github.com/libgit2/libgit2/pull/6535 + +### Performance improvements +* midx: do not try to look at every object in the index by @carlosmn in + https://github.com/libgit2/libgit2/pull/6585 +* Partial fix for #6532: insert-by-date order. by @arroz in + https://github.com/libgit2/libgit2/pull/6539 + +### Bug fixes +* repo: don't allow repeated extensions by @ethomson in + https://github.com/libgit2/libgit2/pull/6505 +* config: return `GIT_ENOTFOUND` for missing programdata by @ethomson in + https://github.com/libgit2/libgit2/pull/6547 +* Fix missing oid type for "fake" repositories by @oreiche in + https://github.com/libgit2/libgit2/pull/6554 +* Thread-local storage: handle failure cases by @ethomson in + https://github.com/libgit2/libgit2/pull/5722 +* midx: allow unknown chunk ids in multi-pack index files by @carlosmn in + https://github.com/libgit2/libgit2/pull/6583 +* pack: cast the number of objects to size_t by @carlosmn in + https://github.com/libgit2/libgit2/pull/6584 +* Fixes #6344: git_branch_move now renames the reflog instead of deleting + by @arroz in https://github.com/libgit2/libgit2/pull/6345 +* #6576 git_diff_index_to_workdir reverse now loads untracked content by + @arroz in https://github.com/libgit2/libgit2/pull/6577 + +### Build and CI improvements +* meta: the main branch is now v1.7.0 by @ethomson in + https://github.com/libgit2/libgit2/pull/6516 +* xdiff: move xdiff to 'deps' by @ethomson in + https://github.com/libgit2/libgit2/pull/6482 +* util: detect all possible qsort_r and qsort_s variants by + @DimitryAndric in https://github.com/libgit2/libgit2/pull/6555 +* Work around -Werror problems when detecting qsort variants by + @DimitryAndric in https://github.com/libgit2/libgit2/pull/6558 +* actions: simplify execution with composite action by @ethomson in + https://github.com/libgit2/libgit2/pull/6488 +* CMake: Search for ssh2 instead of libssh2. by @Faless in + https://github.com/libgit2/libgit2/pull/6586 + +### Documentation improvements +* docs: fix IRC server from freenode to libera by @vincenzopalazzo in + https://github.com/libgit2/libgit2/pull/6590 + +### Dependency upgrades +* Update xdiff to git 2.40.1's version by @ethomson in + https://github.com/libgit2/libgit2/pull/6561 +* deps: update pcre to 8.45 by @ethomson in + https://github.com/libgit2/libgit2/pull/6593 + +## New Contributors +* @oreiche made their first contribution in + https://github.com/libgit2/libgit2/pull/6554 +* @DimitryAndric made their first contribution in + https://github.com/libgit2/libgit2/pull/6555 +* @vincenzopalazzo made their first contribution in + https://github.com/libgit2/libgit2/pull/6590 +* @Faless made their first contribution in + https://github.com/libgit2/libgit2/pull/6586 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.6.3...v1.7.0 + v1.6.3 ------ From 62498558ffbd16449850d33c5048673fce78999e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 17 Jul 2023 11:05:48 +0100 Subject: [PATCH 218/816] meta: update version numbers to v1.8 --- CMakeLists.txt | 2 +- include/git2/version.h | 12 ++++++++---- package.json | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfb5a7d6f4d..81e2bc8aca1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.7.0" LANGUAGES C) +project(libgit2 VERSION "1.8.0" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") diff --git a/include/git2/version.h b/include/git2/version.h index 088ba6b07b1..76cb0026fc2 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,13 +11,13 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.7.0" +#define LIBGIT2_VERSION "1.8.0-alpha" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 /** The minor version number for this version of libgit2. */ -#define LIBGIT2_VER_MINOR 7 +#define LIBGIT2_VER_MINOR 8 /** The revision ("teeny") version number for this version of libgit2. */ #define LIBGIT2_VER_REVISION 0 @@ -31,9 +31,13 @@ * a prerelease name like "beta" or "rc1". For final releases, this will * be `NULL`. */ -#define LIBGIT2_VER_PRERELEASE NULL +#define LIBGIT2_VER_PRERELEASE "alpha" -/** The library ABI soversion for this version of libgit2. */ +/** + * The library ABI soversion for this version of libgit2. This should + * only be changed when the library has a breaking ABI change, and so + * may trail the library's version number. + */ #define LIBGIT2_SOVERSION "1.7" #endif diff --git a/package.json b/package.json index 8c6f4ef6e80..203e99b9bc6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.7.0", + "version": "1.8.0-alpha", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From 89bc8ff9825efd4dcb343ed788a74a58ed8e61d5 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Mon, 17 Jul 2023 21:41:04 +0100 Subject: [PATCH 219/816] Return an error for invalid proxy URLs instead of crashing. --- src/libgit2/transports/http.c | 13 +++++++++++-- tests/libgit2/online/clone.c | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index 0534503bf25..a7aea6b377e 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -334,10 +334,19 @@ static int lookup_proxy( return 0; } - if (!proxy || - (error = git_net_url_parse(&transport->proxy.url, proxy)) < 0) + if (!proxy) goto done; + + if ((error = git_net_url_parse(&transport->proxy.url, proxy) < 0)) + goto done; + + if (!git_net_url_valid(&transport->proxy.url)) { + git_error_set(GIT_ERROR_HTTP, "invalid proxy url: %s", proxy); + error = GIT_EINVALIDSPEC; + goto done; + } + *out_use = true; done: diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index dbcac50ae6e..5c714d1aa9d 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -968,6 +968,19 @@ static int proxy_cert_cb(git_cert *cert, int valid, const char *host, void *payl return valid ? 0 : GIT_ECERTIFICATE; } +void test_online_clone__proxy_invalid_url(void) +{ + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED; + g_options.fetch_opts.proxy_opts.credentials = proxy_cred_cb; + g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb; + + g_options.fetch_opts.proxy_opts.url = "noschemeorport"; + cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + + g_options.fetch_opts.proxy_opts.url = "noscheme:8080"; + cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); +} + void test_online_clone__proxy_credentials_request(void) { git_str url = GIT_STR_INIT; From 9d4c550564ee254dda9e2620c4c1e32ebb529728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 18 Jul 2023 12:31:46 +0200 Subject: [PATCH 220/816] repository: make cleanup safe for re-use with grafts We are allowed to call `git_repository__cleanup` multiple times, and this happens e.g. in rugged if we want to free up resources before GC gets around to them. This means that we cannot leave dangling pointers in it, which we were doing with the grafts. Fix this by setting the pointers to NULL after freeing the resources. --- src/libgit2/repository.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 97f776c4a34..05ece6efc41 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -153,7 +153,9 @@ int git_repository__cleanup(git_repository *repo) git_cache_clear(&repo->objects); git_attr_cache_flush(repo); git_grafts_free(repo->grafts); + repo->grafts = NULL; git_grafts_free(repo->shallow_grafts); + repo->shallow_grafts = NULL; set_config(repo, NULL); set_index(repo, NULL); From 1a1464176b76d98cd71b7542baf56267fcb4c1ad Mon Sep 17 00:00:00 2001 From: steven9724 <116153756+steven9724@users.noreply.github.com> Date: Tue, 20 Jun 2023 10:36:24 +0100 Subject: [PATCH 221/816] ssh: fix known_hosts leak in _git_ssh_setup_conn --- src/libgit2/transports/ssh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c index af618e1a6ed..de63d454ee6 100644 --- a/src/libgit2/transports/ssh.c +++ b/src/libgit2/transports/ssh.c @@ -877,11 +877,12 @@ static int _git_ssh_setup_conn( t->current_stream = s; done: + if (known_hosts) + libssh2_knownhost_free(known_hosts); + if (error < 0) { ssh_stream_free(*stream); - if (known_hosts) - libssh2_knownhost_free(known_hosts); if (session) libssh2_session_free(session); } From f85e0af2b68c97b97de8c2388674b0868b5c5979 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 19 Jul 2023 11:17:03 +0100 Subject: [PATCH 222/816] config: complete entry during creation Don't set entry data when we "get" an entry from the collection, add the data to the entry before it's put into the collection. This keeps the entry creation logic in a single place. --- src/libgit2/config_file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 716924de600..6fc4c6fc21d 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -359,8 +359,6 @@ static int config_file_get(git_config_backend *cfg, const char *key, git_config_ return error; } - entry->free = config_file_entry_free; - entry->payload = entries; *out = entry; return 0; @@ -805,6 +803,8 @@ static int read_on_variable( entry->value = var_value ? git__strdup(var_value) : NULL; entry->level = parse_data->level; entry->include_depth = parse_data->depth; + entry->free = config_file_entry_free; + entry->payload = parse_data->entries; if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) return result; From 650a9dffb48640f9e9b04f82489e74d34eaa9938 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 19 Jul 2023 12:23:07 +0100 Subject: [PATCH 223/816] config: rename config_entries to config_list --- src/libgit2/config_entries.h | 24 ---- src/libgit2/config_file.c | 124 ++++++++--------- .../{config_entries.c => config_list.c} | 127 +++++++++--------- src/libgit2/config_list.h | 24 ++++ src/libgit2/config_mem.c | 28 ++-- src/libgit2/config_snapshot.c | 42 +++--- 6 files changed, 185 insertions(+), 184 deletions(-) delete mode 100644 src/libgit2/config_entries.h rename src/libgit2/{config_entries.c => config_list.c} (50%) create mode 100644 src/libgit2/config_list.h diff --git a/src/libgit2/config_entries.h b/src/libgit2/config_entries.h deleted file mode 100644 index 832379e7466..00000000000 --- a/src/libgit2/config_entries.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "git2/sys/config.h" -#include "config.h" - -typedef struct git_config_entries git_config_entries; - -int git_config_entries_new(git_config_entries **out); -int git_config_entries_dup(git_config_entries **out, git_config_entries *entries); -int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry); -void git_config_entries_incref(git_config_entries *entries); -void git_config_entries_free(git_config_entries *entries); -/* Add or append the new config option */ -int git_config_entries_append(git_config_entries *entries, git_config_entry *entry); -int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key); -int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key); -int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries); diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 6fc4c6fc21d..41241f1b0f5 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -13,7 +13,7 @@ #include "array.h" #include "str.h" #include "config_backend.h" -#include "config_entries.h" +#include "config_list.h" #include "config_parse.h" #include "filebuf.h" #include "regexp.h" @@ -34,7 +34,7 @@ typedef struct config_file { typedef struct { git_config_backend parent; git_mutex values_mutex; - git_config_entries *entries; + git_config_list *config_list; const git_repository *repo; git_config_level_t level; @@ -50,13 +50,13 @@ typedef struct { typedef struct { const git_repository *repo; config_file *file; - git_config_entries *entries; + git_config_list *config_list; git_config_level_t level; unsigned int depth; } config_file_parse_data; -static int config_file_read(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth); -static int config_file_read_buffer(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); +static int config_file_read(git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, int depth); +static int config_file_read_buffer(git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value); static char *escape_value(const char *ptr); @@ -65,7 +65,7 @@ static char *escape_value(const char *ptr); * refcount. This is its own function to make sure we use the mutex to * avoid the map pointer from changing under us. */ -static int config_file_entries_take(git_config_entries **out, config_file_backend *b) +static int config_file_take_list(git_config_list **out, config_file_backend *b) { int error; @@ -74,8 +74,8 @@ static int config_file_entries_take(git_config_entries **out, config_file_backen return error; } - git_config_entries_incref(b->entries); - *out = b->entries; + git_config_list_incref(b->config_list); + *out = b->config_list; git_mutex_unlock(&b->values_mutex); @@ -106,7 +106,7 @@ static int config_file_open(git_config_backend *cfg, git_config_level_t level, c b->level = level; b->repo = repo; - if ((res = git_config_entries_new(&b->entries)) < 0) + if ((res = git_config_list_new(&b->config_list)) < 0) return res; if (!git_fs_path_exists(b->file.path)) @@ -121,9 +121,9 @@ static int config_file_open(git_config_backend *cfg, git_config_level_t level, c if (p_access(b->file.path, R_OK) < 0) return GIT_ENOTFOUND; - if (res < 0 || (res = config_file_read(b->entries, repo, &b->file, level, 0)) < 0) { - git_config_entries_free(b->entries); - b->entries = NULL; + if (res < 0 || (res = config_file_read(b->config_list, repo, &b->file, level, 0)) < 0) { + git_config_list_free(b->config_list); + b->config_list = NULL; } return res; @@ -175,10 +175,10 @@ static void config_file_clear_includes(config_file_backend *cfg) git_array_clear(cfg->file.includes); } -static int config_file_set_entries(git_config_backend *cfg, git_config_entries *entries) +static int config_file_set_entries(git_config_backend *cfg, git_config_list *config_list) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *old = NULL; + git_config_list *old = NULL; int error; if (b->parent.readonly) { @@ -191,40 +191,40 @@ static int config_file_set_entries(git_config_backend *cfg, git_config_entries * goto out; } - old = b->entries; - b->entries = entries; + old = b->config_list; + b->config_list = config_list; git_mutex_unlock(&b->values_mutex); out: - git_config_entries_free(old); + git_config_list_free(old); return error; } static int config_file_refresh_from_buffer(git_config_backend *cfg, const char *buf, size_t buflen) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error; config_file_clear_includes(b); - if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_file_read_buffer(entries, b->repo, &b->file, + if ((error = git_config_list_new(&config_list)) < 0 || + (error = config_file_read_buffer(config_list, b->repo, &b->file, b->level, 0, buf, buflen)) < 0 || - (error = config_file_set_entries(cfg, entries)) < 0) + (error = config_file_set_entries(cfg, config_list)) < 0) goto out; - entries = NULL; + config_list = NULL; out: - git_config_entries_free(entries); + git_config_list_free(config_list); return error; } static int config_file_refresh(git_config_backend *cfg) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error, modified; if (cfg->readonly) @@ -238,14 +238,14 @@ static int config_file_refresh(git_config_backend *cfg) config_file_clear_includes(b); - if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_file_read(entries, b->repo, &b->file, b->level, 0)) < 0 || - (error = config_file_set_entries(cfg, entries)) < 0) + if ((error = git_config_list_new(&config_list)) < 0 || + (error = config_file_read(config_list, b->repo, &b->file, b->level, 0)) < 0 || + (error = config_file_set_entries(cfg, config_list)) < 0) goto out; - entries = NULL; + config_list = NULL; out: - git_config_entries_free(entries); + git_config_list_free(config_list); return (error == GIT_ENOTFOUND) ? 0 : error; } @@ -258,7 +258,7 @@ static void config_file_free(git_config_backend *_backend) return; config_file_clear(&backend->file); - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_mutex_free(&backend->values_mutex); git__free(backend); } @@ -268,19 +268,19 @@ static int config_file_iterator( struct git_config_backend *backend) { config_file_backend *b = GIT_CONTAINER_OF(backend, config_file_backend, parent); - git_config_entries *dupped = NULL, *entries = NULL; + git_config_list *dupped = NULL, *config_list = NULL; int error; if ((error = config_file_refresh(backend)) < 0 || - (error = config_file_entries_take(&entries, b)) < 0 || - (error = git_config_entries_dup(&dupped, entries)) < 0 || - (error = git_config_entries_iterator_new(iter, dupped)) < 0) + (error = config_file_take_list(&config_list, b)) < 0 || + (error = git_config_list_dup(&dupped, config_list)) < 0 || + (error = git_config_list_iterator_new(iter, dupped)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); - git_config_entries_free(dupped); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); + git_config_list_free(dupped); return error; } @@ -292,7 +292,7 @@ static int config_file_snapshot(git_config_backend **out, git_config_backend *ba static int config_file_set(git_config_backend *cfg, const char *name, const char *value) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries; + git_config_list *config_list; git_config_entry *existing; char *key, *esc_value = NULL; int error; @@ -300,11 +300,11 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char if ((error = git_config__normalize_name(name, &key)) < 0) return error; - if ((error = config_file_entries_take(&entries, b)) < 0) + if ((error = config_file_take_list(&config_list, b)) < 0) return error; /* Check whether we'd be modifying an included or multivar key */ - if ((error = git_config_entries_get_unique(&existing, entries, key)) < 0) { + if ((error = git_config_list_get_unique(&existing, config_list, key)) < 0) { if (error != GIT_ENOTFOUND) goto out; error = 0; @@ -325,7 +325,7 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(esc_value); git__free(key); return error; @@ -334,8 +334,8 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char /* release the map containing the entry as an equivalent to freeing it */ static void config_file_entry_free(git_config_entry *entry) { - git_config_entries *entries = (git_config_entries *) entry->payload; - git_config_entries_free(entries); + git_config_list *config_list = (git_config_list *) entry->payload; + git_config_list_free(config_list); } /* @@ -344,18 +344,18 @@ static void config_file_entry_free(git_config_entry *entry) static int config_file_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry; int error = 0; if (!h->parent.readonly && ((error = config_file_refresh(cfg)) < 0)) return error; - if ((error = config_file_entries_take(&entries, h)) < 0) + if ((error = config_file_take_list(&config_list, h)) < 0) return error; - if ((error = (git_config_entries_get(&entry, entries, key))) < 0) { - git_config_entries_free(entries); + if ((error = (git_config_list_get(&entry, config_list, key))) < 0) { + git_config_list_free(config_list); return error; } @@ -394,7 +394,7 @@ static int config_file_set_multivar( static int config_file_delete(git_config_backend *cfg, const char *name) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry; char *key = NULL; int error; @@ -402,11 +402,11 @@ static int config_file_delete(git_config_backend *cfg, const char *name) if ((error = git_config__normalize_name(name, &key)) < 0) goto out; - if ((error = config_file_entries_take(&entries, b)) < 0) + if ((error = config_file_take_list(&config_list, b)) < 0) goto out; /* Check whether we'd be modifying an included or multivar key */ - if ((error = git_config_entries_get_unique(&entry, entries, key)) < 0) { + if ((error = git_config_list_get_unique(&entry, config_list, key)) < 0) { if (error == GIT_ENOTFOUND) git_error_set(GIT_ERROR_CONFIG, "could not find key '%s' to delete", name); goto out; @@ -416,7 +416,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(key); return error; } @@ -424,7 +424,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) static int config_file_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry = NULL; git_regexp preg = GIT_REGEX_INIT; char *key = NULL; @@ -433,10 +433,10 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name if ((result = git_config__normalize_name(name, &key)) < 0) goto out; - if ((result = config_file_entries_take(&entries, b)) < 0) + if ((result = config_file_take_list(&config_list, b)) < 0) goto out; - if ((result = git_config_entries_get(&entry, entries, key)) < 0) { + if ((result = git_config_list_get(&entry, config_list, key)) < 0) { if (result == GIT_ENOTFOUND) git_error_set(GIT_ERROR_CONFIG, "could not find key '%s' to delete", name); goto out; @@ -449,7 +449,7 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(key); git_regexp_dispose(&preg); return result; @@ -589,7 +589,7 @@ static int parse_include(config_file_parse_data *parse_data, const char *file) git_array_init(include->includes); include->path = git_str_detach(&path); - result = config_file_read(parse_data->entries, parse_data->repo, include, + result = config_file_read(parse_data->config_list, parse_data->repo, include, parse_data->level, parse_data->depth+1); if (result == GIT_ENOTFOUND) { @@ -804,9 +804,9 @@ static int read_on_variable( entry->level = parse_data->level; entry->include_depth = parse_data->depth; entry->free = config_file_entry_free; - entry->payload = parse_data->entries; + entry->payload = parse_data->config_list; - if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) + if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; result = 0; @@ -822,7 +822,7 @@ static int read_on_variable( } static int config_file_read_buffer( - git_config_entries *entries, + git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, @@ -851,7 +851,7 @@ static int config_file_read_buffer( parse_data.repo = repo; parse_data.file = file; - parse_data.entries = entries; + parse_data.config_list = config_list; parse_data.level = level; parse_data.depth = depth; @@ -862,7 +862,7 @@ static int config_file_read_buffer( } static int config_file_read( - git_config_entries *entries, + git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, @@ -884,7 +884,7 @@ static int config_file_read( if ((error = git_hash_buf(file->checksum, contents.ptr, contents.size, GIT_HASH_ALGORITHM_SHA256)) < 0) goto out; - if ((error = config_file_read_buffer(entries, repo, file, level, depth, + if ((error = config_file_read_buffer(config_list, repo, file, level, depth, contents.ptr, contents.size)) < 0) goto out; diff --git a/src/libgit2/config_entries.c b/src/libgit2/config_list.c similarity index 50% rename from src/libgit2/config_entries.c rename to src/libgit2/config_list.c index 66aae096d2d..01d41526e98 100644 --- a/src/libgit2/config_entries.c +++ b/src/libgit2/config_list.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "config_entries.h" +#include "config_list.h" typedef struct config_entry_list { struct config_entry_list *next; @@ -18,36 +18,36 @@ typedef struct { bool multivar; } config_entry_map_head; -typedef struct config_entries_iterator { +typedef struct config_list_iterator { git_config_iterator parent; - git_config_entries *entries; + git_config_list *list; config_entry_list *head; -} config_entries_iterator; +} config_list_iterator; -struct git_config_entries { +struct git_config_list { git_refcount rc; git_strmap *map; - config_entry_list *list; + config_entry_list *entries; }; -int git_config_entries_new(git_config_entries **out) +int git_config_list_new(git_config_list **out) { - git_config_entries *entries; + git_config_list *config_list; int error; - entries = git__calloc(1, sizeof(git_config_entries)); - GIT_ERROR_CHECK_ALLOC(entries); - GIT_REFCOUNT_INC(entries); + config_list = git__calloc(1, sizeof(git_config_list)); + GIT_ERROR_CHECK_ALLOC(config_list); + GIT_REFCOUNT_INC(config_list); - if ((error = git_strmap_new(&entries->map)) < 0) - git__free(entries); + if ((error = git_strmap_new(&config_list->map)) < 0) + git__free(config_list); else - *out = entries; + *out = config_list; return error; } -int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry) +int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry) { git_config_entry *duplicated; int error; @@ -65,7 +65,7 @@ int git_config_entries_dup_entry(git_config_entries *entries, const git_config_e duplicated->level = entry->level; duplicated->include_depth = entry->include_depth; - if ((error = git_config_entries_append(entries, duplicated)) < 0) + if ((error = git_config_list_append(config_list, duplicated)) < 0) goto out; out: @@ -77,78 +77,79 @@ int git_config_entries_dup_entry(git_config_entries *entries, const git_config_e return error; } -int git_config_entries_dup(git_config_entries **out, git_config_entries *entries) +int git_config_list_dup(git_config_list **out, git_config_list *config_list) { - git_config_entries *result = NULL; + git_config_list *result = NULL; config_entry_list *head; int error; - if ((error = git_config_entries_new(&result)) < 0) + if ((error = git_config_list_new(&result)) < 0) goto out; - for (head = entries->list; head; head = head->next) - if ((git_config_entries_dup_entry(result, head->entry)) < 0) + for (head = config_list->entries; head; head = head->next) + if ((git_config_list_dup_entry(result, head->entry)) < 0) goto out; *out = result; result = NULL; out: - git_config_entries_free(result); + git_config_list_free(result); return error; } -void git_config_entries_incref(git_config_entries *entries) +void git_config_list_incref(git_config_list *config_list) { - GIT_REFCOUNT_INC(entries); + GIT_REFCOUNT_INC(config_list); } -static void config_entries_free(git_config_entries *entries) +static void config_list_free(git_config_list *config_list) { - config_entry_list *list = NULL, *next; + config_entry_list *entry_list = NULL, *next; config_entry_map_head *head; - git_strmap_foreach_value(entries->map, head, - git__free((char *) head->entry->name); git__free(head) - ); - git_strmap_free(entries->map); - - list = entries->list; - while (list != NULL) { - next = list->next; - git__free((char *) list->entry->value); - git__free(list->entry); - git__free(list); - list = next; + git_strmap_foreach_value(config_list->map, head, { + git__free((char *) head->entry->name); + git__free(head); + }); + git_strmap_free(config_list->map); + + entry_list = config_list->entries; + while (entry_list != NULL) { + next = entry_list->next; + git__free((char *) entry_list->entry->value); + git__free(entry_list->entry); + git__free(entry_list); + entry_list = next; } - git__free(entries); + git__free(config_list); } -void git_config_entries_free(git_config_entries *entries) +void git_config_list_free(git_config_list *config_list) { - if (entries) - GIT_REFCOUNT_DEC(entries, config_entries_free); + if (config_list) + GIT_REFCOUNT_DEC(config_list, config_list_free); } -int git_config_entries_append(git_config_entries *entries, git_config_entry *entry) +int git_config_list_append(git_config_list *config_list, git_config_entry *entry) { config_entry_list *list_head; config_entry_map_head *map_head; - if ((map_head = git_strmap_get(entries->map, entry->name)) != NULL) { + if ((map_head = git_strmap_get(config_list->map, entry->name)) != NULL) { map_head->multivar = true; /* * This is a micro-optimization for configuration files * with a lot of same keys. As for multivars the entry's - * key will be the same for all entries, we can just free + * key will be the same for all list, we can just free * all except the first entry's name and just re-use it. */ git__free((char *) entry->name); entry->name = map_head->entry->name; } else { map_head = git__calloc(1, sizeof(*map_head)); - if ((git_strmap_set(entries->map, entry->name, map_head)) < 0) + if ((git_strmap_set(config_list->map, entry->name, map_head)) < 0) return -1; } map_head->entry = entry; @@ -157,29 +158,29 @@ int git_config_entries_append(git_config_entries *entries, git_config_entry *ent GIT_ERROR_CHECK_ALLOC(list_head); list_head->entry = entry; - if (entries->list) - entries->list->last->next = list_head; + if (config_list->entries) + config_list->entries->last->next = list_head; else - entries->list = list_head; - entries->list->last = list_head; + config_list->entries = list_head; + config_list->entries->last = list_head; return 0; } -int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key) +int git_config_list_get(git_config_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; - if ((entry = git_strmap_get(entries->map, key)) == NULL) + if ((entry = git_strmap_get(config_list->map, key)) == NULL) return GIT_ENOTFOUND; *out = entry->entry; return 0; } -int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key) +int git_config_list_get_unique(git_config_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; - if ((entry = git_strmap_get(entries->map, key)) == NULL) + if ((entry = git_strmap_get(config_list->map, key)) == NULL) return GIT_ENOTFOUND; if (entry->multivar) { @@ -199,8 +200,8 @@ int git_config_entries_get_unique(git_config_entry **out, git_config_entries *en static void config_iterator_free(git_config_iterator *iter) { - config_entries_iterator *it = (config_entries_iterator *) iter; - git_config_entries_free(it->entries); + config_list_iterator *it = (config_list_iterator *) iter; + git_config_list_free(it->list); git__free(it); } @@ -208,7 +209,7 @@ static int config_iterator_next( git_config_entry **entry, git_config_iterator *iter) { - config_entries_iterator *it = (config_entries_iterator *) iter; + config_list_iterator *it = (config_list_iterator *) iter; if (!it->head) return GIT_ITEROVER; @@ -219,18 +220,18 @@ static int config_iterator_next( return 0; } -int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries) +int git_config_list_iterator_new(git_config_iterator **out, git_config_list *config_list) { - config_entries_iterator *it; + config_list_iterator *it; - it = git__calloc(1, sizeof(config_entries_iterator)); + it = git__calloc(1, sizeof(config_list_iterator)); GIT_ERROR_CHECK_ALLOC(it); it->parent.next = config_iterator_next; it->parent.free = config_iterator_free; - it->head = entries->list; - it->entries = entries; + it->head = config_list->entries; + it->list = config_list; - git_config_entries_incref(entries); + git_config_list_incref(config_list); *out = &it->parent; return 0; diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h new file mode 100644 index 00000000000..e14e4aed023 --- /dev/null +++ b/src/libgit2/config_list.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "git2/sys/config.h" +#include "config.h" + +typedef struct git_config_list git_config_list; + +int git_config_list_new(git_config_list **out); +int git_config_list_dup(git_config_list **out, git_config_list *list); +int git_config_list_dup_entry(git_config_list *list, const git_config_entry *entry); +void git_config_list_incref(git_config_list *list); +void git_config_list_free(git_config_list *list); +/* Add or append the new config option */ +int git_config_list_append(git_config_list *list, git_config_entry *entry); +int git_config_list_get(git_config_entry **out, git_config_list *list, const char *key); +int git_config_list_get_unique(git_config_entry **out, git_config_list *list, const char *key); +int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 560229cf534..902bf99e6a3 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -9,16 +9,16 @@ #include "config_backend.h" #include "config_parse.h" -#include "config_entries.h" +#include "config_list.h" typedef struct { git_config_backend parent; - git_config_entries *entries; + git_config_list *config_list; git_str cfg; } config_memory_backend; typedef struct { - git_config_entries *entries; + git_config_list *config_list; git_config_level_t level; } config_memory_parse_data; @@ -69,7 +69,7 @@ static int read_variable_cb( entry->level = parse_data->level; entry->include_depth = 0; - if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) + if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; return result; @@ -87,7 +87,7 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr, memory_backend->cfg.size)) < 0) goto out; - parse_data.entries = memory_backend->entries; + parse_data.config_list = memory_backend->config_list; parse_data.level = level; if ((error = git_config_parse(&parser, NULL, read_variable_cb, NULL, NULL, &parse_data)) < 0) @@ -101,7 +101,7 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) { config_memory_backend *memory_backend = (config_memory_backend *) backend; - return git_config_entries_get(out, memory_backend->entries, key); + return git_config_list_get(out, memory_backend->config_list, key); } static int config_memory_iterator( @@ -109,18 +109,18 @@ static int config_memory_iterator( git_config_backend *backend) { config_memory_backend *memory_backend = (config_memory_backend *) backend; - git_config_entries *entries; + git_config_list *config_list; int error; - if ((error = git_config_entries_dup(&entries, memory_backend->entries)) < 0) + if ((error = git_config_list_dup(&config_list, memory_backend->config_list)) < 0) goto out; - if ((error = git_config_entries_iterator_new(iter, entries)) < 0) + if ((error = git_config_list_iterator_new(iter, config_list)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); return error; } @@ -177,7 +177,7 @@ static void config_memory_free(git_config_backend *_backend) if (backend == NULL) return; - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_str_dispose(&backend->cfg); git__free(backend); } @@ -189,13 +189,13 @@ int git_config_backend_from_string(git_config_backend **out, const char *cfg, si backend = git__calloc(1, sizeof(config_memory_backend)); GIT_ERROR_CHECK_ALLOC(backend); - if (git_config_entries_new(&backend->entries) < 0) { + if (git_config_list_new(&backend->config_list) < 0) { git__free(backend); return -1; } if (git_str_set(&backend->cfg, cfg, len) < 0) { - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git__free(backend); return -1; } diff --git a/src/libgit2/config_snapshot.c b/src/libgit2/config_snapshot.c index e295d2f7f28..dbd05ffdce7 100644 --- a/src/libgit2/config_snapshot.c +++ b/src/libgit2/config_snapshot.c @@ -8,12 +8,12 @@ #include "config_backend.h" #include "config.h" -#include "config_entries.h" +#include "config_list.h" typedef struct { git_config_backend parent; git_mutex values_mutex; - git_config_entries *entries; + git_config_list *config_list; git_config_backend *source; } config_snapshot_backend; @@ -28,30 +28,30 @@ static int config_snapshot_iterator( struct git_config_backend *backend) { config_snapshot_backend *b = GIT_CONTAINER_OF(backend, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error; - if ((error = git_config_entries_dup(&entries, b->entries)) < 0 || - (error = git_config_entries_iterator_new(iter, entries)) < 0) + if ((error = git_config_list_dup(&config_list, b->config_list)) < 0 || + (error = git_config_list_iterator_new(iter, config_list)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); return error; } /* release the map containing the entry as an equivalent to freeing it */ static void config_snapshot_entry_free(git_config_entry *entry) { - git_config_entries *entries = (git_config_entries *) entry->payload; - git_config_entries_free(entries); + git_config_list *config_list = (git_config_list *) entry->payload; + git_config_list_free(config_list); } static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry; int error = 0; @@ -60,17 +60,17 @@ static int config_snapshot_get(git_config_backend *cfg, const char *key, git_con return -1; } - entries = b->entries; - git_config_entries_incref(entries); + config_list = b->config_list; + git_config_list_incref(config_list); git_mutex_unlock(&b->values_mutex); - if ((error = (git_config_entries_get(&entry, entries, key))) < 0) { - git_config_entries_free(entries); + if ((error = (git_config_list_get(&entry, config_list, key))) < 0) { + git_config_list_free(config_list); return error; } entry->free = config_snapshot_entry_free; - entry->payload = entries; + entry->payload = config_list; *out = entry; return 0; @@ -135,7 +135,7 @@ static void config_snapshot_free(git_config_backend *_backend) if (backend == NULL) return; - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_mutex_free(&backend->values_mutex); git__free(backend); } @@ -143,7 +143,7 @@ static void config_snapshot_free(git_config_backend *_backend) static int config_snapshot_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_iterator *it = NULL; git_config_entry *entry; int error; @@ -152,12 +152,12 @@ static int config_snapshot_open(git_config_backend *cfg, git_config_level_t leve GIT_UNUSED(level); GIT_UNUSED(repo); - if ((error = git_config_entries_new(&entries)) < 0 || + if ((error = git_config_list_new(&config_list)) < 0 || (error = b->source->iterator(&it, b->source)) < 0) goto out; while ((error = git_config_next(&entry, it)) == 0) - if ((error = git_config_entries_dup_entry(entries, entry)) < 0) + if ((error = git_config_list_dup_entry(config_list, entry)) < 0) goto out; if (error < 0) { @@ -166,12 +166,12 @@ static int config_snapshot_open(git_config_backend *cfg, git_config_level_t leve error = 0; } - b->entries = entries; + b->config_list = config_list; out: git_config_iterator_free(it); if (error) - git_config_entries_free(entries); + git_config_list_free(config_list); return error; } From 5f7c18d7331c2326cbaecf5ce1487998e89c7489 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 19 Jul 2023 12:50:16 +0100 Subject: [PATCH 224/816] config: drop entry payload; teach config_list about entries The opaque `payload` on an entry is unnecessary and distracting; config entries should follow the patterns of other objects and use space elsewhere in the structure with a "base" config entry struct embedded. --- include/git2/config.h | 8 +++-- src/libgit2/config_file.c | 56 ++++++++++++++++---------------- src/libgit2/config_list.c | 61 +++++++++++++++++++++-------------- src/libgit2/config_list.h | 13 ++++++-- src/libgit2/config_mem.c | 23 +++++++++---- src/libgit2/config_snapshot.c | 14 ++------ 6 files changed, 98 insertions(+), 77 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index cfab0c75739..155a2996205 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -66,8 +66,12 @@ typedef struct git_config_entry { const char *value; /**< String value of the entry */ unsigned int include_depth; /**< Depth of includes where this variable was found */ git_config_level_t level; /**< Which config file this was found in */ - void GIT_CALLBACK(free)(struct git_config_entry *entry); /**< Free function for this entry */ - void *payload; /**< Opaque value for the free function. Do not read or write */ + + /** + * Free function for this entry; for internal purposes. Callers + * should call `git_config_entry_free` to free data. + */ + void GIT_CALLBACK(free)(struct git_config_entry *entry); } git_config_entry; /** diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 41241f1b0f5..46ef07533b6 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -293,7 +293,7 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list; - git_config_entry *existing; + git_config_list_entry *existing; char *key, *esc_value = NULL; int error; @@ -308,8 +308,8 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char if (error != GIT_ENOTFOUND) goto out; error = 0; - } else if ((!existing->value && !value) || - (existing->value && value && !strcmp(existing->value, value))) { + } else if ((!existing->base.value && !value) || + (existing->base.value && value && !strcmp(existing->base.value, value))) { /* don't update if old and new values already match */ error = 0; goto out; @@ -331,13 +331,6 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char return error; } -/* release the map containing the entry as an equivalent to freeing it */ -static void config_file_entry_free(git_config_entry *entry) -{ - git_config_list *config_list = (git_config_list *) entry->payload; - git_config_list_free(config_list); -} - /* * Internal function that actually gets the value in string form */ @@ -345,7 +338,7 @@ static int config_file_get(git_config_backend *cfg, const char *key, git_config_ { config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry; + git_config_list_entry *entry; int error = 0; if (!h->parent.readonly && ((error = config_file_refresh(cfg)) < 0)) @@ -359,7 +352,7 @@ static int config_file_get(git_config_backend *cfg, const char *key, git_config_ return error; } - *out = entry; + *out = &entry->base; return 0; } @@ -395,7 +388,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry; + git_config_list_entry *entry; char *key = NULL; int error; @@ -412,7 +405,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) goto out; } - if ((error = config_file_write(b, name, entry->name, NULL, NULL)) < 0) + if ((error = config_file_write(b, name, entry->base.name, NULL, NULL)) < 0) goto out; out: @@ -425,7 +418,7 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry = NULL; + git_config_list_entry *entry = NULL; git_regexp preg = GIT_REGEX_INIT; char *key = NULL; int result; @@ -774,7 +767,7 @@ static int read_on_variable( { config_file_parse_data *parse_data = (config_file_parse_data *)data; git_str buf = GIT_STR_INIT; - git_config_entry *entry; + git_config_list_entry *entry; const char *c; int result = 0; @@ -797,14 +790,21 @@ static int read_on_variable( if (git_str_oom(&buf)) return -1; - entry = git__calloc(1, sizeof(git_config_entry)); + entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->name = git_str_detach(&buf); - entry->value = var_value ? git__strdup(var_value) : NULL; - entry->level = parse_data->level; - entry->include_depth = parse_data->depth; - entry->free = config_file_entry_free; - entry->payload = parse_data->config_list; + + entry->base.name = git_str_detach(&buf); + GIT_ERROR_CHECK_ALLOC(entry->base.name); + + if (var_value) { + entry->base.value = git__strdup(var_value); + GIT_ERROR_CHECK_ALLOC(entry->base.value); + } + + entry->base.level = parse_data->level; + entry->base.include_depth = parse_data->depth; + entry->base.free = git_config_list_entry_free; + entry->config_list = parse_data->config_list; if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; @@ -812,11 +812,11 @@ static int read_on_variable( result = 0; /* Add or append the new config option */ - if (!git__strcmp(entry->name, "include.path")) - result = parse_include(parse_data, entry->value); - else if (!git__prefixcmp(entry->name, "includeif.") && - !git__suffixcmp(entry->name, ".path")) - result = parse_conditional_include(parse_data, entry->name, entry->value); + if (!git__strcmp(entry->base.name, "include.path")) + result = parse_include(parse_data, entry->base.value); + else if (!git__prefixcmp(entry->base.name, "includeif.") && + !git__suffixcmp(entry->base.name, ".path")) + result = parse_conditional_include(parse_data, entry->base.name, entry->base.value); return result; } diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index 01d41526e98..979c6ccff99 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -10,11 +10,11 @@ typedef struct config_entry_list { struct config_entry_list *next; struct config_entry_list *last; - git_config_entry *entry; + git_config_list_entry *entry; } config_entry_list; typedef struct { - git_config_entry *entry; + git_config_list_entry *entry; bool multivar; } config_entry_map_head; @@ -49,29 +49,32 @@ int git_config_list_new(git_config_list **out) int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry) { - git_config_entry *duplicated; + git_config_list_entry *duplicated; int error; - duplicated = git__calloc(1, sizeof(git_config_entry)); + duplicated = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(duplicated); - duplicated->name = git__strdup(entry->name); - GIT_ERROR_CHECK_ALLOC(duplicated->name); + duplicated->base.name = git__strdup(entry->name); + GIT_ERROR_CHECK_ALLOC(duplicated->base.name); if (entry->value) { - duplicated->value = git__strdup(entry->value); - GIT_ERROR_CHECK_ALLOC(duplicated->value); + duplicated->base.value = git__strdup(entry->value); + GIT_ERROR_CHECK_ALLOC(duplicated->base.value); } - duplicated->level = entry->level; - duplicated->include_depth = entry->include_depth; + + duplicated->base.level = entry->level; + duplicated->base.include_depth = entry->include_depth; + duplicated->base.free = git_config_list_entry_free; + duplicated->config_list = config_list; if ((error = git_config_list_append(config_list, duplicated)) < 0) goto out; out: if (error && duplicated) { - git__free((char *) duplicated->name); - git__free((char *) duplicated->value); + git__free((char *) duplicated->base.name); + git__free((char *) duplicated->base.value); git__free(duplicated); } return error; @@ -87,7 +90,7 @@ int git_config_list_dup(git_config_list **out, git_config_list *config_list) goto out; for (head = config_list->entries; head; head = head->next) - if ((git_config_list_dup_entry(result, head->entry)) < 0) + if ((git_config_list_dup_entry(result, &head->entry->base)) < 0) goto out; *out = result; @@ -109,7 +112,7 @@ static void config_list_free(git_config_list *config_list) config_entry_map_head *head; git_strmap_foreach_value(config_list->map, head, { - git__free((char *) head->entry->name); + git__free((char *) head->entry->base.name); git__free(head); }); git_strmap_free(config_list->map); @@ -117,7 +120,7 @@ static void config_list_free(git_config_list *config_list) entry_list = config_list->entries; while (entry_list != NULL) { next = entry_list->next; - git__free((char *) entry_list->entry->value); + git__free((char *) entry_list->entry->base.value); git__free(entry_list->entry); git__free(entry_list); entry_list = next; @@ -132,12 +135,12 @@ void git_config_list_free(git_config_list *config_list) GIT_REFCOUNT_DEC(config_list, config_list_free); } -int git_config_list_append(git_config_list *config_list, git_config_entry *entry) +int git_config_list_append(git_config_list *config_list, git_config_list_entry *entry) { config_entry_list *list_head; config_entry_map_head *map_head; - if ((map_head = git_strmap_get(config_list->map, entry->name)) != NULL) { + if ((map_head = git_strmap_get(config_list->map, entry->base.name)) != NULL) { map_head->multivar = true; /* * This is a micro-optimization for configuration files @@ -145,11 +148,11 @@ int git_config_list_append(git_config_list *config_list, git_config_entry *entry * key will be the same for all list, we can just free * all except the first entry's name and just re-use it. */ - git__free((char *) entry->name); - entry->name = map_head->entry->name; + git__free((char *) entry->base.name); + entry->base.name = map_head->entry->base.name; } else { map_head = git__calloc(1, sizeof(*map_head)); - if ((git_strmap_set(config_list->map, entry->name, map_head)) < 0) + if ((git_strmap_set(config_list->map, entry->base.name, map_head)) < 0) return -1; } map_head->entry = entry; @@ -167,16 +170,18 @@ int git_config_list_append(git_config_list *config_list, git_config_entry *entry return 0; } -int git_config_list_get(git_config_entry **out, git_config_list *config_list, const char *key) +int git_config_list_get(git_config_list_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; + if ((entry = git_strmap_get(config_list->map, key)) == NULL) return GIT_ENOTFOUND; + *out = entry->entry; return 0; } -int git_config_list_get_unique(git_config_entry **out, git_config_list *config_list, const char *key) +int git_config_list_get_unique(git_config_list_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; @@ -188,13 +193,12 @@ int git_config_list_get_unique(git_config_entry **out, git_config_list *config_l return -1; } - if (entry->entry->include_depth) { + if (entry->entry->base.include_depth) { git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included"); return -1; } *out = entry->entry; - return 0; } @@ -214,7 +218,7 @@ static int config_iterator_next( if (!it->head) return GIT_ITEROVER; - *entry = it->head->entry; + *entry = &it->head->entry->base; it->head = it->head->next; return 0; @@ -236,3 +240,10 @@ int git_config_list_iterator_new(git_config_iterator **out, git_config_list *con return 0; } + +/* release the map containing the entry as an equivalent to freeing it */ +void git_config_list_entry_free(git_config_entry *e) +{ + git_config_list_entry *entry = (git_config_list_entry *)e; + git_config_list_free(entry->config_list); +} diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h index e14e4aed023..0cacabb110d 100644 --- a/src/libgit2/config_list.h +++ b/src/libgit2/config_list.h @@ -12,13 +12,20 @@ typedef struct git_config_list git_config_list; +typedef struct { + git_config_entry base; + git_config_list *config_list; +} git_config_list_entry; + int git_config_list_new(git_config_list **out); int git_config_list_dup(git_config_list **out, git_config_list *list); int git_config_list_dup_entry(git_config_list *list, const git_config_entry *entry); void git_config_list_incref(git_config_list *list); void git_config_list_free(git_config_list *list); /* Add or append the new config option */ -int git_config_list_append(git_config_list *list, git_config_entry *entry); -int git_config_list_get(git_config_entry **out, git_config_list *list, const char *key); -int git_config_list_get_unique(git_config_entry **out, git_config_list *list, const char *key); +int git_config_list_append(git_config_list *list, git_config_list_entry *entry); +int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key); +int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); + +void git_config_list_entry_free(git_config_entry *entry); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 902bf99e6a3..37f5b01f983 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -39,7 +39,7 @@ static int read_variable_cb( { config_memory_parse_data *parse_data = (config_memory_parse_data *) payload; git_str buf = GIT_STR_INIT; - git_config_entry *entry; + git_config_list_entry *entry; const char *c; int result; @@ -62,12 +62,14 @@ static int read_variable_cb( if (git_str_oom(&buf)) return -1; - entry = git__calloc(1, sizeof(git_config_entry)); + entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->name = git_str_detach(&buf); - entry->value = var_value ? git__strdup(var_value) : NULL; - entry->level = parse_data->level; - entry->include_depth = 0; + entry->base.name = git_str_detach(&buf); + entry->base.value = var_value ? git__strdup(var_value) : NULL; + entry->base.level = parse_data->level; + entry->base.include_depth = 0; + entry->base.free = git_config_list_entry_free; + entry->config_list = parse_data->config_list; if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; @@ -101,7 +103,14 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) { config_memory_backend *memory_backend = (config_memory_backend *) backend; - return git_config_list_get(out, memory_backend->config_list, key); + git_config_list_entry *entry; + int error; + + if ((error = git_config_list_get(&entry, memory_backend->config_list, key)) != 0) + return error; + + *out = &entry->base; + return 0; } static int config_memory_iterator( diff --git a/src/libgit2/config_snapshot.c b/src/libgit2/config_snapshot.c index dbd05ffdce7..d8b8733a9fb 100644 --- a/src/libgit2/config_snapshot.c +++ b/src/libgit2/config_snapshot.c @@ -41,18 +41,11 @@ static int config_snapshot_iterator( return error; } -/* release the map containing the entry as an equivalent to freeing it */ -static void config_snapshot_entry_free(git_config_entry *entry) -{ - git_config_list *config_list = (git_config_list *) entry->payload; - git_config_list_free(config_list); -} - static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry; + git_config_list_entry *entry; int error = 0; if (git_mutex_lock(&b->values_mutex) < 0) { @@ -69,10 +62,7 @@ static int config_snapshot_get(git_config_backend *cfg, const char *key, git_con return error; } - entry->free = config_snapshot_entry_free; - entry->payload = config_list; - *out = entry; - + *out = &entry->base; return 0; } From d48a5d5104114b56c5084fd56d2581e5d5ed09eb Mon Sep 17 00:00:00 2001 From: lmcglash Date: Wed, 19 Jul 2023 14:33:39 +0100 Subject: [PATCH 225/816] Validate proxy URL on Windows. --- src/libgit2/transports/http.c | 11 ++++------- src/libgit2/transports/winhttp.c | 2 +- tests/libgit2/online/clone.c | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index a7aea6b377e..eed51914549 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -334,16 +334,13 @@ static int lookup_proxy( return 0; } - if (!proxy) - goto done; - - - if ((error = git_net_url_parse(&transport->proxy.url, proxy) < 0)) + if (!proxy || + (error = git_net_url_parse(&transport->proxy.url, proxy)) < 0) goto done; if (!git_net_url_valid(&transport->proxy.url)) { - git_error_set(GIT_ERROR_HTTP, "invalid proxy url: %s", proxy); - error = GIT_EINVALIDSPEC; + git_error_set(GIT_ERROR_HTTP, "invalid URL: '%s'", proxy); + error = -1; goto done; } diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index 27e0fb6f7e9..b7ffb9512ae 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -446,7 +446,7 @@ static int winhttp_stream_connect(winhttp_stream *s) if ((error = git_net_url_parse(&t->proxy.url, proxy_url)) < 0) goto on_error; - if (strcmp(t->proxy.url.scheme, "http") != 0 && strcmp(t->proxy.url.scheme, "https") != 0) { + if (!git_net_url_valid(&t->proxy.url)) { git_error_set(GIT_ERROR_HTTP, "invalid URL: '%s'", proxy_url); error = -1; goto on_error; diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 5c714d1aa9d..0c53514a425 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -975,10 +975,10 @@ void test_online_clone__proxy_invalid_url(void) g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb; g_options.fetch_opts.proxy_opts.url = "noschemeorport"; - cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_git_fail(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); g_options.fetch_opts.proxy_opts.url = "noscheme:8080"; - cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_git_fail(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); } void test_online_clone__proxy_credentials_request(void) From 0e0781f6f3d51b6eda93010db3c56530cb3953af Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 20 Jul 2023 10:29:41 +0100 Subject: [PATCH 226/816] config: provide origin in git_config_entry A git_config_entry now knows the type of the origin for the entry ("file", "memory", etc) and the path details (for files, the path on disk). This is propagated through snapshots. --- include/git2/config.h | 24 ++++++++++++++--- src/libgit2/config_file.c | 6 +++++ src/libgit2/config_list.c | 47 +++++++++++++++++++++++++++++---- src/libgit2/config_list.h | 1 + src/libgit2/config_mem.c | 1 + tests/libgit2/config/read.c | 2 ++ tests/libgit2/config/snapshot.c | 35 +++++++++++++++++++++++- 7 files changed, 106 insertions(+), 10 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index 155a2996205..332e62036d0 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -62,10 +62,26 @@ typedef enum { * An entry in a configuration file */ typedef struct git_config_entry { - const char *name; /**< Name of the entry (normalised) */ - const char *value; /**< String value of the entry */ - unsigned int include_depth; /**< Depth of includes where this variable was found */ - git_config_level_t level; /**< Which config file this was found in */ + /** Name of the configuration entry (normalized) */ + const char *name; + + /** Literal (string) value of the entry */ + const char *value; + + /** The type of backend that this entry exists in (eg, "file") */ + const char *backend_type; + + /** + * The path to the origin of this entry. For config files, this is + * the path to the file. + */ + const char *origin_path; + + /** Depth of includes where this variable was found */ + unsigned int include_depth; + + /** Configuration level for the file this was found in */ + git_config_level_t level; /** * Free function for this entry; for internal purposes. Callers diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 46ef07533b6..c86e98bf2bf 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -24,6 +24,8 @@ /* Max depth for [include] directives */ #define MAX_INCLUDE_DEPTH 10 +#define CONFIG_FILE_TYPE "file" + typedef struct config_file { git_futils_filestamp stamp; unsigned char checksum[GIT_HASH_SHA256_SIZE]; @@ -801,7 +803,11 @@ static int read_on_variable( GIT_ERROR_CHECK_ALLOC(entry->base.value); } + entry->base.origin_path = git_config_list_add_path(parse_data->config_list, parse_data->file->path); + GIT_ERROR_CHECK_ALLOC(entry->base.origin_path); + entry->base.level = parse_data->level; + entry->base.backend_type = CONFIG_FILE_TYPE; entry->base.include_depth = parse_data->depth; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index 979c6ccff99..f642c87a4a7 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -26,6 +26,11 @@ typedef struct config_list_iterator { struct git_config_list { git_refcount rc; + + /* Paths to config files that contribute to these entries */ + git_strmap *paths; + + /* Config entries */ git_strmap *map; config_entry_list *entries; }; @@ -33,18 +38,22 @@ struct git_config_list { int git_config_list_new(git_config_list **out) { git_config_list *config_list; - int error; config_list = git__calloc(1, sizeof(git_config_list)); GIT_ERROR_CHECK_ALLOC(config_list); GIT_REFCOUNT_INC(config_list); - if ((error = git_strmap_new(&config_list->map)) < 0) + if (git_strmap_new(&config_list->paths) < 0 || + git_strmap_new(&config_list->map) < 0) { + git_strmap_free(config_list->paths); + git_strmap_free(config_list->map); git__free(config_list); - else - *out = config_list; - return error; + return -1; + } + + *out = config_list; + return 0; } int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry) @@ -63,6 +72,12 @@ int git_config_list_dup_entry(git_config_list *config_list, const git_config_ent GIT_ERROR_CHECK_ALLOC(duplicated->base.value); } + if (entry->origin_path) { + duplicated->base.origin_path = git_config_list_add_path(config_list, entry->origin_path); + GIT_ERROR_CHECK_ALLOC(duplicated->base.origin_path); + } + + duplicated->base.backend_type = entry->backend_type; duplicated->base.level = entry->level; duplicated->base.include_depth = entry->include_depth; duplicated->base.free = git_config_list_entry_free; @@ -110,6 +125,12 @@ static void config_list_free(git_config_list *config_list) { config_entry_list *entry_list = NULL, *next; config_entry_map_head *head; + char *path; + + git_strmap_foreach_value(config_list->paths, path, { + git__free(path); + }); + git_strmap_free(config_list->paths); git_strmap_foreach_value(config_list->map, head, { git__free((char *) head->entry->base.name); @@ -247,3 +268,19 @@ void git_config_list_entry_free(git_config_entry *e) git_config_list_entry *entry = (git_config_list_entry *)e; git_config_list_free(entry->config_list); } + +const char *git_config_list_add_path( + git_config_list *config_list, + const char *path) +{ + const char *p; + + if ((p = git_strmap_get(config_list->paths, path)) != NULL) + return p; + + if ((p = git__strdup(path)) == NULL || + git_strmap_set(config_list->paths, p, (void *)p) < 0) + return NULL; + + return p; +} diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h index 0cacabb110d..83c43b9a0ff 100644 --- a/src/libgit2/config_list.h +++ b/src/libgit2/config_list.h @@ -27,5 +27,6 @@ int git_config_list_append(git_config_list *list, git_config_list_entry *entry); int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); +const char *git_config_list_add_path(git_config_list *list, const char *path); void git_config_list_entry_free(git_config_entry *entry); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 37f5b01f983..748a1471673 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -68,6 +68,7 @@ static int read_variable_cb( entry->base.value = var_value ? git__strdup(var_value) : NULL; entry->base.level = parse_data->level; entry->base.include_depth = 0; + entry->base.backend_type = "memory"; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; diff --git a/tests/libgit2/config/read.c b/tests/libgit2/config/read.c index ac6459b9ea6..25e7b963c4d 100644 --- a/tests/libgit2/config/read.c +++ b/tests/libgit2/config/read.c @@ -495,6 +495,8 @@ void test_config_read__read_git_config_entry(void) cl_assert_equal_s("core.dummy2", entry->name); cl_assert_equal_s("42", entry->value); cl_assert_equal_i(GIT_CONFIG_LEVEL_SYSTEM, entry->level); + cl_assert_equal_s("file", entry->backend_type); + cl_assert_equal_s(cl_fixture("config/config9"), entry->origin_path); git_config_entry_free(entry); git_config_free(cfg); diff --git a/tests/libgit2/config/snapshot.c b/tests/libgit2/config/snapshot.c index 5cc08a721ac..bfb68e21e23 100644 --- a/tests/libgit2/config/snapshot.c +++ b/tests/libgit2/config/snapshot.c @@ -79,6 +79,7 @@ void test_config_snapshot__multivar(void) void test_config_snapshot__includes(void) { + git_config_entry *entry; int i; cl_git_mkfile("including", "[include]\npath = included"); @@ -99,6 +100,16 @@ void test_config_snapshot__includes(void) cl_git_pass(git_config_get_int32(&i, snapshot, "section.key")); cl_assert_equal_i(i, 1); + /* Ensure that the config entry is populated with origin */ + cl_git_pass(git_config_get_entry(&entry, snapshot, "section.key")); + + cl_assert_equal_s("section.key", entry->name); + cl_assert_equal_s("1", entry->value); + cl_assert_equal_s("file", entry->backend_type); + cl_assert_equal_s("./included", entry->origin_path); + + git_config_entry_free(entry); + cl_git_pass(p_unlink("including")); cl_git_pass(p_unlink("included")); } @@ -106,6 +117,7 @@ void test_config_snapshot__includes(void) void test_config_snapshot__snapshot(void) { git_config *snapshot_snapshot; + git_config_entry *entry; int i; cl_git_mkfile("configfile", "[section]\nkey = 1\n"); @@ -118,15 +130,26 @@ void test_config_snapshot__snapshot(void) cl_git_pass(git_config_get_int32(&i, snapshot_snapshot, "section.key")); cl_assert_equal_i(i, 1); + /* Ensure that the config entry is populated with origin */ + cl_git_pass(git_config_get_entry(&entry, snapshot_snapshot, "section.key")); + + cl_assert_equal_s("section.key", entry->name); + cl_assert_equal_s("1", entry->value); + cl_assert_equal_s("file", entry->backend_type); + cl_assert_equal_s("configfile", entry->origin_path); + + git_config_entry_free(entry); + git_config_free(snapshot_snapshot); cl_git_pass(p_unlink("configfile")); } -void test_config_snapshot__snapshot_from_in_memony(void) +void test_config_snapshot__snapshot_from_in_memory(void) { const char *configuration = "[section]\nkey = 1\n"; git_config_backend *backend; + git_config_entry *entry; int i; cl_git_pass(git_config_new(&cfg)); @@ -136,4 +159,14 @@ void test_config_snapshot__snapshot_from_in_memony(void) cl_git_pass(git_config_snapshot(&snapshot, cfg)); cl_git_pass(git_config_get_int32(&i, snapshot, "section.key")); cl_assert_equal_i(i, 1); + + /* Ensure that the config entry is populated with origin */ + cl_git_pass(git_config_get_entry(&entry, snapshot, "section.key")); + + cl_assert_equal_s("section.key", entry->name); + cl_assert_equal_s("1", entry->value); + cl_assert_equal_s("memory", entry->backend_type); + cl_assert_equal_p(NULL, entry->origin_path); + + git_config_entry_free(entry); } From 248ac08cb89b9a8d962b6752bced8809c757e412 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 20 Jul 2023 10:54:14 +0100 Subject: [PATCH 227/816] config: memory backends have an optional type --- src/libgit2/config_backend.h | 10 +++++++-- src/libgit2/config_file.c | 6 ++++-- src/libgit2/config_list.c | 38 +++++++++++++++++---------------- src/libgit2/config_list.h | 2 +- src/libgit2/config_mem.c | 17 +++++++++++++-- tests/libgit2/config/memory.c | 4 ++-- tests/libgit2/config/snapshot.c | 4 ++-- 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/libgit2/config_backend.h b/src/libgit2/config_backend.h index dbb19051484..677b2236f98 100644 --- a/src/libgit2/config_backend.h +++ b/src/libgit2/config_backend.h @@ -38,13 +38,19 @@ extern int git_config_backend_from_file(git_config_backend **out, const char *pa extern int git_config_backend_snapshot(git_config_backend **out, git_config_backend *source); /** - * Create an in-memory configuration file backend + * Create an in-memory configuration file backend from a string in standard + * git configuration file format. * * @param out the new backend + * @param origin the name of the origin to use (or NULL for "memory") * @param cfg the configuration that is to be parsed * @param len the length of the string pointed to by `cfg` */ -extern int git_config_backend_from_string(git_config_backend **out, const char *cfg, size_t len); +extern int git_config_backend_from_string( + git_config_backend **out, + const char *origin, + const char *cfg, + size_t len); GIT_INLINE(int) git_config_backend_open(git_config_backend *cfg, unsigned int level, const git_repository *repo) { diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index c86e98bf2bf..340e85691ed 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -803,11 +803,13 @@ static int read_on_variable( GIT_ERROR_CHECK_ALLOC(entry->base.value); } - entry->base.origin_path = git_config_list_add_path(parse_data->config_list, parse_data->file->path); + entry->base.backend_type = git_config_list_add_string(parse_data->config_list, CONFIG_FILE_TYPE); + GIT_ERROR_CHECK_ALLOC(entry->base.backend_type); + + entry->base.origin_path = git_config_list_add_string(parse_data->config_list, parse_data->file->path); GIT_ERROR_CHECK_ALLOC(entry->base.origin_path); entry->base.level = parse_data->level; - entry->base.backend_type = CONFIG_FILE_TYPE; entry->base.include_depth = parse_data->depth; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index f642c87a4a7..0b7a4f3600a 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -27,8 +27,8 @@ typedef struct config_list_iterator { struct git_config_list { git_refcount rc; - /* Paths to config files that contribute to these entries */ - git_strmap *paths; + /* Interned strings - paths to config files or backend types */ + git_strmap *strings; /* Config entries */ git_strmap *map; @@ -43,9 +43,9 @@ int git_config_list_new(git_config_list **out) GIT_ERROR_CHECK_ALLOC(config_list); GIT_REFCOUNT_INC(config_list); - if (git_strmap_new(&config_list->paths) < 0 || + if (git_strmap_new(&config_list->strings) < 0 || git_strmap_new(&config_list->map) < 0) { - git_strmap_free(config_list->paths); + git_strmap_free(config_list->strings); git_strmap_free(config_list->map); git__free(config_list); @@ -72,12 +72,14 @@ int git_config_list_dup_entry(git_config_list *config_list, const git_config_ent GIT_ERROR_CHECK_ALLOC(duplicated->base.value); } + duplicated->base.backend_type = git_config_list_add_string(config_list, entry->backend_type); + GIT_ERROR_CHECK_ALLOC(duplicated->base.backend_type); + if (entry->origin_path) { - duplicated->base.origin_path = git_config_list_add_path(config_list, entry->origin_path); + duplicated->base.origin_path = git_config_list_add_string(config_list, entry->origin_path); GIT_ERROR_CHECK_ALLOC(duplicated->base.origin_path); } - duplicated->base.backend_type = entry->backend_type; duplicated->base.level = entry->level; duplicated->base.include_depth = entry->include_depth; duplicated->base.free = git_config_list_entry_free; @@ -125,12 +127,12 @@ static void config_list_free(git_config_list *config_list) { config_entry_list *entry_list = NULL, *next; config_entry_map_head *head; - char *path; + char *str; - git_strmap_foreach_value(config_list->paths, path, { - git__free(path); + git_strmap_foreach_value(config_list->strings, str, { + git__free(str); }); - git_strmap_free(config_list->paths); + git_strmap_free(config_list->strings); git_strmap_foreach_value(config_list->map, head, { git__free((char *) head->entry->base.name); @@ -269,18 +271,18 @@ void git_config_list_entry_free(git_config_entry *e) git_config_list_free(entry->config_list); } -const char *git_config_list_add_path( +const char *git_config_list_add_string( git_config_list *config_list, - const char *path) + const char *str) { - const char *p; + const char *s; - if ((p = git_strmap_get(config_list->paths, path)) != NULL) - return p; + if ((s = git_strmap_get(config_list->strings, str)) != NULL) + return s; - if ((p = git__strdup(path)) == NULL || - git_strmap_set(config_list->paths, p, (void *)p) < 0) + if ((s = git__strdup(str)) == NULL || + git_strmap_set(config_list->strings, s, (void *)s) < 0) return NULL; - return p; + return s; } diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h index 83c43b9a0ff..023bca1e5ca 100644 --- a/src/libgit2/config_list.h +++ b/src/libgit2/config_list.h @@ -27,6 +27,6 @@ int git_config_list_append(git_config_list *list, git_config_list_entry *entry); int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); -const char *git_config_list_add_path(git_config_list *list, const char *path); +const char *git_config_list_add_string(git_config_list *list, const char *str); void git_config_list_entry_free(git_config_entry *entry); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 748a1471673..8faa53dcba5 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -13,11 +13,13 @@ typedef struct { git_config_backend parent; + char *type; git_config_list *config_list; git_str cfg; } config_memory_backend; typedef struct { + const char *backend_type; git_config_list *config_list; git_config_level_t level; } config_memory_parse_data; @@ -68,7 +70,7 @@ static int read_variable_cb( entry->base.value = var_value ? git__strdup(var_value) : NULL; entry->base.level = parse_data->level; entry->base.include_depth = 0; - entry->base.backend_type = "memory"; + entry->base.backend_type = parse_data->backend_type; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; @@ -90,6 +92,9 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr, memory_backend->cfg.size)) < 0) goto out; + + parse_data.backend_type = git_config_list_add_string( + memory_backend->config_list, memory_backend->type); parse_data.config_list = memory_backend->config_list; parse_data.level = level; @@ -187,12 +192,17 @@ static void config_memory_free(git_config_backend *_backend) if (backend == NULL) return; + git__free(backend->type); git_config_list_free(backend->config_list); git_str_dispose(&backend->cfg); git__free(backend); } -int git_config_backend_from_string(git_config_backend **out, const char *cfg, size_t len) +int git_config_backend_from_string( + git_config_backend **out, + const char *backend_type, + const char *cfg, + size_t len) { config_memory_backend *backend; @@ -210,6 +220,9 @@ int git_config_backend_from_string(git_config_backend **out, const char *cfg, si return -1; } + backend->type = git__strdup(backend_type ? backend_type : "in-memory"); + GIT_ERROR_CHECK_ALLOC(backend->type); + backend->parent.version = GIT_CONFIG_BACKEND_VERSION; backend->parent.readonly = 1; backend->parent.open = config_memory_open; diff --git a/tests/libgit2/config/memory.c b/tests/libgit2/config/memory.c index ae661899da7..67a61a1c573 100644 --- a/tests/libgit2/config/memory.c +++ b/tests/libgit2/config/memory.c @@ -61,7 +61,7 @@ static void assert_config_contains_all(git_config_backend *backend, static void setup_backend(const char *cfg) { - cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg))); + cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); cl_git_pass(git_config_backend_open(backend, 0, NULL)); } @@ -88,7 +88,7 @@ void test_config_memory__malformed_fails_to_open(void) const char *cfg = "[general\n" "foo=bar\n"; - cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg))); + cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); cl_git_fail(git_config_backend_open(backend, 0, NULL)); } diff --git a/tests/libgit2/config/snapshot.c b/tests/libgit2/config/snapshot.c index bfb68e21e23..87a68600ee4 100644 --- a/tests/libgit2/config/snapshot.c +++ b/tests/libgit2/config/snapshot.c @@ -153,7 +153,7 @@ void test_config_snapshot__snapshot_from_in_memory(void) int i; cl_git_pass(git_config_new(&cfg)); - cl_git_pass(git_config_backend_from_string(&backend, configuration, strlen(configuration))); + cl_git_pass(git_config_backend_from_string(&backend, "test", configuration, strlen(configuration))); cl_git_pass(git_config_add_backend(cfg, backend, 0, NULL, 0)); cl_git_pass(git_config_snapshot(&snapshot, cfg)); @@ -165,7 +165,7 @@ void test_config_snapshot__snapshot_from_in_memory(void) cl_assert_equal_s("section.key", entry->name); cl_assert_equal_s("1", entry->value); - cl_assert_equal_s("memory", entry->backend_type); + cl_assert_equal_s("test", entry->backend_type); cl_assert_equal_p(NULL, entry->origin_path); git_config_entry_free(entry); From 40ce52e51fa766f05be8bf942cfcd0b082eb2224 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 20 Jul 2023 22:27:25 +0100 Subject: [PATCH 228/816] config: provide two memory-backed config backends Provide two memory-backed configuration backends -- one that takes a string in config file format `[section] key=value` and one that takes a list of strings in `section.key=value` format. --- fuzzers/config_file_fuzzer.c | 2 +- include/git2/sys/config.h | 51 +++++++++ src/libgit2/config_backend.h | 15 --- src/libgit2/config_mem.c | 191 +++++++++++++++++++++++++++----- src/util/strlist.c | 42 +++++++ src/util/strlist.h | 16 +++ tests/libgit2/config/memory.c | 75 ++++++++++++- tests/libgit2/config/snapshot.c | 10 +- 8 files changed, 350 insertions(+), 52 deletions(-) create mode 100644 src/util/strlist.c create mode 100644 src/util/strlist.h diff --git a/fuzzers/config_file_fuzzer.c b/fuzzers/config_file_fuzzer.c index 890adbfc528..763036960b4 100644 --- a/fuzzers/config_file_fuzzer.c +++ b/fuzzers/config_file_fuzzer.c @@ -43,7 +43,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) goto out; } - if ((err = git_config_backend_from_string(&backend, (const char*)data, size)) != 0) { + if ((err = git_config_backend_from_string(&backend, (const char*)data, size, NULL)) != 0) { goto out; } if ((err = git_config_add_backend(cfg, backend, 0, NULL, 0)) != 0) { diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index 0a9005e35d4..75d20758b84 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -125,6 +125,57 @@ GIT_EXTERN(int) git_config_add_backend( const git_repository *repo, int force); +/** Options for in-memory configuration backends. */ +typedef struct { + unsigned int version; + + /** + * The type of this backend (eg, "command line"). If this is + * NULL, then this will be "in-memory". + */ + const char *backend_type; + + /** + * The path to the origin; if this is NULL then it will be + * left unset in the resulting configuration entries. + */ + const char *origin_path; +} git_config_backend_memory_options; + +#define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION 1 +#define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT { GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION } + + +/** + * Create an in-memory configuration backend from a string in standard + * git configuration file format. + * + * @param out the new backend + * @param cfg the configuration that is to be parsed + * @param len the length of the string pointed to by `cfg` + * @param opts the options to initialize this backend with, or NULL + */ +extern int git_config_backend_from_string( + git_config_backend **out, + const char *cfg, + size_t len, + git_config_backend_memory_options *opts); + +/** + * Create an in-memory configuration backend from a list of name/value + * pairs. + * + * @param out the new backend + * @param values the configuration values to set (in "key=value" format) + * @param len the length of the values array + * @param opts the options to initialize this backend with, or NULL + */ +extern int git_config_backend_from_values( + git_config_backend **out, + const char **values, + size_t len, + git_config_backend_memory_options *opts); + /** @} */ GIT_END_DECL #endif diff --git a/src/libgit2/config_backend.h b/src/libgit2/config_backend.h index 677b2236f98..37d25abe146 100644 --- a/src/libgit2/config_backend.h +++ b/src/libgit2/config_backend.h @@ -37,21 +37,6 @@ extern int git_config_backend_from_file(git_config_backend **out, const char *pa */ extern int git_config_backend_snapshot(git_config_backend **out, git_config_backend *source); -/** - * Create an in-memory configuration file backend from a string in standard - * git configuration file format. - * - * @param out the new backend - * @param origin the name of the origin to use (or NULL for "memory") - * @param cfg the configuration that is to be parsed - * @param len the length of the string pointed to by `cfg` - */ -extern int git_config_backend_from_string( - git_config_backend **out, - const char *origin, - const char *cfg, - size_t len); - GIT_INLINE(int) git_config_backend_open(git_config_backend *cfg, unsigned int level, const git_repository *repo) { return cfg->open(cfg, level, repo); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 8faa53dcba5..406aa83e6e1 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -10,16 +10,27 @@ #include "config_backend.h" #include "config_parse.h" #include "config_list.h" +#include "strlist.h" typedef struct { git_config_backend parent; - char *type; + + char *backend_type; + char *origin_path; + git_config_list *config_list; + + /* Configuration data in the config file format */ git_str cfg; + + /* Array of key=value pairs */ + char **values; + size_t values_len; } config_memory_backend; typedef struct { const char *backend_type; + const char *origin_path; git_config_list *config_list; git_config_level_t level; } config_memory_parse_data; @@ -71,6 +82,7 @@ static int read_variable_cb( entry->base.level = parse_data->level; entry->base.include_depth = 0; entry->base.backend_type = parse_data->backend_type; + entry->base.origin_path = parse_data->origin_path; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; @@ -80,25 +92,29 @@ static int read_variable_cb( return result; } -static int config_memory_open(git_config_backend *backend, git_config_level_t level, const git_repository *repo) +static int parse_config( + config_memory_backend *memory_backend, + git_config_level_t level) { - config_memory_backend *memory_backend = (config_memory_backend *) backend; git_config_parser parser = GIT_PARSE_CTX_INIT; config_memory_parse_data parse_data; int error; - GIT_UNUSED(repo); - - if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr, - memory_backend->cfg.size)) < 0) + if ((error = git_config_parser_init(&parser, "in-memory", + memory_backend->cfg.ptr, memory_backend->cfg.size)) < 0) goto out; parse_data.backend_type = git_config_list_add_string( - memory_backend->config_list, memory_backend->type); + memory_backend->config_list, memory_backend->backend_type); + parse_data.origin_path = memory_backend->origin_path ? + git_config_list_add_string(memory_backend->config_list, + memory_backend->origin_path) : + NULL; parse_data.config_list = memory_backend->config_list; parse_data.level = level; - if ((error = git_config_parse(&parser, NULL, read_variable_cb, NULL, NULL, &parse_data)) < 0) + if ((error = git_config_parse(&parser, NULL, read_variable_cb, + NULL, NULL, &parse_data)) < 0) goto out; out: @@ -106,6 +122,74 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le return error; } +static int parse_values( + config_memory_backend *memory_backend, + git_config_level_t level) +{ + git_config_list_entry *entry; + const char *eql, *backend_type, *origin_path; + size_t name_len, i; + + backend_type = git_config_list_add_string( + memory_backend->config_list, memory_backend->backend_type); + GIT_ERROR_CHECK_ALLOC(backend_type); + + origin_path = memory_backend->origin_path ? + git_config_list_add_string(memory_backend->config_list, + memory_backend->origin_path) : + NULL; + + for (i = 0; i < memory_backend->values_len; i++) { + eql = strchr(memory_backend->values[i], '='); + name_len = eql - memory_backend->values[i]; + + if (name_len == 0) { + git_error_set(GIT_ERROR_CONFIG, "empty config key"); + return -1; + } + + entry = git__calloc(1, sizeof(git_config_list_entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->base.name = git__strndup(memory_backend->values[i], name_len); + GIT_ERROR_CHECK_ALLOC(entry->base.name); + + if (eql) { + entry->base.value = git__strdup(eql + 1); + GIT_ERROR_CHECK_ALLOC(entry->base.value); + } + + entry->base.level = level; + entry->base.include_depth = 0; + entry->base.backend_type = backend_type; + entry->base.origin_path = origin_path; + entry->base.free = git_config_list_entry_free; + entry->config_list = memory_backend->config_list; + + if (git_config_list_append(memory_backend->config_list, entry) < 0) + return -1; + } + + return 0; +} + +static int config_memory_open(git_config_backend *backend, git_config_level_t level, const git_repository *repo) +{ + config_memory_backend *memory_backend = (config_memory_backend *) backend; + + GIT_UNUSED(repo); + + if (memory_backend->cfg.size > 0 && + parse_config(memory_backend, level) < 0) + return -1; + + if (memory_backend->values_len > 0 && + parse_values(memory_backend, level) < 0) + return -1; + + return 0; +} + static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) { config_memory_backend *memory_backend = (config_memory_backend *) backend; @@ -192,36 +276,24 @@ static void config_memory_free(git_config_backend *_backend) if (backend == NULL) return; - git__free(backend->type); + git__free(backend->origin_path); + git__free(backend->backend_type); git_config_list_free(backend->config_list); + git_strlist_free(backend->values, backend->values_len); git_str_dispose(&backend->cfg); git__free(backend); } -int git_config_backend_from_string( - git_config_backend **out, - const char *backend_type, - const char *cfg, - size_t len) +static config_memory_backend *config_backend_new( + git_config_backend_memory_options *opts) { config_memory_backend *backend; - backend = git__calloc(1, sizeof(config_memory_backend)); - GIT_ERROR_CHECK_ALLOC(backend); - - if (git_config_list_new(&backend->config_list) < 0) { - git__free(backend); - return -1; - } - - if (git_str_set(&backend->cfg, cfg, len) < 0) { - git_config_list_free(backend->config_list); - git__free(backend); - return -1; - } + if ((backend = git__calloc(1, sizeof(config_memory_backend))) == NULL) + return NULL; - backend->type = git__strdup(backend_type ? backend_type : "in-memory"); - GIT_ERROR_CHECK_ALLOC(backend->type); + if (git_config_list_new(&backend->config_list) < 0) + goto on_error; backend->parent.version = GIT_CONFIG_BACKEND_VERSION; backend->parent.readonly = 1; @@ -237,7 +309,66 @@ int git_config_backend_from_string( backend->parent.snapshot = git_config_backend_snapshot; backend->parent.free = config_memory_free; + backend->backend_type = git__strdup(opts && opts->backend_type ? + opts->backend_type : "in-memory"); + + if (backend->backend_type == NULL) + goto on_error; + + if (opts && opts->origin_path && + (backend->origin_path = git__strdup(opts->origin_path)) == NULL) + goto on_error; + + return backend; + +on_error: + git_config_list_free(backend->config_list); + git__free(backend->origin_path); + git__free(backend->backend_type); + git__free(backend); + return NULL; +} + +int git_config_backend_from_string( + git_config_backend **out, + const char *cfg, + size_t len, + git_config_backend_memory_options *opts) +{ + config_memory_backend *backend; + + if ((backend = config_backend_new(opts)) == NULL) + return -1; + + if (git_str_set(&backend->cfg, cfg, len) < 0) { + git_config_list_free(backend->config_list); + git__free(backend); + return -1; + } + *out = (git_config_backend *)backend; + return 0; +} + +int git_config_backend_from_values( + git_config_backend **out, + const char **values, + size_t len, + git_config_backend_memory_options *opts) +{ + config_memory_backend *backend; + if ((backend = config_backend_new(opts)) == NULL) + return -1; + + if (git_strlist_copy(&backend->values, values, len) < 0) { + git_config_list_free(backend->config_list); + git__free(backend); + return -1; + } + + backend->values_len = len; + + *out = (git_config_backend *)backend; return 0; } diff --git a/src/util/strlist.c b/src/util/strlist.c new file mode 100644 index 00000000000..af9b4bbd34d --- /dev/null +++ b/src/util/strlist.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include + +#include "git2_util.h" +#include "vector.h" +#include "strlist.h" + +int git_strlist_copy(char ***out, const char **in, size_t len) +{ + char **dup; + size_t i; + + dup = git__calloc(len, sizeof(char *)); + GIT_ERROR_CHECK_ALLOC(dup); + + for (i = 0; i < len; i++) { + dup[i] = git__strdup(in[i]); + GIT_ERROR_CHECK_ALLOC(dup[i]); + } + + *out = dup; + return 0; +} + +void git_strlist_free(char **strings, size_t len) +{ + size_t i; + + if (!strings) + return; + + for (i = 0; i < len; i++) + git__free(strings[i]); + + git__free(strings); +} diff --git a/src/util/strlist.h b/src/util/strlist.h new file mode 100644 index 00000000000..089a8bb57b3 --- /dev/null +++ b/src/util/strlist.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_runtime_h__ +#define INCLUDE_runtime_h__ + +#include "git2_util.h" + +extern int git_strlist_copy(char ***out, const char **in, size_t len); +extern void git_strlist_free(char **strings, size_t len); + +#endif diff --git a/tests/libgit2/config/memory.c b/tests/libgit2/config/memory.c index 67a61a1c573..9f533e282fd 100644 --- a/tests/libgit2/config/memory.c +++ b/tests/libgit2/config/memory.c @@ -34,8 +34,13 @@ static int contains_all_cb(const git_config_entry *entry, void *payload) int i; for (i = 0; entries[i].name; i++) { - if (strcmp(entries[i].name, entry->name) || - strcmp(entries[i].value , entry->value)) + if (strcmp(entries[i].name, entry->name)) + continue; + + if ((entries[i].value == NULL) ^ (entry->value == NULL)) + continue; + + if (entry->value && strcmp(entries[i].value , entry->value)) continue; if (entries[i].seen) @@ -61,7 +66,23 @@ static void assert_config_contains_all(git_config_backend *backend, static void setup_backend(const char *cfg) { - cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg), &opts)); + cl_git_pass(git_config_backend_open(backend, 0, NULL)); +} + +static void setup_values_backend(const char **values, size_t len) +{ + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_values(&backend, values, len, &opts)); cl_git_pass(git_config_backend_open(backend, 0, NULL)); } @@ -88,7 +109,13 @@ void test_config_memory__malformed_fails_to_open(void) const char *cfg = "[general\n" "foo=bar\n"; - cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); + + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg), &opts)); cl_git_fail(git_config_backend_open(backend, 0, NULL)); } @@ -137,3 +164,43 @@ void test_config_memory__foreach_sees_multivar(void) "foo=bar2\n"); assert_config_contains_all(backend, entries); } + +void test_config_memory__values(void) +{ + const char *values[] = { + "general.foo=bar1", + "general.foo=bar2", + "other.key=value", + "empty.value=", + "no.value", + }; + + struct expected_entry entries[] = { + { "general.foo", "bar1", 0 }, + { "general.foo", "bar2", 0 }, + { "other.key", "value", 0 }, + { "empty.value", "", 0 }, + { "no.value", NULL, 0 }, + { NULL, NULL, 0 } + }; + + setup_values_backend(values, 5); + assert_config_contains_all(backend, entries); +} + +void test_config_memory__valid_values(void) +{ + const char *values[] = { + "general.foo=bar1", + "=bar2", + "other.key=value" + }; + + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_values(&backend, values, 3, &opts)); + cl_git_fail(git_config_backend_open(backend, 0, NULL)); +} diff --git a/tests/libgit2/config/snapshot.c b/tests/libgit2/config/snapshot.c index 87a68600ee4..cc877063c08 100644 --- a/tests/libgit2/config/snapshot.c +++ b/tests/libgit2/config/snapshot.c @@ -152,8 +152,14 @@ void test_config_snapshot__snapshot_from_in_memory(void) git_config_entry *entry; int i; + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + opts.origin_path = "hello"; + cl_git_pass(git_config_new(&cfg)); - cl_git_pass(git_config_backend_from_string(&backend, "test", configuration, strlen(configuration))); + cl_git_pass(git_config_backend_from_string(&backend, configuration, strlen(configuration), &opts)); cl_git_pass(git_config_add_backend(cfg, backend, 0, NULL, 0)); cl_git_pass(git_config_snapshot(&snapshot, cfg)); @@ -166,7 +172,7 @@ void test_config_snapshot__snapshot_from_in_memory(void) cl_assert_equal_s("section.key", entry->name); cl_assert_equal_s("1", entry->value); cl_assert_equal_s("test", entry->backend_type); - cl_assert_equal_p(NULL, entry->origin_path); + cl_assert_equal_s("hello", entry->origin_path); git_config_entry_free(entry); } From f7c746a2ef3e7e0e7e90bda17178eb5a87cc130b Mon Sep 17 00:00:00 2001 From: David Runge Date: Fri, 21 Jul 2023 16:18:39 +0200 Subject: [PATCH 229/816] fix: Add missing include for oidarray. Add a missing include for `git2/oidarray.h` so build doesn't fail on using `git_oidarray` when using custom transports. Fixes #6607 --- include/git2/sys/transport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 96a35d08cb2..370ca45d570 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -9,6 +9,7 @@ #define INCLUDE_sys_git_transport_h #include "git2/net.h" +#include "git2/oidarray.h" #include "git2/proxy.h" #include "git2/remote.h" #include "git2/strarray.h" From 3e15292d8863da316a57be23fede04f443460686 Mon Sep 17 00:00:00 2001 From: Christopher Nielsen Date: Mon, 24 Jul 2023 20:37:34 -0400 Subject: [PATCH 230/816] stransport: macos: replace errSSLNetworkTimeout, with hard-coded value - Constant only available in 10.13+, causing build failures for older macOS releases Fixes: https://github.com/libgit2/libgit2/issues/6606 --- src/libgit2/streams/stransport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index d956df84d10..7a3585e246b 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -162,7 +162,7 @@ static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len) if (ret < 0) { st->error = ret; return (ret == GIT_TIMEOUT) ? - errSSLNetworkTimeout : + -9853 /* errSSLNetworkTimeout */: -36 /* ioErr */; } @@ -214,7 +214,7 @@ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) if (ret < 0) { st->error = ret; error = (ret == GIT_TIMEOUT) ? - errSSLNetworkTimeout : + -9853 /* errSSLNetworkTimeout */: -36 /* ioErr */; break; } else if (ret == 0) { From 23ba7aedff74043ac178e8dca24109b5aa1dffe0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 19 Jul 2023 11:17:03 +0100 Subject: [PATCH 231/816] config: complete entry during creation Don't set entry data when we "get" an entry from the collection, add the data to the entry before it's put into the collection. This keeps the entry creation logic in a single place. --- src/libgit2/config_file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 716924de600..6fc4c6fc21d 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -359,8 +359,6 @@ static int config_file_get(git_config_backend *cfg, const char *key, git_config_ return error; } - entry->free = config_file_entry_free; - entry->payload = entries; *out = entry; return 0; @@ -805,6 +803,8 @@ static int read_on_variable( entry->value = var_value ? git__strdup(var_value) : NULL; entry->level = parse_data->level; entry->include_depth = parse_data->depth; + entry->free = config_file_entry_free; + entry->payload = parse_data->entries; if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) return result; From 1951864f7da3dc720dc56ce170a17a2a8b80130c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 19 Jul 2023 12:23:07 +0100 Subject: [PATCH 232/816] config: rename config_entries to config_list --- src/libgit2/config_entries.h | 24 ---- src/libgit2/config_file.c | 124 ++++++++--------- .../{config_entries.c => config_list.c} | 127 +++++++++--------- src/libgit2/config_list.h | 24 ++++ src/libgit2/config_mem.c | 28 ++-- src/libgit2/config_snapshot.c | 42 +++--- 6 files changed, 185 insertions(+), 184 deletions(-) delete mode 100644 src/libgit2/config_entries.h rename src/libgit2/{config_entries.c => config_list.c} (50%) create mode 100644 src/libgit2/config_list.h diff --git a/src/libgit2/config_entries.h b/src/libgit2/config_entries.h deleted file mode 100644 index 832379e7466..00000000000 --- a/src/libgit2/config_entries.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "git2/sys/config.h" -#include "config.h" - -typedef struct git_config_entries git_config_entries; - -int git_config_entries_new(git_config_entries **out); -int git_config_entries_dup(git_config_entries **out, git_config_entries *entries); -int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry); -void git_config_entries_incref(git_config_entries *entries); -void git_config_entries_free(git_config_entries *entries); -/* Add or append the new config option */ -int git_config_entries_append(git_config_entries *entries, git_config_entry *entry); -int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key); -int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key); -int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries); diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 6fc4c6fc21d..41241f1b0f5 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -13,7 +13,7 @@ #include "array.h" #include "str.h" #include "config_backend.h" -#include "config_entries.h" +#include "config_list.h" #include "config_parse.h" #include "filebuf.h" #include "regexp.h" @@ -34,7 +34,7 @@ typedef struct config_file { typedef struct { git_config_backend parent; git_mutex values_mutex; - git_config_entries *entries; + git_config_list *config_list; const git_repository *repo; git_config_level_t level; @@ -50,13 +50,13 @@ typedef struct { typedef struct { const git_repository *repo; config_file *file; - git_config_entries *entries; + git_config_list *config_list; git_config_level_t level; unsigned int depth; } config_file_parse_data; -static int config_file_read(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth); -static int config_file_read_buffer(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); +static int config_file_read(git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, int depth); +static int config_file_read_buffer(git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value); static char *escape_value(const char *ptr); @@ -65,7 +65,7 @@ static char *escape_value(const char *ptr); * refcount. This is its own function to make sure we use the mutex to * avoid the map pointer from changing under us. */ -static int config_file_entries_take(git_config_entries **out, config_file_backend *b) +static int config_file_take_list(git_config_list **out, config_file_backend *b) { int error; @@ -74,8 +74,8 @@ static int config_file_entries_take(git_config_entries **out, config_file_backen return error; } - git_config_entries_incref(b->entries); - *out = b->entries; + git_config_list_incref(b->config_list); + *out = b->config_list; git_mutex_unlock(&b->values_mutex); @@ -106,7 +106,7 @@ static int config_file_open(git_config_backend *cfg, git_config_level_t level, c b->level = level; b->repo = repo; - if ((res = git_config_entries_new(&b->entries)) < 0) + if ((res = git_config_list_new(&b->config_list)) < 0) return res; if (!git_fs_path_exists(b->file.path)) @@ -121,9 +121,9 @@ static int config_file_open(git_config_backend *cfg, git_config_level_t level, c if (p_access(b->file.path, R_OK) < 0) return GIT_ENOTFOUND; - if (res < 0 || (res = config_file_read(b->entries, repo, &b->file, level, 0)) < 0) { - git_config_entries_free(b->entries); - b->entries = NULL; + if (res < 0 || (res = config_file_read(b->config_list, repo, &b->file, level, 0)) < 0) { + git_config_list_free(b->config_list); + b->config_list = NULL; } return res; @@ -175,10 +175,10 @@ static void config_file_clear_includes(config_file_backend *cfg) git_array_clear(cfg->file.includes); } -static int config_file_set_entries(git_config_backend *cfg, git_config_entries *entries) +static int config_file_set_entries(git_config_backend *cfg, git_config_list *config_list) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *old = NULL; + git_config_list *old = NULL; int error; if (b->parent.readonly) { @@ -191,40 +191,40 @@ static int config_file_set_entries(git_config_backend *cfg, git_config_entries * goto out; } - old = b->entries; - b->entries = entries; + old = b->config_list; + b->config_list = config_list; git_mutex_unlock(&b->values_mutex); out: - git_config_entries_free(old); + git_config_list_free(old); return error; } static int config_file_refresh_from_buffer(git_config_backend *cfg, const char *buf, size_t buflen) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error; config_file_clear_includes(b); - if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_file_read_buffer(entries, b->repo, &b->file, + if ((error = git_config_list_new(&config_list)) < 0 || + (error = config_file_read_buffer(config_list, b->repo, &b->file, b->level, 0, buf, buflen)) < 0 || - (error = config_file_set_entries(cfg, entries)) < 0) + (error = config_file_set_entries(cfg, config_list)) < 0) goto out; - entries = NULL; + config_list = NULL; out: - git_config_entries_free(entries); + git_config_list_free(config_list); return error; } static int config_file_refresh(git_config_backend *cfg) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error, modified; if (cfg->readonly) @@ -238,14 +238,14 @@ static int config_file_refresh(git_config_backend *cfg) config_file_clear_includes(b); - if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_file_read(entries, b->repo, &b->file, b->level, 0)) < 0 || - (error = config_file_set_entries(cfg, entries)) < 0) + if ((error = git_config_list_new(&config_list)) < 0 || + (error = config_file_read(config_list, b->repo, &b->file, b->level, 0)) < 0 || + (error = config_file_set_entries(cfg, config_list)) < 0) goto out; - entries = NULL; + config_list = NULL; out: - git_config_entries_free(entries); + git_config_list_free(config_list); return (error == GIT_ENOTFOUND) ? 0 : error; } @@ -258,7 +258,7 @@ static void config_file_free(git_config_backend *_backend) return; config_file_clear(&backend->file); - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_mutex_free(&backend->values_mutex); git__free(backend); } @@ -268,19 +268,19 @@ static int config_file_iterator( struct git_config_backend *backend) { config_file_backend *b = GIT_CONTAINER_OF(backend, config_file_backend, parent); - git_config_entries *dupped = NULL, *entries = NULL; + git_config_list *dupped = NULL, *config_list = NULL; int error; if ((error = config_file_refresh(backend)) < 0 || - (error = config_file_entries_take(&entries, b)) < 0 || - (error = git_config_entries_dup(&dupped, entries)) < 0 || - (error = git_config_entries_iterator_new(iter, dupped)) < 0) + (error = config_file_take_list(&config_list, b)) < 0 || + (error = git_config_list_dup(&dupped, config_list)) < 0 || + (error = git_config_list_iterator_new(iter, dupped)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); - git_config_entries_free(dupped); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); + git_config_list_free(dupped); return error; } @@ -292,7 +292,7 @@ static int config_file_snapshot(git_config_backend **out, git_config_backend *ba static int config_file_set(git_config_backend *cfg, const char *name, const char *value) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries; + git_config_list *config_list; git_config_entry *existing; char *key, *esc_value = NULL; int error; @@ -300,11 +300,11 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char if ((error = git_config__normalize_name(name, &key)) < 0) return error; - if ((error = config_file_entries_take(&entries, b)) < 0) + if ((error = config_file_take_list(&config_list, b)) < 0) return error; /* Check whether we'd be modifying an included or multivar key */ - if ((error = git_config_entries_get_unique(&existing, entries, key)) < 0) { + if ((error = git_config_list_get_unique(&existing, config_list, key)) < 0) { if (error != GIT_ENOTFOUND) goto out; error = 0; @@ -325,7 +325,7 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(esc_value); git__free(key); return error; @@ -334,8 +334,8 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char /* release the map containing the entry as an equivalent to freeing it */ static void config_file_entry_free(git_config_entry *entry) { - git_config_entries *entries = (git_config_entries *) entry->payload; - git_config_entries_free(entries); + git_config_list *config_list = (git_config_list *) entry->payload; + git_config_list_free(config_list); } /* @@ -344,18 +344,18 @@ static void config_file_entry_free(git_config_entry *entry) static int config_file_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry; int error = 0; if (!h->parent.readonly && ((error = config_file_refresh(cfg)) < 0)) return error; - if ((error = config_file_entries_take(&entries, h)) < 0) + if ((error = config_file_take_list(&config_list, h)) < 0) return error; - if ((error = (git_config_entries_get(&entry, entries, key))) < 0) { - git_config_entries_free(entries); + if ((error = (git_config_list_get(&entry, config_list, key))) < 0) { + git_config_list_free(config_list); return error; } @@ -394,7 +394,7 @@ static int config_file_set_multivar( static int config_file_delete(git_config_backend *cfg, const char *name) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry; char *key = NULL; int error; @@ -402,11 +402,11 @@ static int config_file_delete(git_config_backend *cfg, const char *name) if ((error = git_config__normalize_name(name, &key)) < 0) goto out; - if ((error = config_file_entries_take(&entries, b)) < 0) + if ((error = config_file_take_list(&config_list, b)) < 0) goto out; /* Check whether we'd be modifying an included or multivar key */ - if ((error = git_config_entries_get_unique(&entry, entries, key)) < 0) { + if ((error = git_config_list_get_unique(&entry, config_list, key)) < 0) { if (error == GIT_ENOTFOUND) git_error_set(GIT_ERROR_CONFIG, "could not find key '%s' to delete", name); goto out; @@ -416,7 +416,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(key); return error; } @@ -424,7 +424,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) static int config_file_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry = NULL; git_regexp preg = GIT_REGEX_INIT; char *key = NULL; @@ -433,10 +433,10 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name if ((result = git_config__normalize_name(name, &key)) < 0) goto out; - if ((result = config_file_entries_take(&entries, b)) < 0) + if ((result = config_file_take_list(&config_list, b)) < 0) goto out; - if ((result = git_config_entries_get(&entry, entries, key)) < 0) { + if ((result = git_config_list_get(&entry, config_list, key)) < 0) { if (result == GIT_ENOTFOUND) git_error_set(GIT_ERROR_CONFIG, "could not find key '%s' to delete", name); goto out; @@ -449,7 +449,7 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(key); git_regexp_dispose(&preg); return result; @@ -589,7 +589,7 @@ static int parse_include(config_file_parse_data *parse_data, const char *file) git_array_init(include->includes); include->path = git_str_detach(&path); - result = config_file_read(parse_data->entries, parse_data->repo, include, + result = config_file_read(parse_data->config_list, parse_data->repo, include, parse_data->level, parse_data->depth+1); if (result == GIT_ENOTFOUND) { @@ -804,9 +804,9 @@ static int read_on_variable( entry->level = parse_data->level; entry->include_depth = parse_data->depth; entry->free = config_file_entry_free; - entry->payload = parse_data->entries; + entry->payload = parse_data->config_list; - if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) + if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; result = 0; @@ -822,7 +822,7 @@ static int read_on_variable( } static int config_file_read_buffer( - git_config_entries *entries, + git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, @@ -851,7 +851,7 @@ static int config_file_read_buffer( parse_data.repo = repo; parse_data.file = file; - parse_data.entries = entries; + parse_data.config_list = config_list; parse_data.level = level; parse_data.depth = depth; @@ -862,7 +862,7 @@ static int config_file_read_buffer( } static int config_file_read( - git_config_entries *entries, + git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, @@ -884,7 +884,7 @@ static int config_file_read( if ((error = git_hash_buf(file->checksum, contents.ptr, contents.size, GIT_HASH_ALGORITHM_SHA256)) < 0) goto out; - if ((error = config_file_read_buffer(entries, repo, file, level, depth, + if ((error = config_file_read_buffer(config_list, repo, file, level, depth, contents.ptr, contents.size)) < 0) goto out; diff --git a/src/libgit2/config_entries.c b/src/libgit2/config_list.c similarity index 50% rename from src/libgit2/config_entries.c rename to src/libgit2/config_list.c index 66aae096d2d..01d41526e98 100644 --- a/src/libgit2/config_entries.c +++ b/src/libgit2/config_list.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "config_entries.h" +#include "config_list.h" typedef struct config_entry_list { struct config_entry_list *next; @@ -18,36 +18,36 @@ typedef struct { bool multivar; } config_entry_map_head; -typedef struct config_entries_iterator { +typedef struct config_list_iterator { git_config_iterator parent; - git_config_entries *entries; + git_config_list *list; config_entry_list *head; -} config_entries_iterator; +} config_list_iterator; -struct git_config_entries { +struct git_config_list { git_refcount rc; git_strmap *map; - config_entry_list *list; + config_entry_list *entries; }; -int git_config_entries_new(git_config_entries **out) +int git_config_list_new(git_config_list **out) { - git_config_entries *entries; + git_config_list *config_list; int error; - entries = git__calloc(1, sizeof(git_config_entries)); - GIT_ERROR_CHECK_ALLOC(entries); - GIT_REFCOUNT_INC(entries); + config_list = git__calloc(1, sizeof(git_config_list)); + GIT_ERROR_CHECK_ALLOC(config_list); + GIT_REFCOUNT_INC(config_list); - if ((error = git_strmap_new(&entries->map)) < 0) - git__free(entries); + if ((error = git_strmap_new(&config_list->map)) < 0) + git__free(config_list); else - *out = entries; + *out = config_list; return error; } -int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry) +int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry) { git_config_entry *duplicated; int error; @@ -65,7 +65,7 @@ int git_config_entries_dup_entry(git_config_entries *entries, const git_config_e duplicated->level = entry->level; duplicated->include_depth = entry->include_depth; - if ((error = git_config_entries_append(entries, duplicated)) < 0) + if ((error = git_config_list_append(config_list, duplicated)) < 0) goto out; out: @@ -77,78 +77,79 @@ int git_config_entries_dup_entry(git_config_entries *entries, const git_config_e return error; } -int git_config_entries_dup(git_config_entries **out, git_config_entries *entries) +int git_config_list_dup(git_config_list **out, git_config_list *config_list) { - git_config_entries *result = NULL; + git_config_list *result = NULL; config_entry_list *head; int error; - if ((error = git_config_entries_new(&result)) < 0) + if ((error = git_config_list_new(&result)) < 0) goto out; - for (head = entries->list; head; head = head->next) - if ((git_config_entries_dup_entry(result, head->entry)) < 0) + for (head = config_list->entries; head; head = head->next) + if ((git_config_list_dup_entry(result, head->entry)) < 0) goto out; *out = result; result = NULL; out: - git_config_entries_free(result); + git_config_list_free(result); return error; } -void git_config_entries_incref(git_config_entries *entries) +void git_config_list_incref(git_config_list *config_list) { - GIT_REFCOUNT_INC(entries); + GIT_REFCOUNT_INC(config_list); } -static void config_entries_free(git_config_entries *entries) +static void config_list_free(git_config_list *config_list) { - config_entry_list *list = NULL, *next; + config_entry_list *entry_list = NULL, *next; config_entry_map_head *head; - git_strmap_foreach_value(entries->map, head, - git__free((char *) head->entry->name); git__free(head) - ); - git_strmap_free(entries->map); - - list = entries->list; - while (list != NULL) { - next = list->next; - git__free((char *) list->entry->value); - git__free(list->entry); - git__free(list); - list = next; + git_strmap_foreach_value(config_list->map, head, { + git__free((char *) head->entry->name); + git__free(head); + }); + git_strmap_free(config_list->map); + + entry_list = config_list->entries; + while (entry_list != NULL) { + next = entry_list->next; + git__free((char *) entry_list->entry->value); + git__free(entry_list->entry); + git__free(entry_list); + entry_list = next; } - git__free(entries); + git__free(config_list); } -void git_config_entries_free(git_config_entries *entries) +void git_config_list_free(git_config_list *config_list) { - if (entries) - GIT_REFCOUNT_DEC(entries, config_entries_free); + if (config_list) + GIT_REFCOUNT_DEC(config_list, config_list_free); } -int git_config_entries_append(git_config_entries *entries, git_config_entry *entry) +int git_config_list_append(git_config_list *config_list, git_config_entry *entry) { config_entry_list *list_head; config_entry_map_head *map_head; - if ((map_head = git_strmap_get(entries->map, entry->name)) != NULL) { + if ((map_head = git_strmap_get(config_list->map, entry->name)) != NULL) { map_head->multivar = true; /* * This is a micro-optimization for configuration files * with a lot of same keys. As for multivars the entry's - * key will be the same for all entries, we can just free + * key will be the same for all list, we can just free * all except the first entry's name and just re-use it. */ git__free((char *) entry->name); entry->name = map_head->entry->name; } else { map_head = git__calloc(1, sizeof(*map_head)); - if ((git_strmap_set(entries->map, entry->name, map_head)) < 0) + if ((git_strmap_set(config_list->map, entry->name, map_head)) < 0) return -1; } map_head->entry = entry; @@ -157,29 +158,29 @@ int git_config_entries_append(git_config_entries *entries, git_config_entry *ent GIT_ERROR_CHECK_ALLOC(list_head); list_head->entry = entry; - if (entries->list) - entries->list->last->next = list_head; + if (config_list->entries) + config_list->entries->last->next = list_head; else - entries->list = list_head; - entries->list->last = list_head; + config_list->entries = list_head; + config_list->entries->last = list_head; return 0; } -int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key) +int git_config_list_get(git_config_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; - if ((entry = git_strmap_get(entries->map, key)) == NULL) + if ((entry = git_strmap_get(config_list->map, key)) == NULL) return GIT_ENOTFOUND; *out = entry->entry; return 0; } -int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key) +int git_config_list_get_unique(git_config_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; - if ((entry = git_strmap_get(entries->map, key)) == NULL) + if ((entry = git_strmap_get(config_list->map, key)) == NULL) return GIT_ENOTFOUND; if (entry->multivar) { @@ -199,8 +200,8 @@ int git_config_entries_get_unique(git_config_entry **out, git_config_entries *en static void config_iterator_free(git_config_iterator *iter) { - config_entries_iterator *it = (config_entries_iterator *) iter; - git_config_entries_free(it->entries); + config_list_iterator *it = (config_list_iterator *) iter; + git_config_list_free(it->list); git__free(it); } @@ -208,7 +209,7 @@ static int config_iterator_next( git_config_entry **entry, git_config_iterator *iter) { - config_entries_iterator *it = (config_entries_iterator *) iter; + config_list_iterator *it = (config_list_iterator *) iter; if (!it->head) return GIT_ITEROVER; @@ -219,18 +220,18 @@ static int config_iterator_next( return 0; } -int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries) +int git_config_list_iterator_new(git_config_iterator **out, git_config_list *config_list) { - config_entries_iterator *it; + config_list_iterator *it; - it = git__calloc(1, sizeof(config_entries_iterator)); + it = git__calloc(1, sizeof(config_list_iterator)); GIT_ERROR_CHECK_ALLOC(it); it->parent.next = config_iterator_next; it->parent.free = config_iterator_free; - it->head = entries->list; - it->entries = entries; + it->head = config_list->entries; + it->list = config_list; - git_config_entries_incref(entries); + git_config_list_incref(config_list); *out = &it->parent; return 0; diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h new file mode 100644 index 00000000000..e14e4aed023 --- /dev/null +++ b/src/libgit2/config_list.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "git2/sys/config.h" +#include "config.h" + +typedef struct git_config_list git_config_list; + +int git_config_list_new(git_config_list **out); +int git_config_list_dup(git_config_list **out, git_config_list *list); +int git_config_list_dup_entry(git_config_list *list, const git_config_entry *entry); +void git_config_list_incref(git_config_list *list); +void git_config_list_free(git_config_list *list); +/* Add or append the new config option */ +int git_config_list_append(git_config_list *list, git_config_entry *entry); +int git_config_list_get(git_config_entry **out, git_config_list *list, const char *key); +int git_config_list_get_unique(git_config_entry **out, git_config_list *list, const char *key); +int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 560229cf534..902bf99e6a3 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -9,16 +9,16 @@ #include "config_backend.h" #include "config_parse.h" -#include "config_entries.h" +#include "config_list.h" typedef struct { git_config_backend parent; - git_config_entries *entries; + git_config_list *config_list; git_str cfg; } config_memory_backend; typedef struct { - git_config_entries *entries; + git_config_list *config_list; git_config_level_t level; } config_memory_parse_data; @@ -69,7 +69,7 @@ static int read_variable_cb( entry->level = parse_data->level; entry->include_depth = 0; - if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) + if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; return result; @@ -87,7 +87,7 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr, memory_backend->cfg.size)) < 0) goto out; - parse_data.entries = memory_backend->entries; + parse_data.config_list = memory_backend->config_list; parse_data.level = level; if ((error = git_config_parse(&parser, NULL, read_variable_cb, NULL, NULL, &parse_data)) < 0) @@ -101,7 +101,7 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) { config_memory_backend *memory_backend = (config_memory_backend *) backend; - return git_config_entries_get(out, memory_backend->entries, key); + return git_config_list_get(out, memory_backend->config_list, key); } static int config_memory_iterator( @@ -109,18 +109,18 @@ static int config_memory_iterator( git_config_backend *backend) { config_memory_backend *memory_backend = (config_memory_backend *) backend; - git_config_entries *entries; + git_config_list *config_list; int error; - if ((error = git_config_entries_dup(&entries, memory_backend->entries)) < 0) + if ((error = git_config_list_dup(&config_list, memory_backend->config_list)) < 0) goto out; - if ((error = git_config_entries_iterator_new(iter, entries)) < 0) + if ((error = git_config_list_iterator_new(iter, config_list)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); return error; } @@ -177,7 +177,7 @@ static void config_memory_free(git_config_backend *_backend) if (backend == NULL) return; - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_str_dispose(&backend->cfg); git__free(backend); } @@ -189,13 +189,13 @@ int git_config_backend_from_string(git_config_backend **out, const char *cfg, si backend = git__calloc(1, sizeof(config_memory_backend)); GIT_ERROR_CHECK_ALLOC(backend); - if (git_config_entries_new(&backend->entries) < 0) { + if (git_config_list_new(&backend->config_list) < 0) { git__free(backend); return -1; } if (git_str_set(&backend->cfg, cfg, len) < 0) { - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git__free(backend); return -1; } diff --git a/src/libgit2/config_snapshot.c b/src/libgit2/config_snapshot.c index e295d2f7f28..dbd05ffdce7 100644 --- a/src/libgit2/config_snapshot.c +++ b/src/libgit2/config_snapshot.c @@ -8,12 +8,12 @@ #include "config_backend.h" #include "config.h" -#include "config_entries.h" +#include "config_list.h" typedef struct { git_config_backend parent; git_mutex values_mutex; - git_config_entries *entries; + git_config_list *config_list; git_config_backend *source; } config_snapshot_backend; @@ -28,30 +28,30 @@ static int config_snapshot_iterator( struct git_config_backend *backend) { config_snapshot_backend *b = GIT_CONTAINER_OF(backend, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error; - if ((error = git_config_entries_dup(&entries, b->entries)) < 0 || - (error = git_config_entries_iterator_new(iter, entries)) < 0) + if ((error = git_config_list_dup(&config_list, b->config_list)) < 0 || + (error = git_config_list_iterator_new(iter, config_list)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); return error; } /* release the map containing the entry as an equivalent to freeing it */ static void config_snapshot_entry_free(git_config_entry *entry) { - git_config_entries *entries = (git_config_entries *) entry->payload; - git_config_entries_free(entries); + git_config_list *config_list = (git_config_list *) entry->payload; + git_config_list_free(config_list); } static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_entry *entry; int error = 0; @@ -60,17 +60,17 @@ static int config_snapshot_get(git_config_backend *cfg, const char *key, git_con return -1; } - entries = b->entries; - git_config_entries_incref(entries); + config_list = b->config_list; + git_config_list_incref(config_list); git_mutex_unlock(&b->values_mutex); - if ((error = (git_config_entries_get(&entry, entries, key))) < 0) { - git_config_entries_free(entries); + if ((error = (git_config_list_get(&entry, config_list, key))) < 0) { + git_config_list_free(config_list); return error; } entry->free = config_snapshot_entry_free; - entry->payload = entries; + entry->payload = config_list; *out = entry; return 0; @@ -135,7 +135,7 @@ static void config_snapshot_free(git_config_backend *_backend) if (backend == NULL) return; - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_mutex_free(&backend->values_mutex); git__free(backend); } @@ -143,7 +143,7 @@ static void config_snapshot_free(git_config_backend *_backend) static int config_snapshot_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_iterator *it = NULL; git_config_entry *entry; int error; @@ -152,12 +152,12 @@ static int config_snapshot_open(git_config_backend *cfg, git_config_level_t leve GIT_UNUSED(level); GIT_UNUSED(repo); - if ((error = git_config_entries_new(&entries)) < 0 || + if ((error = git_config_list_new(&config_list)) < 0 || (error = b->source->iterator(&it, b->source)) < 0) goto out; while ((error = git_config_next(&entry, it)) == 0) - if ((error = git_config_entries_dup_entry(entries, entry)) < 0) + if ((error = git_config_list_dup_entry(config_list, entry)) < 0) goto out; if (error < 0) { @@ -166,12 +166,12 @@ static int config_snapshot_open(git_config_backend *cfg, git_config_level_t leve error = 0; } - b->entries = entries; + b->config_list = config_list; out: git_config_iterator_free(it); if (error) - git_config_entries_free(entries); + git_config_list_free(config_list); return error; } From a8cac7ff7d5b760fe7c5114a1e7e580b37e764a4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 19 Jul 2023 12:50:16 +0100 Subject: [PATCH 233/816] config: drop entry payload; teach config_list about entries The opaque `payload` on an entry is unnecessary and distracting; config entries should follow the patterns of other objects and use space elsewhere in the structure with a "base" config entry struct embedded. --- include/git2/config.h | 8 +++-- src/libgit2/config_file.c | 56 ++++++++++++++++---------------- src/libgit2/config_list.c | 61 +++++++++++++++++++++-------------- src/libgit2/config_list.h | 13 ++++++-- src/libgit2/config_mem.c | 23 +++++++++---- src/libgit2/config_snapshot.c | 14 ++------ 6 files changed, 98 insertions(+), 77 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index cfab0c75739..155a2996205 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -66,8 +66,12 @@ typedef struct git_config_entry { const char *value; /**< String value of the entry */ unsigned int include_depth; /**< Depth of includes where this variable was found */ git_config_level_t level; /**< Which config file this was found in */ - void GIT_CALLBACK(free)(struct git_config_entry *entry); /**< Free function for this entry */ - void *payload; /**< Opaque value for the free function. Do not read or write */ + + /** + * Free function for this entry; for internal purposes. Callers + * should call `git_config_entry_free` to free data. + */ + void GIT_CALLBACK(free)(struct git_config_entry *entry); } git_config_entry; /** diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 41241f1b0f5..46ef07533b6 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -293,7 +293,7 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list; - git_config_entry *existing; + git_config_list_entry *existing; char *key, *esc_value = NULL; int error; @@ -308,8 +308,8 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char if (error != GIT_ENOTFOUND) goto out; error = 0; - } else if ((!existing->value && !value) || - (existing->value && value && !strcmp(existing->value, value))) { + } else if ((!existing->base.value && !value) || + (existing->base.value && value && !strcmp(existing->base.value, value))) { /* don't update if old and new values already match */ error = 0; goto out; @@ -331,13 +331,6 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char return error; } -/* release the map containing the entry as an equivalent to freeing it */ -static void config_file_entry_free(git_config_entry *entry) -{ - git_config_list *config_list = (git_config_list *) entry->payload; - git_config_list_free(config_list); -} - /* * Internal function that actually gets the value in string form */ @@ -345,7 +338,7 @@ static int config_file_get(git_config_backend *cfg, const char *key, git_config_ { config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry; + git_config_list_entry *entry; int error = 0; if (!h->parent.readonly && ((error = config_file_refresh(cfg)) < 0)) @@ -359,7 +352,7 @@ static int config_file_get(git_config_backend *cfg, const char *key, git_config_ return error; } - *out = entry; + *out = &entry->base; return 0; } @@ -395,7 +388,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry; + git_config_list_entry *entry; char *key = NULL; int error; @@ -412,7 +405,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) goto out; } - if ((error = config_file_write(b, name, entry->name, NULL, NULL)) < 0) + if ((error = config_file_write(b, name, entry->base.name, NULL, NULL)) < 0) goto out; out: @@ -425,7 +418,7 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry = NULL; + git_config_list_entry *entry = NULL; git_regexp preg = GIT_REGEX_INIT; char *key = NULL; int result; @@ -774,7 +767,7 @@ static int read_on_variable( { config_file_parse_data *parse_data = (config_file_parse_data *)data; git_str buf = GIT_STR_INIT; - git_config_entry *entry; + git_config_list_entry *entry; const char *c; int result = 0; @@ -797,14 +790,21 @@ static int read_on_variable( if (git_str_oom(&buf)) return -1; - entry = git__calloc(1, sizeof(git_config_entry)); + entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->name = git_str_detach(&buf); - entry->value = var_value ? git__strdup(var_value) : NULL; - entry->level = parse_data->level; - entry->include_depth = parse_data->depth; - entry->free = config_file_entry_free; - entry->payload = parse_data->config_list; + + entry->base.name = git_str_detach(&buf); + GIT_ERROR_CHECK_ALLOC(entry->base.name); + + if (var_value) { + entry->base.value = git__strdup(var_value); + GIT_ERROR_CHECK_ALLOC(entry->base.value); + } + + entry->base.level = parse_data->level; + entry->base.include_depth = parse_data->depth; + entry->base.free = git_config_list_entry_free; + entry->config_list = parse_data->config_list; if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; @@ -812,11 +812,11 @@ static int read_on_variable( result = 0; /* Add or append the new config option */ - if (!git__strcmp(entry->name, "include.path")) - result = parse_include(parse_data, entry->value); - else if (!git__prefixcmp(entry->name, "includeif.") && - !git__suffixcmp(entry->name, ".path")) - result = parse_conditional_include(parse_data, entry->name, entry->value); + if (!git__strcmp(entry->base.name, "include.path")) + result = parse_include(parse_data, entry->base.value); + else if (!git__prefixcmp(entry->base.name, "includeif.") && + !git__suffixcmp(entry->base.name, ".path")) + result = parse_conditional_include(parse_data, entry->base.name, entry->base.value); return result; } diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index 01d41526e98..979c6ccff99 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -10,11 +10,11 @@ typedef struct config_entry_list { struct config_entry_list *next; struct config_entry_list *last; - git_config_entry *entry; + git_config_list_entry *entry; } config_entry_list; typedef struct { - git_config_entry *entry; + git_config_list_entry *entry; bool multivar; } config_entry_map_head; @@ -49,29 +49,32 @@ int git_config_list_new(git_config_list **out) int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry) { - git_config_entry *duplicated; + git_config_list_entry *duplicated; int error; - duplicated = git__calloc(1, sizeof(git_config_entry)); + duplicated = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(duplicated); - duplicated->name = git__strdup(entry->name); - GIT_ERROR_CHECK_ALLOC(duplicated->name); + duplicated->base.name = git__strdup(entry->name); + GIT_ERROR_CHECK_ALLOC(duplicated->base.name); if (entry->value) { - duplicated->value = git__strdup(entry->value); - GIT_ERROR_CHECK_ALLOC(duplicated->value); + duplicated->base.value = git__strdup(entry->value); + GIT_ERROR_CHECK_ALLOC(duplicated->base.value); } - duplicated->level = entry->level; - duplicated->include_depth = entry->include_depth; + + duplicated->base.level = entry->level; + duplicated->base.include_depth = entry->include_depth; + duplicated->base.free = git_config_list_entry_free; + duplicated->config_list = config_list; if ((error = git_config_list_append(config_list, duplicated)) < 0) goto out; out: if (error && duplicated) { - git__free((char *) duplicated->name); - git__free((char *) duplicated->value); + git__free((char *) duplicated->base.name); + git__free((char *) duplicated->base.value); git__free(duplicated); } return error; @@ -87,7 +90,7 @@ int git_config_list_dup(git_config_list **out, git_config_list *config_list) goto out; for (head = config_list->entries; head; head = head->next) - if ((git_config_list_dup_entry(result, head->entry)) < 0) + if ((git_config_list_dup_entry(result, &head->entry->base)) < 0) goto out; *out = result; @@ -109,7 +112,7 @@ static void config_list_free(git_config_list *config_list) config_entry_map_head *head; git_strmap_foreach_value(config_list->map, head, { - git__free((char *) head->entry->name); + git__free((char *) head->entry->base.name); git__free(head); }); git_strmap_free(config_list->map); @@ -117,7 +120,7 @@ static void config_list_free(git_config_list *config_list) entry_list = config_list->entries; while (entry_list != NULL) { next = entry_list->next; - git__free((char *) entry_list->entry->value); + git__free((char *) entry_list->entry->base.value); git__free(entry_list->entry); git__free(entry_list); entry_list = next; @@ -132,12 +135,12 @@ void git_config_list_free(git_config_list *config_list) GIT_REFCOUNT_DEC(config_list, config_list_free); } -int git_config_list_append(git_config_list *config_list, git_config_entry *entry) +int git_config_list_append(git_config_list *config_list, git_config_list_entry *entry) { config_entry_list *list_head; config_entry_map_head *map_head; - if ((map_head = git_strmap_get(config_list->map, entry->name)) != NULL) { + if ((map_head = git_strmap_get(config_list->map, entry->base.name)) != NULL) { map_head->multivar = true; /* * This is a micro-optimization for configuration files @@ -145,11 +148,11 @@ int git_config_list_append(git_config_list *config_list, git_config_entry *entry * key will be the same for all list, we can just free * all except the first entry's name and just re-use it. */ - git__free((char *) entry->name); - entry->name = map_head->entry->name; + git__free((char *) entry->base.name); + entry->base.name = map_head->entry->base.name; } else { map_head = git__calloc(1, sizeof(*map_head)); - if ((git_strmap_set(config_list->map, entry->name, map_head)) < 0) + if ((git_strmap_set(config_list->map, entry->base.name, map_head)) < 0) return -1; } map_head->entry = entry; @@ -167,16 +170,18 @@ int git_config_list_append(git_config_list *config_list, git_config_entry *entry return 0; } -int git_config_list_get(git_config_entry **out, git_config_list *config_list, const char *key) +int git_config_list_get(git_config_list_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; + if ((entry = git_strmap_get(config_list->map, key)) == NULL) return GIT_ENOTFOUND; + *out = entry->entry; return 0; } -int git_config_list_get_unique(git_config_entry **out, git_config_list *config_list, const char *key) +int git_config_list_get_unique(git_config_list_entry **out, git_config_list *config_list, const char *key) { config_entry_map_head *entry; @@ -188,13 +193,12 @@ int git_config_list_get_unique(git_config_entry **out, git_config_list *config_l return -1; } - if (entry->entry->include_depth) { + if (entry->entry->base.include_depth) { git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included"); return -1; } *out = entry->entry; - return 0; } @@ -214,7 +218,7 @@ static int config_iterator_next( if (!it->head) return GIT_ITEROVER; - *entry = it->head->entry; + *entry = &it->head->entry->base; it->head = it->head->next; return 0; @@ -236,3 +240,10 @@ int git_config_list_iterator_new(git_config_iterator **out, git_config_list *con return 0; } + +/* release the map containing the entry as an equivalent to freeing it */ +void git_config_list_entry_free(git_config_entry *e) +{ + git_config_list_entry *entry = (git_config_list_entry *)e; + git_config_list_free(entry->config_list); +} diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h index e14e4aed023..0cacabb110d 100644 --- a/src/libgit2/config_list.h +++ b/src/libgit2/config_list.h @@ -12,13 +12,20 @@ typedef struct git_config_list git_config_list; +typedef struct { + git_config_entry base; + git_config_list *config_list; +} git_config_list_entry; + int git_config_list_new(git_config_list **out); int git_config_list_dup(git_config_list **out, git_config_list *list); int git_config_list_dup_entry(git_config_list *list, const git_config_entry *entry); void git_config_list_incref(git_config_list *list); void git_config_list_free(git_config_list *list); /* Add or append the new config option */ -int git_config_list_append(git_config_list *list, git_config_entry *entry); -int git_config_list_get(git_config_entry **out, git_config_list *list, const char *key); -int git_config_list_get_unique(git_config_entry **out, git_config_list *list, const char *key); +int git_config_list_append(git_config_list *list, git_config_list_entry *entry); +int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key); +int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); + +void git_config_list_entry_free(git_config_entry *entry); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 902bf99e6a3..37f5b01f983 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -39,7 +39,7 @@ static int read_variable_cb( { config_memory_parse_data *parse_data = (config_memory_parse_data *) payload; git_str buf = GIT_STR_INIT; - git_config_entry *entry; + git_config_list_entry *entry; const char *c; int result; @@ -62,12 +62,14 @@ static int read_variable_cb( if (git_str_oom(&buf)) return -1; - entry = git__calloc(1, sizeof(git_config_entry)); + entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->name = git_str_detach(&buf); - entry->value = var_value ? git__strdup(var_value) : NULL; - entry->level = parse_data->level; - entry->include_depth = 0; + entry->base.name = git_str_detach(&buf); + entry->base.value = var_value ? git__strdup(var_value) : NULL; + entry->base.level = parse_data->level; + entry->base.include_depth = 0; + entry->base.free = git_config_list_entry_free; + entry->config_list = parse_data->config_list; if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; @@ -101,7 +103,14 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) { config_memory_backend *memory_backend = (config_memory_backend *) backend; - return git_config_list_get(out, memory_backend->config_list, key); + git_config_list_entry *entry; + int error; + + if ((error = git_config_list_get(&entry, memory_backend->config_list, key)) != 0) + return error; + + *out = &entry->base; + return 0; } static int config_memory_iterator( diff --git a/src/libgit2/config_snapshot.c b/src/libgit2/config_snapshot.c index dbd05ffdce7..d8b8733a9fb 100644 --- a/src/libgit2/config_snapshot.c +++ b/src/libgit2/config_snapshot.c @@ -41,18 +41,11 @@ static int config_snapshot_iterator( return error; } -/* release the map containing the entry as an equivalent to freeing it */ -static void config_snapshot_entry_free(git_config_entry *entry) -{ - git_config_list *config_list = (git_config_list *) entry->payload; - git_config_list_free(config_list); -} - static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); git_config_list *config_list = NULL; - git_config_entry *entry; + git_config_list_entry *entry; int error = 0; if (git_mutex_lock(&b->values_mutex) < 0) { @@ -69,10 +62,7 @@ static int config_snapshot_get(git_config_backend *cfg, const char *key, git_con return error; } - entry->free = config_snapshot_entry_free; - entry->payload = config_list; - *out = entry; - + *out = &entry->base; return 0; } From d9012202763d42ab192af736ed490ed8929fd295 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 20 Jul 2023 10:29:41 +0100 Subject: [PATCH 234/816] config: provide origin in git_config_entry A git_config_entry now knows the type of the origin for the entry ("file", "memory", etc) and the path details (for files, the path on disk). This is propagated through snapshots. --- include/git2/config.h | 24 ++++++++++++++--- src/libgit2/config_file.c | 6 +++++ src/libgit2/config_list.c | 47 +++++++++++++++++++++++++++++---- src/libgit2/config_list.h | 1 + src/libgit2/config_mem.c | 1 + tests/libgit2/config/read.c | 2 ++ tests/libgit2/config/snapshot.c | 35 +++++++++++++++++++++++- 7 files changed, 106 insertions(+), 10 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index 155a2996205..332e62036d0 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -62,10 +62,26 @@ typedef enum { * An entry in a configuration file */ typedef struct git_config_entry { - const char *name; /**< Name of the entry (normalised) */ - const char *value; /**< String value of the entry */ - unsigned int include_depth; /**< Depth of includes where this variable was found */ - git_config_level_t level; /**< Which config file this was found in */ + /** Name of the configuration entry (normalized) */ + const char *name; + + /** Literal (string) value of the entry */ + const char *value; + + /** The type of backend that this entry exists in (eg, "file") */ + const char *backend_type; + + /** + * The path to the origin of this entry. For config files, this is + * the path to the file. + */ + const char *origin_path; + + /** Depth of includes where this variable was found */ + unsigned int include_depth; + + /** Configuration level for the file this was found in */ + git_config_level_t level; /** * Free function for this entry; for internal purposes. Callers diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 46ef07533b6..c86e98bf2bf 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -24,6 +24,8 @@ /* Max depth for [include] directives */ #define MAX_INCLUDE_DEPTH 10 +#define CONFIG_FILE_TYPE "file" + typedef struct config_file { git_futils_filestamp stamp; unsigned char checksum[GIT_HASH_SHA256_SIZE]; @@ -801,7 +803,11 @@ static int read_on_variable( GIT_ERROR_CHECK_ALLOC(entry->base.value); } + entry->base.origin_path = git_config_list_add_path(parse_data->config_list, parse_data->file->path); + GIT_ERROR_CHECK_ALLOC(entry->base.origin_path); + entry->base.level = parse_data->level; + entry->base.backend_type = CONFIG_FILE_TYPE; entry->base.include_depth = parse_data->depth; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index 979c6ccff99..f642c87a4a7 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -26,6 +26,11 @@ typedef struct config_list_iterator { struct git_config_list { git_refcount rc; + + /* Paths to config files that contribute to these entries */ + git_strmap *paths; + + /* Config entries */ git_strmap *map; config_entry_list *entries; }; @@ -33,18 +38,22 @@ struct git_config_list { int git_config_list_new(git_config_list **out) { git_config_list *config_list; - int error; config_list = git__calloc(1, sizeof(git_config_list)); GIT_ERROR_CHECK_ALLOC(config_list); GIT_REFCOUNT_INC(config_list); - if ((error = git_strmap_new(&config_list->map)) < 0) + if (git_strmap_new(&config_list->paths) < 0 || + git_strmap_new(&config_list->map) < 0) { + git_strmap_free(config_list->paths); + git_strmap_free(config_list->map); git__free(config_list); - else - *out = config_list; - return error; + return -1; + } + + *out = config_list; + return 0; } int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry) @@ -63,6 +72,12 @@ int git_config_list_dup_entry(git_config_list *config_list, const git_config_ent GIT_ERROR_CHECK_ALLOC(duplicated->base.value); } + if (entry->origin_path) { + duplicated->base.origin_path = git_config_list_add_path(config_list, entry->origin_path); + GIT_ERROR_CHECK_ALLOC(duplicated->base.origin_path); + } + + duplicated->base.backend_type = entry->backend_type; duplicated->base.level = entry->level; duplicated->base.include_depth = entry->include_depth; duplicated->base.free = git_config_list_entry_free; @@ -110,6 +125,12 @@ static void config_list_free(git_config_list *config_list) { config_entry_list *entry_list = NULL, *next; config_entry_map_head *head; + char *path; + + git_strmap_foreach_value(config_list->paths, path, { + git__free(path); + }); + git_strmap_free(config_list->paths); git_strmap_foreach_value(config_list->map, head, { git__free((char *) head->entry->base.name); @@ -247,3 +268,19 @@ void git_config_list_entry_free(git_config_entry *e) git_config_list_entry *entry = (git_config_list_entry *)e; git_config_list_free(entry->config_list); } + +const char *git_config_list_add_path( + git_config_list *config_list, + const char *path) +{ + const char *p; + + if ((p = git_strmap_get(config_list->paths, path)) != NULL) + return p; + + if ((p = git__strdup(path)) == NULL || + git_strmap_set(config_list->paths, p, (void *)p) < 0) + return NULL; + + return p; +} diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h index 0cacabb110d..83c43b9a0ff 100644 --- a/src/libgit2/config_list.h +++ b/src/libgit2/config_list.h @@ -27,5 +27,6 @@ int git_config_list_append(git_config_list *list, git_config_list_entry *entry); int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); +const char *git_config_list_add_path(git_config_list *list, const char *path); void git_config_list_entry_free(git_config_entry *entry); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 37f5b01f983..748a1471673 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -68,6 +68,7 @@ static int read_variable_cb( entry->base.value = var_value ? git__strdup(var_value) : NULL; entry->base.level = parse_data->level; entry->base.include_depth = 0; + entry->base.backend_type = "memory"; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; diff --git a/tests/libgit2/config/read.c b/tests/libgit2/config/read.c index ac6459b9ea6..25e7b963c4d 100644 --- a/tests/libgit2/config/read.c +++ b/tests/libgit2/config/read.c @@ -495,6 +495,8 @@ void test_config_read__read_git_config_entry(void) cl_assert_equal_s("core.dummy2", entry->name); cl_assert_equal_s("42", entry->value); cl_assert_equal_i(GIT_CONFIG_LEVEL_SYSTEM, entry->level); + cl_assert_equal_s("file", entry->backend_type); + cl_assert_equal_s(cl_fixture("config/config9"), entry->origin_path); git_config_entry_free(entry); git_config_free(cfg); diff --git a/tests/libgit2/config/snapshot.c b/tests/libgit2/config/snapshot.c index 5cc08a721ac..bfb68e21e23 100644 --- a/tests/libgit2/config/snapshot.c +++ b/tests/libgit2/config/snapshot.c @@ -79,6 +79,7 @@ void test_config_snapshot__multivar(void) void test_config_snapshot__includes(void) { + git_config_entry *entry; int i; cl_git_mkfile("including", "[include]\npath = included"); @@ -99,6 +100,16 @@ void test_config_snapshot__includes(void) cl_git_pass(git_config_get_int32(&i, snapshot, "section.key")); cl_assert_equal_i(i, 1); + /* Ensure that the config entry is populated with origin */ + cl_git_pass(git_config_get_entry(&entry, snapshot, "section.key")); + + cl_assert_equal_s("section.key", entry->name); + cl_assert_equal_s("1", entry->value); + cl_assert_equal_s("file", entry->backend_type); + cl_assert_equal_s("./included", entry->origin_path); + + git_config_entry_free(entry); + cl_git_pass(p_unlink("including")); cl_git_pass(p_unlink("included")); } @@ -106,6 +117,7 @@ void test_config_snapshot__includes(void) void test_config_snapshot__snapshot(void) { git_config *snapshot_snapshot; + git_config_entry *entry; int i; cl_git_mkfile("configfile", "[section]\nkey = 1\n"); @@ -118,15 +130,26 @@ void test_config_snapshot__snapshot(void) cl_git_pass(git_config_get_int32(&i, snapshot_snapshot, "section.key")); cl_assert_equal_i(i, 1); + /* Ensure that the config entry is populated with origin */ + cl_git_pass(git_config_get_entry(&entry, snapshot_snapshot, "section.key")); + + cl_assert_equal_s("section.key", entry->name); + cl_assert_equal_s("1", entry->value); + cl_assert_equal_s("file", entry->backend_type); + cl_assert_equal_s("configfile", entry->origin_path); + + git_config_entry_free(entry); + git_config_free(snapshot_snapshot); cl_git_pass(p_unlink("configfile")); } -void test_config_snapshot__snapshot_from_in_memony(void) +void test_config_snapshot__snapshot_from_in_memory(void) { const char *configuration = "[section]\nkey = 1\n"; git_config_backend *backend; + git_config_entry *entry; int i; cl_git_pass(git_config_new(&cfg)); @@ -136,4 +159,14 @@ void test_config_snapshot__snapshot_from_in_memony(void) cl_git_pass(git_config_snapshot(&snapshot, cfg)); cl_git_pass(git_config_get_int32(&i, snapshot, "section.key")); cl_assert_equal_i(i, 1); + + /* Ensure that the config entry is populated with origin */ + cl_git_pass(git_config_get_entry(&entry, snapshot, "section.key")); + + cl_assert_equal_s("section.key", entry->name); + cl_assert_equal_s("1", entry->value); + cl_assert_equal_s("memory", entry->backend_type); + cl_assert_equal_p(NULL, entry->origin_path); + + git_config_entry_free(entry); } From 1977a9a450ed92fcfda4cc33d1e670d24ac8b568 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 20 Jul 2023 10:54:14 +0100 Subject: [PATCH 235/816] config: memory backends have an optional type --- src/libgit2/config_backend.h | 10 +++++++-- src/libgit2/config_file.c | 6 ++++-- src/libgit2/config_list.c | 38 +++++++++++++++++---------------- src/libgit2/config_list.h | 2 +- src/libgit2/config_mem.c | 17 +++++++++++++-- tests/libgit2/config/memory.c | 4 ++-- tests/libgit2/config/snapshot.c | 4 ++-- 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/libgit2/config_backend.h b/src/libgit2/config_backend.h index dbb19051484..677b2236f98 100644 --- a/src/libgit2/config_backend.h +++ b/src/libgit2/config_backend.h @@ -38,13 +38,19 @@ extern int git_config_backend_from_file(git_config_backend **out, const char *pa extern int git_config_backend_snapshot(git_config_backend **out, git_config_backend *source); /** - * Create an in-memory configuration file backend + * Create an in-memory configuration file backend from a string in standard + * git configuration file format. * * @param out the new backend + * @param origin the name of the origin to use (or NULL for "memory") * @param cfg the configuration that is to be parsed * @param len the length of the string pointed to by `cfg` */ -extern int git_config_backend_from_string(git_config_backend **out, const char *cfg, size_t len); +extern int git_config_backend_from_string( + git_config_backend **out, + const char *origin, + const char *cfg, + size_t len); GIT_INLINE(int) git_config_backend_open(git_config_backend *cfg, unsigned int level, const git_repository *repo) { diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index c86e98bf2bf..340e85691ed 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -803,11 +803,13 @@ static int read_on_variable( GIT_ERROR_CHECK_ALLOC(entry->base.value); } - entry->base.origin_path = git_config_list_add_path(parse_data->config_list, parse_data->file->path); + entry->base.backend_type = git_config_list_add_string(parse_data->config_list, CONFIG_FILE_TYPE); + GIT_ERROR_CHECK_ALLOC(entry->base.backend_type); + + entry->base.origin_path = git_config_list_add_string(parse_data->config_list, parse_data->file->path); GIT_ERROR_CHECK_ALLOC(entry->base.origin_path); entry->base.level = parse_data->level; - entry->base.backend_type = CONFIG_FILE_TYPE; entry->base.include_depth = parse_data->depth; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index f642c87a4a7..0b7a4f3600a 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -27,8 +27,8 @@ typedef struct config_list_iterator { struct git_config_list { git_refcount rc; - /* Paths to config files that contribute to these entries */ - git_strmap *paths; + /* Interned strings - paths to config files or backend types */ + git_strmap *strings; /* Config entries */ git_strmap *map; @@ -43,9 +43,9 @@ int git_config_list_new(git_config_list **out) GIT_ERROR_CHECK_ALLOC(config_list); GIT_REFCOUNT_INC(config_list); - if (git_strmap_new(&config_list->paths) < 0 || + if (git_strmap_new(&config_list->strings) < 0 || git_strmap_new(&config_list->map) < 0) { - git_strmap_free(config_list->paths); + git_strmap_free(config_list->strings); git_strmap_free(config_list->map); git__free(config_list); @@ -72,12 +72,14 @@ int git_config_list_dup_entry(git_config_list *config_list, const git_config_ent GIT_ERROR_CHECK_ALLOC(duplicated->base.value); } + duplicated->base.backend_type = git_config_list_add_string(config_list, entry->backend_type); + GIT_ERROR_CHECK_ALLOC(duplicated->base.backend_type); + if (entry->origin_path) { - duplicated->base.origin_path = git_config_list_add_path(config_list, entry->origin_path); + duplicated->base.origin_path = git_config_list_add_string(config_list, entry->origin_path); GIT_ERROR_CHECK_ALLOC(duplicated->base.origin_path); } - duplicated->base.backend_type = entry->backend_type; duplicated->base.level = entry->level; duplicated->base.include_depth = entry->include_depth; duplicated->base.free = git_config_list_entry_free; @@ -125,12 +127,12 @@ static void config_list_free(git_config_list *config_list) { config_entry_list *entry_list = NULL, *next; config_entry_map_head *head; - char *path; + char *str; - git_strmap_foreach_value(config_list->paths, path, { - git__free(path); + git_strmap_foreach_value(config_list->strings, str, { + git__free(str); }); - git_strmap_free(config_list->paths); + git_strmap_free(config_list->strings); git_strmap_foreach_value(config_list->map, head, { git__free((char *) head->entry->base.name); @@ -269,18 +271,18 @@ void git_config_list_entry_free(git_config_entry *e) git_config_list_free(entry->config_list); } -const char *git_config_list_add_path( +const char *git_config_list_add_string( git_config_list *config_list, - const char *path) + const char *str) { - const char *p; + const char *s; - if ((p = git_strmap_get(config_list->paths, path)) != NULL) - return p; + if ((s = git_strmap_get(config_list->strings, str)) != NULL) + return s; - if ((p = git__strdup(path)) == NULL || - git_strmap_set(config_list->paths, p, (void *)p) < 0) + if ((s = git__strdup(str)) == NULL || + git_strmap_set(config_list->strings, s, (void *)s) < 0) return NULL; - return p; + return s; } diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h index 83c43b9a0ff..023bca1e5ca 100644 --- a/src/libgit2/config_list.h +++ b/src/libgit2/config_list.h @@ -27,6 +27,6 @@ int git_config_list_append(git_config_list *list, git_config_list_entry *entry); int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key); int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); -const char *git_config_list_add_path(git_config_list *list, const char *path); +const char *git_config_list_add_string(git_config_list *list, const char *str); void git_config_list_entry_free(git_config_entry *entry); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 748a1471673..8faa53dcba5 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -13,11 +13,13 @@ typedef struct { git_config_backend parent; + char *type; git_config_list *config_list; git_str cfg; } config_memory_backend; typedef struct { + const char *backend_type; git_config_list *config_list; git_config_level_t level; } config_memory_parse_data; @@ -68,7 +70,7 @@ static int read_variable_cb( entry->base.value = var_value ? git__strdup(var_value) : NULL; entry->base.level = parse_data->level; entry->base.include_depth = 0; - entry->base.backend_type = "memory"; + entry->base.backend_type = parse_data->backend_type; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; @@ -90,6 +92,9 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr, memory_backend->cfg.size)) < 0) goto out; + + parse_data.backend_type = git_config_list_add_string( + memory_backend->config_list, memory_backend->type); parse_data.config_list = memory_backend->config_list; parse_data.level = level; @@ -187,12 +192,17 @@ static void config_memory_free(git_config_backend *_backend) if (backend == NULL) return; + git__free(backend->type); git_config_list_free(backend->config_list); git_str_dispose(&backend->cfg); git__free(backend); } -int git_config_backend_from_string(git_config_backend **out, const char *cfg, size_t len) +int git_config_backend_from_string( + git_config_backend **out, + const char *backend_type, + const char *cfg, + size_t len) { config_memory_backend *backend; @@ -210,6 +220,9 @@ int git_config_backend_from_string(git_config_backend **out, const char *cfg, si return -1; } + backend->type = git__strdup(backend_type ? backend_type : "in-memory"); + GIT_ERROR_CHECK_ALLOC(backend->type); + backend->parent.version = GIT_CONFIG_BACKEND_VERSION; backend->parent.readonly = 1; backend->parent.open = config_memory_open; diff --git a/tests/libgit2/config/memory.c b/tests/libgit2/config/memory.c index ae661899da7..67a61a1c573 100644 --- a/tests/libgit2/config/memory.c +++ b/tests/libgit2/config/memory.c @@ -61,7 +61,7 @@ static void assert_config_contains_all(git_config_backend *backend, static void setup_backend(const char *cfg) { - cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg))); + cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); cl_git_pass(git_config_backend_open(backend, 0, NULL)); } @@ -88,7 +88,7 @@ void test_config_memory__malformed_fails_to_open(void) const char *cfg = "[general\n" "foo=bar\n"; - cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg))); + cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); cl_git_fail(git_config_backend_open(backend, 0, NULL)); } diff --git a/tests/libgit2/config/snapshot.c b/tests/libgit2/config/snapshot.c index bfb68e21e23..87a68600ee4 100644 --- a/tests/libgit2/config/snapshot.c +++ b/tests/libgit2/config/snapshot.c @@ -153,7 +153,7 @@ void test_config_snapshot__snapshot_from_in_memory(void) int i; cl_git_pass(git_config_new(&cfg)); - cl_git_pass(git_config_backend_from_string(&backend, configuration, strlen(configuration))); + cl_git_pass(git_config_backend_from_string(&backend, "test", configuration, strlen(configuration))); cl_git_pass(git_config_add_backend(cfg, backend, 0, NULL, 0)); cl_git_pass(git_config_snapshot(&snapshot, cfg)); @@ -165,7 +165,7 @@ void test_config_snapshot__snapshot_from_in_memory(void) cl_assert_equal_s("section.key", entry->name); cl_assert_equal_s("1", entry->value); - cl_assert_equal_s("memory", entry->backend_type); + cl_assert_equal_s("test", entry->backend_type); cl_assert_equal_p(NULL, entry->origin_path); git_config_entry_free(entry); From 21d3301135338ac27b4e8b8804d935bcfca633e6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 20 Jul 2023 22:27:25 +0100 Subject: [PATCH 236/816] config: provide two memory-backed config backends Provide two memory-backed configuration backends -- one that takes a string in config file format `[section] key=value` and one that takes a list of strings in `section.key=value` format. --- fuzzers/config_file_fuzzer.c | 2 +- include/git2/sys/config.h | 51 +++++++++ src/libgit2/config_backend.h | 15 --- src/libgit2/config_mem.c | 191 +++++++++++++++++++++++++++----- src/util/strlist.c | 42 +++++++ src/util/strlist.h | 16 +++ tests/libgit2/config/memory.c | 75 ++++++++++++- tests/libgit2/config/snapshot.c | 10 +- 8 files changed, 350 insertions(+), 52 deletions(-) create mode 100644 src/util/strlist.c create mode 100644 src/util/strlist.h diff --git a/fuzzers/config_file_fuzzer.c b/fuzzers/config_file_fuzzer.c index 890adbfc528..763036960b4 100644 --- a/fuzzers/config_file_fuzzer.c +++ b/fuzzers/config_file_fuzzer.c @@ -43,7 +43,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) goto out; } - if ((err = git_config_backend_from_string(&backend, (const char*)data, size)) != 0) { + if ((err = git_config_backend_from_string(&backend, (const char*)data, size, NULL)) != 0) { goto out; } if ((err = git_config_add_backend(cfg, backend, 0, NULL, 0)) != 0) { diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index 0a9005e35d4..75d20758b84 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -125,6 +125,57 @@ GIT_EXTERN(int) git_config_add_backend( const git_repository *repo, int force); +/** Options for in-memory configuration backends. */ +typedef struct { + unsigned int version; + + /** + * The type of this backend (eg, "command line"). If this is + * NULL, then this will be "in-memory". + */ + const char *backend_type; + + /** + * The path to the origin; if this is NULL then it will be + * left unset in the resulting configuration entries. + */ + const char *origin_path; +} git_config_backend_memory_options; + +#define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION 1 +#define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT { GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION } + + +/** + * Create an in-memory configuration backend from a string in standard + * git configuration file format. + * + * @param out the new backend + * @param cfg the configuration that is to be parsed + * @param len the length of the string pointed to by `cfg` + * @param opts the options to initialize this backend with, or NULL + */ +extern int git_config_backend_from_string( + git_config_backend **out, + const char *cfg, + size_t len, + git_config_backend_memory_options *opts); + +/** + * Create an in-memory configuration backend from a list of name/value + * pairs. + * + * @param out the new backend + * @param values the configuration values to set (in "key=value" format) + * @param len the length of the values array + * @param opts the options to initialize this backend with, or NULL + */ +extern int git_config_backend_from_values( + git_config_backend **out, + const char **values, + size_t len, + git_config_backend_memory_options *opts); + /** @} */ GIT_END_DECL #endif diff --git a/src/libgit2/config_backend.h b/src/libgit2/config_backend.h index 677b2236f98..37d25abe146 100644 --- a/src/libgit2/config_backend.h +++ b/src/libgit2/config_backend.h @@ -37,21 +37,6 @@ extern int git_config_backend_from_file(git_config_backend **out, const char *pa */ extern int git_config_backend_snapshot(git_config_backend **out, git_config_backend *source); -/** - * Create an in-memory configuration file backend from a string in standard - * git configuration file format. - * - * @param out the new backend - * @param origin the name of the origin to use (or NULL for "memory") - * @param cfg the configuration that is to be parsed - * @param len the length of the string pointed to by `cfg` - */ -extern int git_config_backend_from_string( - git_config_backend **out, - const char *origin, - const char *cfg, - size_t len); - GIT_INLINE(int) git_config_backend_open(git_config_backend *cfg, unsigned int level, const git_repository *repo) { return cfg->open(cfg, level, repo); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 8faa53dcba5..406aa83e6e1 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -10,16 +10,27 @@ #include "config_backend.h" #include "config_parse.h" #include "config_list.h" +#include "strlist.h" typedef struct { git_config_backend parent; - char *type; + + char *backend_type; + char *origin_path; + git_config_list *config_list; + + /* Configuration data in the config file format */ git_str cfg; + + /* Array of key=value pairs */ + char **values; + size_t values_len; } config_memory_backend; typedef struct { const char *backend_type; + const char *origin_path; git_config_list *config_list; git_config_level_t level; } config_memory_parse_data; @@ -71,6 +82,7 @@ static int read_variable_cb( entry->base.level = parse_data->level; entry->base.include_depth = 0; entry->base.backend_type = parse_data->backend_type; + entry->base.origin_path = parse_data->origin_path; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; @@ -80,25 +92,29 @@ static int read_variable_cb( return result; } -static int config_memory_open(git_config_backend *backend, git_config_level_t level, const git_repository *repo) +static int parse_config( + config_memory_backend *memory_backend, + git_config_level_t level) { - config_memory_backend *memory_backend = (config_memory_backend *) backend; git_config_parser parser = GIT_PARSE_CTX_INIT; config_memory_parse_data parse_data; int error; - GIT_UNUSED(repo); - - if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr, - memory_backend->cfg.size)) < 0) + if ((error = git_config_parser_init(&parser, "in-memory", + memory_backend->cfg.ptr, memory_backend->cfg.size)) < 0) goto out; parse_data.backend_type = git_config_list_add_string( - memory_backend->config_list, memory_backend->type); + memory_backend->config_list, memory_backend->backend_type); + parse_data.origin_path = memory_backend->origin_path ? + git_config_list_add_string(memory_backend->config_list, + memory_backend->origin_path) : + NULL; parse_data.config_list = memory_backend->config_list; parse_data.level = level; - if ((error = git_config_parse(&parser, NULL, read_variable_cb, NULL, NULL, &parse_data)) < 0) + if ((error = git_config_parse(&parser, NULL, read_variable_cb, + NULL, NULL, &parse_data)) < 0) goto out; out: @@ -106,6 +122,74 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le return error; } +static int parse_values( + config_memory_backend *memory_backend, + git_config_level_t level) +{ + git_config_list_entry *entry; + const char *eql, *backend_type, *origin_path; + size_t name_len, i; + + backend_type = git_config_list_add_string( + memory_backend->config_list, memory_backend->backend_type); + GIT_ERROR_CHECK_ALLOC(backend_type); + + origin_path = memory_backend->origin_path ? + git_config_list_add_string(memory_backend->config_list, + memory_backend->origin_path) : + NULL; + + for (i = 0; i < memory_backend->values_len; i++) { + eql = strchr(memory_backend->values[i], '='); + name_len = eql - memory_backend->values[i]; + + if (name_len == 0) { + git_error_set(GIT_ERROR_CONFIG, "empty config key"); + return -1; + } + + entry = git__calloc(1, sizeof(git_config_list_entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->base.name = git__strndup(memory_backend->values[i], name_len); + GIT_ERROR_CHECK_ALLOC(entry->base.name); + + if (eql) { + entry->base.value = git__strdup(eql + 1); + GIT_ERROR_CHECK_ALLOC(entry->base.value); + } + + entry->base.level = level; + entry->base.include_depth = 0; + entry->base.backend_type = backend_type; + entry->base.origin_path = origin_path; + entry->base.free = git_config_list_entry_free; + entry->config_list = memory_backend->config_list; + + if (git_config_list_append(memory_backend->config_list, entry) < 0) + return -1; + } + + return 0; +} + +static int config_memory_open(git_config_backend *backend, git_config_level_t level, const git_repository *repo) +{ + config_memory_backend *memory_backend = (config_memory_backend *) backend; + + GIT_UNUSED(repo); + + if (memory_backend->cfg.size > 0 && + parse_config(memory_backend, level) < 0) + return -1; + + if (memory_backend->values_len > 0 && + parse_values(memory_backend, level) < 0) + return -1; + + return 0; +} + static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) { config_memory_backend *memory_backend = (config_memory_backend *) backend; @@ -192,36 +276,24 @@ static void config_memory_free(git_config_backend *_backend) if (backend == NULL) return; - git__free(backend->type); + git__free(backend->origin_path); + git__free(backend->backend_type); git_config_list_free(backend->config_list); + git_strlist_free(backend->values, backend->values_len); git_str_dispose(&backend->cfg); git__free(backend); } -int git_config_backend_from_string( - git_config_backend **out, - const char *backend_type, - const char *cfg, - size_t len) +static config_memory_backend *config_backend_new( + git_config_backend_memory_options *opts) { config_memory_backend *backend; - backend = git__calloc(1, sizeof(config_memory_backend)); - GIT_ERROR_CHECK_ALLOC(backend); - - if (git_config_list_new(&backend->config_list) < 0) { - git__free(backend); - return -1; - } - - if (git_str_set(&backend->cfg, cfg, len) < 0) { - git_config_list_free(backend->config_list); - git__free(backend); - return -1; - } + if ((backend = git__calloc(1, sizeof(config_memory_backend))) == NULL) + return NULL; - backend->type = git__strdup(backend_type ? backend_type : "in-memory"); - GIT_ERROR_CHECK_ALLOC(backend->type); + if (git_config_list_new(&backend->config_list) < 0) + goto on_error; backend->parent.version = GIT_CONFIG_BACKEND_VERSION; backend->parent.readonly = 1; @@ -237,7 +309,66 @@ int git_config_backend_from_string( backend->parent.snapshot = git_config_backend_snapshot; backend->parent.free = config_memory_free; + backend->backend_type = git__strdup(opts && opts->backend_type ? + opts->backend_type : "in-memory"); + + if (backend->backend_type == NULL) + goto on_error; + + if (opts && opts->origin_path && + (backend->origin_path = git__strdup(opts->origin_path)) == NULL) + goto on_error; + + return backend; + +on_error: + git_config_list_free(backend->config_list); + git__free(backend->origin_path); + git__free(backend->backend_type); + git__free(backend); + return NULL; +} + +int git_config_backend_from_string( + git_config_backend **out, + const char *cfg, + size_t len, + git_config_backend_memory_options *opts) +{ + config_memory_backend *backend; + + if ((backend = config_backend_new(opts)) == NULL) + return -1; + + if (git_str_set(&backend->cfg, cfg, len) < 0) { + git_config_list_free(backend->config_list); + git__free(backend); + return -1; + } + *out = (git_config_backend *)backend; + return 0; +} + +int git_config_backend_from_values( + git_config_backend **out, + const char **values, + size_t len, + git_config_backend_memory_options *opts) +{ + config_memory_backend *backend; + if ((backend = config_backend_new(opts)) == NULL) + return -1; + + if (git_strlist_copy(&backend->values, values, len) < 0) { + git_config_list_free(backend->config_list); + git__free(backend); + return -1; + } + + backend->values_len = len; + + *out = (git_config_backend *)backend; return 0; } diff --git a/src/util/strlist.c b/src/util/strlist.c new file mode 100644 index 00000000000..af9b4bbd34d --- /dev/null +++ b/src/util/strlist.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include + +#include "git2_util.h" +#include "vector.h" +#include "strlist.h" + +int git_strlist_copy(char ***out, const char **in, size_t len) +{ + char **dup; + size_t i; + + dup = git__calloc(len, sizeof(char *)); + GIT_ERROR_CHECK_ALLOC(dup); + + for (i = 0; i < len; i++) { + dup[i] = git__strdup(in[i]); + GIT_ERROR_CHECK_ALLOC(dup[i]); + } + + *out = dup; + return 0; +} + +void git_strlist_free(char **strings, size_t len) +{ + size_t i; + + if (!strings) + return; + + for (i = 0; i < len; i++) + git__free(strings[i]); + + git__free(strings); +} diff --git a/src/util/strlist.h b/src/util/strlist.h new file mode 100644 index 00000000000..089a8bb57b3 --- /dev/null +++ b/src/util/strlist.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_runtime_h__ +#define INCLUDE_runtime_h__ + +#include "git2_util.h" + +extern int git_strlist_copy(char ***out, const char **in, size_t len); +extern void git_strlist_free(char **strings, size_t len); + +#endif diff --git a/tests/libgit2/config/memory.c b/tests/libgit2/config/memory.c index 67a61a1c573..9f533e282fd 100644 --- a/tests/libgit2/config/memory.c +++ b/tests/libgit2/config/memory.c @@ -34,8 +34,13 @@ static int contains_all_cb(const git_config_entry *entry, void *payload) int i; for (i = 0; entries[i].name; i++) { - if (strcmp(entries[i].name, entry->name) || - strcmp(entries[i].value , entry->value)) + if (strcmp(entries[i].name, entry->name)) + continue; + + if ((entries[i].value == NULL) ^ (entry->value == NULL)) + continue; + + if (entry->value && strcmp(entries[i].value , entry->value)) continue; if (entries[i].seen) @@ -61,7 +66,23 @@ static void assert_config_contains_all(git_config_backend *backend, static void setup_backend(const char *cfg) { - cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg), &opts)); + cl_git_pass(git_config_backend_open(backend, 0, NULL)); +} + +static void setup_values_backend(const char **values, size_t len) +{ + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_values(&backend, values, len, &opts)); cl_git_pass(git_config_backend_open(backend, 0, NULL)); } @@ -88,7 +109,13 @@ void test_config_memory__malformed_fails_to_open(void) const char *cfg = "[general\n" "foo=bar\n"; - cl_git_pass(git_config_backend_from_string(&backend, "test", cfg, strlen(cfg))); + + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg), &opts)); cl_git_fail(git_config_backend_open(backend, 0, NULL)); } @@ -137,3 +164,43 @@ void test_config_memory__foreach_sees_multivar(void) "foo=bar2\n"); assert_config_contains_all(backend, entries); } + +void test_config_memory__values(void) +{ + const char *values[] = { + "general.foo=bar1", + "general.foo=bar2", + "other.key=value", + "empty.value=", + "no.value", + }; + + struct expected_entry entries[] = { + { "general.foo", "bar1", 0 }, + { "general.foo", "bar2", 0 }, + { "other.key", "value", 0 }, + { "empty.value", "", 0 }, + { "no.value", NULL, 0 }, + { NULL, NULL, 0 } + }; + + setup_values_backend(values, 5); + assert_config_contains_all(backend, entries); +} + +void test_config_memory__valid_values(void) +{ + const char *values[] = { + "general.foo=bar1", + "=bar2", + "other.key=value" + }; + + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + + cl_git_pass(git_config_backend_from_values(&backend, values, 3, &opts)); + cl_git_fail(git_config_backend_open(backend, 0, NULL)); +} diff --git a/tests/libgit2/config/snapshot.c b/tests/libgit2/config/snapshot.c index 87a68600ee4..cc877063c08 100644 --- a/tests/libgit2/config/snapshot.c +++ b/tests/libgit2/config/snapshot.c @@ -152,8 +152,14 @@ void test_config_snapshot__snapshot_from_in_memory(void) git_config_entry *entry; int i; + git_config_backend_memory_options opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + + opts.backend_type = "test"; + opts.origin_path = "hello"; + cl_git_pass(git_config_new(&cfg)); - cl_git_pass(git_config_backend_from_string(&backend, "test", configuration, strlen(configuration))); + cl_git_pass(git_config_backend_from_string(&backend, configuration, strlen(configuration), &opts)); cl_git_pass(git_config_add_backend(cfg, backend, 0, NULL, 0)); cl_git_pass(git_config_snapshot(&snapshot, cfg)); @@ -166,7 +172,7 @@ void test_config_snapshot__snapshot_from_in_memory(void) cl_assert_equal_s("section.key", entry->name); cl_assert_equal_s("1", entry->value); cl_assert_equal_s("test", entry->backend_type); - cl_assert_equal_p(NULL, entry->origin_path); + cl_assert_equal_s("hello", entry->origin_path); git_config_entry_free(entry); } From 877968418ac645e79bb4cc8c0f39a05f5f7bbc98 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 21 Jul 2023 10:35:31 +0100 Subject: [PATCH 237/816] cli: add `config` command Add a `config` command with `--list` and `--get`. --- src/cli/cmd.h | 1 + src/cli/cmd_config.c | 178 +++++++++++++++++++++++++++++++++++++++++++ src/cli/main.c | 1 + 3 files changed, 180 insertions(+) create mode 100644 src/cli/cmd_config.c diff --git a/src/cli/cmd.h b/src/cli/cmd.h index 8b1a1b38fd7..12977cbc7bb 100644 --- a/src/cli/cmd.h +++ b/src/cli/cmd.h @@ -27,6 +27,7 @@ extern const cli_cmd_spec *cli_cmd_spec_byname(const char *name); /* Commands */ extern int cmd_cat_file(int argc, char **argv); extern int cmd_clone(int argc, char **argv); +extern int cmd_config(int argc, char **argv); extern int cmd_hash_object(int argc, char **argv); extern int cmd_help(int argc, char **argv); diff --git a/src/cli/cmd_config.c b/src/cli/cmd_config.c new file mode 100644 index 00000000000..9c966faef9b --- /dev/null +++ b/src/cli/cmd_config.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include "cli.h" +#include "cmd.h" + +#define COMMAND_NAME "config" + +typedef enum { + ACTION_NONE = 0, + ACTION_GET, + ACTION_LIST +} action_t; + +static action_t action = ACTION_NONE; +static int show_origin; +static int show_scope; +static int show_help; +static int null_separator; +static char *name; + +static const cli_opt_spec opts[] = { + { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, + "display help about the " COMMAND_NAME " command" }, + + { CLI_OPT_TYPE_SWITCH, "null", 'z', &null_separator, 1, + 0, NULL, "use NUL as a separator" }, + + { CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET, + CLI_OPT_USAGE_REQUIRED, NULL, "get a configuration value" }, + { CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST, + CLI_OPT_USAGE_CHOICE | CLI_OPT_USAGE_SHOW_LONG, + NULL, "list all configuration entries" }, + { CLI_OPT_TYPE_SWITCH, "show-origin", 0, &show_origin, 1, + 0, NULL, "show origin of configuration" }, + { CLI_OPT_TYPE_SWITCH, "show-scope", 0, &show_scope, 1, + 0, NULL, "show scope of configuration" }, + { CLI_OPT_TYPE_ARG, "name", 0, &name, 0, + 0, "name", "name of configuration entry" }, + { 0 }, +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Query and set configuration options.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +static int get_config(git_config *config) +{ + git_buf value = GIT_BUF_INIT; + char sep = null_separator ? '\0' : '\n'; + int error; + + error = git_config_get_string_buf(&value, config, name); + + if (error && error != GIT_ENOTFOUND) + return cli_error_git(); + + else if (error == GIT_ENOTFOUND) + return 1; + + printf("%s%c", value.ptr, sep); + return 0; +} + +static const char *level_name(git_config_level_t level) +{ + switch (level) { + case GIT_CONFIG_LEVEL_PROGRAMDATA: + return "programdata"; + case GIT_CONFIG_LEVEL_SYSTEM: + return "system"; + case GIT_CONFIG_LEVEL_XDG: + return "global"; + case GIT_CONFIG_LEVEL_GLOBAL: + return "global"; + case GIT_CONFIG_LEVEL_LOCAL: + return "local"; + case GIT_CONFIG_LEVEL_APP: + return "command"; + default: + return "unknown"; + } +} + +static int list_config(git_config *config) +{ + git_config_iterator *iterator; + git_config_entry *entry; + char data_separator = null_separator ? '\0' : '\t'; + char kv_separator = null_separator ? '\n' : '='; + char entry_separator = null_separator ? '\0' : '\n'; + int error; + + if (git_config_iterator_new(&iterator, config) < 0) + return cli_error_git(); + + while ((error = git_config_next(&entry, iterator)) == 0) { + if (show_scope) + printf("%s%c", + level_name(entry->level), + data_separator); + + if (show_origin) + printf("%s%s%s%c", + entry->backend_type ? entry->backend_type : "", + entry->backend_type && entry->origin_path ? ":" : "", + entry->origin_path ? entry->origin_path : "", + data_separator); + + printf("%s%c%s%c", entry->name, kv_separator, entry->value, + entry_separator); + } + + if (error != GIT_ITEROVER) + return cli_error_git(); + + git_config_iterator_free(iterator); + return 0; +} + +int cmd_config(int argc, char **argv) +{ + git_repository *repo = NULL; + git_config *config = NULL; + cli_opt invalid_opt; + int ret = 0; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (git_repository_open_ext(&repo, ".", GIT_REPOSITORY_OPEN_FROM_ENV, NULL) < 0 || + git_repository_config(&config, repo) < 0) { + ret = cli_error_git(); + goto done; + } + + switch (action) { + case ACTION_LIST: + if (name) + ret = cli_error_usage("%s --list does not take an argument", COMMAND_NAME); + else + ret = list_config(config); + break; + case ACTION_GET: + if (!name) + ret = cli_error_usage("%s --get requires an argument", COMMAND_NAME); + else + ret = get_config(config); + break; + default: + ret = cli_error_usage("unknown action"); + } + +done: + git_config_free(config); + git_repository_free(repo); + return ret; +} diff --git a/src/cli/main.c b/src/cli/main.c index cbfc50eec35..96a70127546 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -30,6 +30,7 @@ const cli_opt_spec cli_common_opts[] = { const cli_cmd_spec cli_cmds[] = { { "cat-file", cmd_cat_file, "Display an object in the repository" }, { "clone", cmd_clone, "Clone a repository into a new directory" }, + { "config", cmd_config, "View or set configuration values " }, { "hash-object", cmd_hash_object, "Hash a raw object and product its object ID" }, { "help", cmd_help, "Display help information" }, { NULL } From 1c381acf9d530a539c2cbf7c2cbbd05010c102cc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Jul 2023 20:30:59 +0100 Subject: [PATCH 238/816] cli: accept configuration on the command line Introduce `cli_repository_open` which will reparse command-line options looking for `-c` or `--config-env`. Add those values to an in-memory configuration database and configure the opened repository with that. --- src/cli/cli.h | 20 ------ src/cli/cmd.c | 2 +- src/cli/cmd_cat_file.c | 2 +- src/cli/cmd_clone.c | 2 +- src/cli/cmd_config.c | 46 ++++++++----- src/cli/cmd_hash_object.c | 2 +- src/cli/cmd_help.c | 2 +- src/cli/common.c | 126 ++++++++++++++++++++++++++++++++++++ src/cli/common.h | 47 ++++++++++++++ src/cli/error.h | 2 +- src/cli/main.c | 2 +- src/cli/opt.c | 26 +++++++- src/cli/opt.h | 8 +++ src/cli/opt_usage.c | 2 +- src/cli/unix/sighandler.c | 3 +- src/cli/win32/precompiled.h | 2 +- src/cli/win32/sighandler.c | 2 +- 17 files changed, 246 insertions(+), 50 deletions(-) delete mode 100644 src/cli/cli.h create mode 100644 src/cli/common.c create mode 100644 src/cli/common.h diff --git a/src/cli/cli.h b/src/cli/cli.h deleted file mode 100644 index 7dede678519..00000000000 --- a/src/cli/cli.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef CLI_cli_h__ -#define CLI_cli_h__ - -#define PROGRAM_NAME "git2" - -#include "git2_util.h" - -#include "error.h" -#include "opt.h" -#include "opt_usage.h" -#include "sighandler.h" - -#endif /* CLI_cli_h__ */ diff --git a/src/cli/cmd.c b/src/cli/cmd.c index 2a7e71cdbcb..0b1fafb4423 100644 --- a/src/cli/cmd.c +++ b/src/cli/cmd.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "cli.h" +#include "common.h" #include "cmd.h" const cli_cmd_spec *cli_cmd_spec_byname(const char *name) diff --git a/src/cli/cmd_cat_file.c b/src/cli/cmd_cat_file.c index fb53a722ba2..96cab4a67ac 100644 --- a/src/cli/cmd_cat_file.c +++ b/src/cli/cmd_cat_file.c @@ -6,7 +6,7 @@ */ #include -#include "cli.h" +#include "common.h" #include "cmd.h" #define COMMAND_NAME "cat-file" diff --git a/src/cli/cmd_clone.c b/src/cli/cmd_clone.c index e4776256cb3..90d3e3db3b8 100644 --- a/src/cli/cmd_clone.c +++ b/src/cli/cmd_clone.c @@ -7,7 +7,7 @@ #include #include -#include "cli.h" +#include "common.h" #include "cmd.h" #include "error.h" #include "sighandler.h" diff --git a/src/cli/cmd_config.c b/src/cli/cmd_config.c index 9c966faef9b..75044af7a25 100644 --- a/src/cli/cmd_config.c +++ b/src/cli/cmd_config.c @@ -6,7 +6,8 @@ */ #include -#include "cli.h" + +#include "common.h" #include "cmd.h" #define COMMAND_NAME "config" @@ -24,25 +25,35 @@ static int show_help; static int null_separator; static char *name; +#define CLI_COMMON_OPT_HELP \ + CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING +#define CLI_COMMON_OPT_CONFIG \ + CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ + CLI_OPT_USAGE_HIDDEN +#define CLI_COMMON_OPT_CONFIG_ENV \ + CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ + CLI_OPT_USAGE_HIDDEN + static const cli_opt_spec opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, - "display help about the " COMMAND_NAME " command" }, + { CLI_COMMON_OPT_HELP }, + { CLI_COMMON_OPT_CONFIG }, + { CLI_COMMON_OPT_CONFIG_ENV }, - { CLI_OPT_TYPE_SWITCH, "null", 'z', &null_separator, 1, - 0, NULL, "use NUL as a separator" }, + { CLI_OPT_TYPE_SWITCH, "null", 'z', &null_separator, 1, + 0, NULL, "use NUL as a separator" }, - { CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET, - CLI_OPT_USAGE_REQUIRED, NULL, "get a configuration value" }, - { CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST, + { CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET, + CLI_OPT_USAGE_REQUIRED, NULL, "get a configuration value" }, + { CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST, CLI_OPT_USAGE_CHOICE | CLI_OPT_USAGE_SHOW_LONG, - NULL, "list all configuration entries" }, - { CLI_OPT_TYPE_SWITCH, "show-origin", 0, &show_origin, 1, - 0, NULL, "show origin of configuration" }, - { CLI_OPT_TYPE_SWITCH, "show-scope", 0, &show_scope, 1, - 0, NULL, "show scope of configuration" }, - { CLI_OPT_TYPE_ARG, "name", 0, &name, 0, - 0, "name", "name of configuration entry" }, + NULL, "list all configuration entries" }, + { CLI_OPT_TYPE_SWITCH, "show-origin", 0, &show_origin, 1, + 0, NULL, "show origin of configuration" }, + { CLI_OPT_TYPE_SWITCH, "show-scope", 0, &show_scope, 1, + 0, NULL, "show scope of configuration" }, + { CLI_OPT_TYPE_ARG, "name", 0, &name, 0, + 0, "name", "name of configuration entry" }, { 0 }, }; @@ -137,6 +148,7 @@ int cmd_config(int argc, char **argv) { git_repository *repo = NULL; git_config *config = NULL; + cli_repository_open_options open_opts = { argv + 1, argc - 1}; cli_opt invalid_opt; int ret = 0; @@ -148,7 +160,7 @@ int cmd_config(int argc, char **argv) return 0; } - if (git_repository_open_ext(&repo, ".", GIT_REPOSITORY_OPEN_FROM_ENV, NULL) < 0 || + if (cli_repository_open(&repo, &open_opts) < 0 || git_repository_config(&config, repo) < 0) { ret = cli_error_git(); goto done; diff --git a/src/cli/cmd_hash_object.c b/src/cli/cmd_hash_object.c index 93b980d6676..529a1ec44e5 100644 --- a/src/cli/cmd_hash_object.c +++ b/src/cli/cmd_hash_object.c @@ -6,7 +6,7 @@ */ #include -#include "cli.h" +#include "common.h" #include "cmd.h" #include "futils.h" diff --git a/src/cli/cmd_help.c b/src/cli/cmd_help.c index 7ee9822427c..c9ac48aa96e 100644 --- a/src/cli/cmd_help.c +++ b/src/cli/cmd_help.c @@ -7,7 +7,7 @@ #include #include -#include "cli.h" +#include "common.h" #include "cmd.h" #define COMMAND_NAME "help" diff --git a/src/cli/common.c b/src/cli/common.c new file mode 100644 index 00000000000..60b0358662b --- /dev/null +++ b/src/cli/common.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include + +#include "git2_util.h" +#include "vector.h" + +#include "common.h" +#include "error.h" + +static int parse_option(cli_opt *opt, void *data) +{ + git_str kv = GIT_STR_INIT, env = GIT_STR_INIT; + git_vector *cmdline_config = data; + int error = 0; + + if (opt->spec && opt->spec->alias == 'c') { + if (git_str_puts(&kv, opt->value) < 0) { + error = cli_error_git(); + goto done; + } + } + + else if (opt->spec && !strcmp(opt->spec->name, "config-env")) { + char *val = strchr(opt->value, '='); + + if (val == NULL || *(val + 1) == '\0') { + error = cli_error("invalid config format: '%s'", opt->value); + goto done; + } + + if (git_str_put(&kv, opt->value, (val - opt->value)) < 0) { + error = cli_error_git(); + goto done; + } + + val++; + + if ((error = git__getenv(&env, val)) == GIT_ENOTFOUND) { + error = cli_error("missing environment variable '%s' for configuration '%s'", val, kv.ptr); + goto done; + } else if (error) { + error = cli_error_git(); + goto done; + } + + if (git_str_putc(&kv, '=') < 0 || + git_str_puts(&kv, env.ptr) < 0) { + error = cli_error_git(); + goto done; + } + } + + if (kv.size > 0 && + git_vector_insert(cmdline_config, git_str_detach(&kv)) < 0) + error = cli_error_git(); + +done: + git_str_dispose(&env); + git_str_dispose(&kv); + return error; +} + +static int parse_common_options( + git_repository *repo, + cli_repository_open_options *opts) +{ + cli_opt_spec common_opts[] = { + { CLI_COMMON_OPT_CONFIG }, + { CLI_COMMON_OPT_CONFIG_ENV }, + { 0 } + }; + git_config_backend_memory_options config_opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + git_vector cmdline = GIT_VECTOR_INIT; + git_config *config = NULL; + git_config_backend *backend = NULL; + int error = 0; + + config_opts.backend_type = "command line"; + + if ((error = cli_opt_foreach(common_opts, opts->args, + opts->args_len, CLI_OPT_PARSE_GNU, parse_option, + &cmdline)) < 0) + goto done; + + if (git_vector_length(&cmdline) == 0) + goto done; + + if (git_repository_config(&config, repo) < 0 || + git_config_backend_from_values(&backend, + (const char **)cmdline.contents, cmdline.length, + &config_opts) < 0 || + git_config_add_backend(config, backend, GIT_CONFIG_LEVEL_APP, + repo, 0) < 0) + error = cli_error_git(); + +done: + if (error && backend) + backend->free(backend); + git_config_free(config); + git_vector_free_deep(&cmdline); + return error; +} + +int cli_repository_open( + git_repository **out, + cli_repository_open_options *opts) +{ + git_repository *repo; + + if (git_repository_open_ext(&repo, ".", GIT_REPOSITORY_OPEN_FROM_ENV, NULL) < 0) + return -1; + + if (opts && parse_common_options(repo, opts) < 0) + return -1; + + *out = repo; + return 0; +} diff --git a/src/cli/common.h b/src/cli/common.h new file mode 100644 index 00000000000..0d98c56cb12 --- /dev/null +++ b/src/cli/common.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_common_h__ +#define CLI_common_h__ + +#define PROGRAM_NAME "git2" + +#include "git2_util.h" + +#include "error.h" +#include "opt.h" +#include "opt_usage.h" + +/* + * Common command arguments. + */ + +#define CLI_COMMON_OPT_HELP \ + CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING +#define CLI_COMMON_OPT_CONFIG \ + CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ + CLI_OPT_USAGE_HIDDEN +#define CLI_COMMON_OPT_CONFIG_ENV \ + CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ + CLI_OPT_USAGE_HIDDEN + +#define CLI_COMMON_OPT \ + { CLI_COMMON_OPT_HELP }, \ + { CLI_COMMON_OPT_CONFIG }, \ + { CLI_COMMON_OPT_CONFIG_ENV } + +typedef struct { + char **args; + int args_len; +} cli_repository_open_options; + +extern int cli_repository_open( + git_repository **out, + cli_repository_open_options *opts); + +#endif /* CLI_common_h__ */ diff --git a/src/cli/error.h b/src/cli/error.h index cce7a54c093..abf8a5160d1 100644 --- a/src/cli/error.h +++ b/src/cli/error.h @@ -8,7 +8,7 @@ #ifndef CLI_error_h__ #define CLI_error_h__ -#include "cli.h" +#include "common.h" #include #define CLI_EXIT_OK 0 diff --git a/src/cli/main.c b/src/cli/main.c index 96a70127546..d1639e62ee3 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -7,7 +7,7 @@ #include #include -#include "cli.h" +#include "common.h" #include "cmd.h" static int show_help = 0; diff --git a/src/cli/opt.c b/src/cli/opt.c index 62a3430d16e..25c97746f1d 100644 --- a/src/cli/opt.c +++ b/src/cli/opt.c @@ -19,7 +19,7 @@ #include #include -#include "cli.h" +#include "common.h" #include "opt.h" #ifdef _WIN32 @@ -73,7 +73,7 @@ GIT_INLINE(const cli_opt_spec *) spec_for_long( /* Handle --option=value arguments */ if (spec->type == CLI_OPT_TYPE_VALUE && - eql && + spec->name && eql && strncmp(arg, spec->name, eql_pos) == 0 && spec->name[eql_pos] == '\0') { *has_value = 1; @@ -575,6 +575,28 @@ cli_opt_status_t cli_opt_parse( return validate_required(opt, specs, given_specs); } +int cli_opt_foreach( + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags, + int (*callback)(cli_opt *, void *), + void *callback_data) +{ + cli_opt_parser parser; + cli_opt opt; + int ret; + + cli_opt_parser_init(&parser, specs, args, args_len, flags); + + while (cli_opt_parser_next(&opt, &parser)) { + if ((ret = callback(&opt, callback_data)) != 0) + return ret; + } + + return 0; +} + static int spec_name_fprint(FILE *file, const cli_opt_spec *spec) { int error; diff --git a/src/cli/opt.h b/src/cli/opt.h index 6c1d4603ecd..7133307b4f7 100644 --- a/src/cli/opt.h +++ b/src/cli/opt.h @@ -300,6 +300,14 @@ cli_opt_status_t cli_opt_parse( size_t args_len, unsigned int flags); +int cli_opt_foreach( + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags, + int (*callback)(cli_opt *, void *), + void *callback_data); + /** * Initializes a parser that parses the given arguments according to the * given specifications. diff --git a/src/cli/opt_usage.c b/src/cli/opt_usage.c index 478b416316d..8374f5151a7 100644 --- a/src/cli/opt_usage.c +++ b/src/cli/opt_usage.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "cli.h" +#include "common.h" #include "str.h" static int print_spec_name(git_str *out, const cli_opt_spec *spec) diff --git a/src/cli/unix/sighandler.c b/src/cli/unix/sighandler.c index 6b4982d48f2..05ac8672cad 100644 --- a/src/cli/unix/sighandler.c +++ b/src/cli/unix/sighandler.c @@ -8,7 +8,8 @@ #include #include #include "git2_util.h" -#include "cli.h" +#include "common.h" +#include "sighandler.h" static void (*interrupt_handler)(void) = NULL; diff --git a/src/cli/win32/precompiled.h b/src/cli/win32/precompiled.h index b0309b864ad..031370e87e7 100644 --- a/src/cli/win32/precompiled.h +++ b/src/cli/win32/precompiled.h @@ -1,3 +1,3 @@ #include -#include "cli.h" +#include "common.h" diff --git a/src/cli/win32/sighandler.c b/src/cli/win32/sighandler.c index cc0b6464033..05a67fb14fe 100644 --- a/src/cli/win32/sighandler.c +++ b/src/cli/win32/sighandler.c @@ -8,7 +8,7 @@ #include "git2_util.h" #include -#include "cli.h" +#include "sighandler.h" static void (*interrupt_handler)(void) = NULL; From 005bccea58e1e529e2af821f0d8f8c6423c0bb3e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Jul 2023 20:38:17 +0100 Subject: [PATCH 239/816] cli: reorder arguments for subcommands Instead of special casing `--help`, reorder the arguments for subcommands so that it can handle "global" arguments like `--help`, `-c key=value`, etc. --- src/cli/main.c | 53 ++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/cli/main.c b/src/cli/main.c index d1639e62ee3..6854b82289a 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -16,8 +16,12 @@ static char *command = NULL; static char **args = NULL; const cli_opt_spec cli_common_opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_DEFAULT, NULL, "display help information" }, + { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "display help information" }, + { CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, + CLI_OPT_USAGE_DEFAULT, "key=value", "add configuration value" }, + { CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, + CLI_OPT_USAGE_DEFAULT, "key=value", "set configuration value to environment variable" }, { CLI_OPT_TYPE_SWITCH, "version", 0, &show_version, 1, CLI_OPT_USAGE_DEFAULT, NULL, "display the version" }, { CLI_OPT_TYPE_ARG, "command", 0, &command, 0, @@ -36,14 +40,33 @@ const cli_cmd_spec cli_cmds[] = { { NULL } }; +/* + * Reorder the argv as it was given, since git has the notion of global + * options (like `--help` or `-c key=val`) that we want to pass to the + * subcommand, and that can appear early in the arguments, before the + * command name. Put the command-name in argv[1] to allow easier parsing. + */ +static void reorder_args(char **argv, size_t first) +{ + char *tmp; + size_t i; + + if (first == 1) + return; + + tmp = argv[first]; + + for (i = first; i > 1; i--) + argv[i] = argv[i - 1]; + + argv[1] = tmp; +} + int main(int argc, char **argv) { const cli_cmd_spec *cmd; cli_opt_parser optparser; cli_opt opt; - char *help_args[3] = { NULL }; - int help_args_len; - int args_len = 0; int ret = 0; if (git_libgit2_init() < 0) { @@ -67,8 +90,7 @@ int main(int argc, char **argv) * remaining arguments as args for the command itself. */ if (command) { - args = &argv[optparser.idx]; - args_len = (int)(argc - optparser.idx); + reorder_args(argv, optparser.idx); break; } } @@ -78,28 +100,13 @@ int main(int argc, char **argv) goto done; } - /* - * If `--help ` is specified, delegate to that command's - * `--help` option. If no command is specified, run the `help` - * command. Do this by updating the args to emulate that behavior. - */ - if (!command || show_help) { - help_args[0] = command ? (char *)command : "help"; - help_args[1] = command ? "--help" : NULL; - help_args_len = command ? 2 : 1; - - command = help_args[0]; - args = help_args; - args_len = help_args_len; - } - if ((cmd = cli_cmd_spec_byname(command)) == NULL) { ret = cli_error("'%s' is not a %s command. See '%s help'.", command, PROGRAM_NAME, PROGRAM_NAME); goto done; } - ret = cmd->fn(args_len, args); + ret = cmd->fn(argc - 1, &argv[1]); done: git_libgit2_shutdown(); From 90d3cc6cd4e4562023134202aae9294a86d99347 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 24 Jul 2023 21:27:10 +0100 Subject: [PATCH 240/816] cli: common options --- src/cli/cmd_cat_file.c | 4 +--- src/cli/cmd_clone.c | 4 +--- src/cli/cmd_config.c | 14 +------------- src/cli/cmd_hash_object.c | 4 +--- src/cli/cmd_help.c | 4 ++-- src/cli/common.h | 19 +++++++++++++++++++ 6 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/cli/cmd_cat_file.c b/src/cli/cmd_cat_file.c index 96cab4a67ac..f05449e7d9b 100644 --- a/src/cli/cmd_cat_file.c +++ b/src/cli/cmd_cat_file.c @@ -24,9 +24,7 @@ static int display = DISPLAY_CONTENT; static char *type_name, *object_spec; static const cli_opt_spec opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, - "display help about the " COMMAND_NAME " command" }, + CLI_COMMON_OPT, { CLI_OPT_TYPE_SWITCH, NULL, 't', &display, DISPLAY_TYPE, CLI_OPT_USAGE_REQUIRED, NULL, "display the type of the object" }, diff --git a/src/cli/cmd_clone.c b/src/cli/cmd_clone.c index 90d3e3db3b8..7d9736fc72a 100644 --- a/src/cli/cmd_clone.c +++ b/src/cli/cmd_clone.c @@ -24,9 +24,7 @@ static bool local_path_exists; static cli_progress progress = CLI_PROGRESS_INIT; static const cli_opt_spec opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, - "display help about the " COMMAND_NAME " command" }, + CLI_COMMON_OPT, { CLI_OPT_TYPE_SWITCH, "quiet", 'q', &quiet, 1, CLI_OPT_USAGE_DEFAULT, NULL, "display the type of the object" }, diff --git a/src/cli/cmd_config.c b/src/cli/cmd_config.c index 75044af7a25..c393fe8efce 100644 --- a/src/cli/cmd_config.c +++ b/src/cli/cmd_config.c @@ -25,20 +25,8 @@ static int show_help; static int null_separator; static char *name; -#define CLI_COMMON_OPT_HELP \ - CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING -#define CLI_COMMON_OPT_CONFIG \ - CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ - CLI_OPT_USAGE_HIDDEN -#define CLI_COMMON_OPT_CONFIG_ENV \ - CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ - CLI_OPT_USAGE_HIDDEN - static const cli_opt_spec opts[] = { - { CLI_COMMON_OPT_HELP }, - { CLI_COMMON_OPT_CONFIG }, - { CLI_COMMON_OPT_CONFIG_ENV }, + CLI_COMMON_OPT, \ { CLI_OPT_TYPE_SWITCH, "null", 'z', &null_separator, 1, 0, NULL, "use NUL as a separator" }, diff --git a/src/cli/cmd_hash_object.c b/src/cli/cmd_hash_object.c index 529a1ec44e5..a35f0666277 100644 --- a/src/cli/cmd_hash_object.c +++ b/src/cli/cmd_hash_object.c @@ -19,9 +19,7 @@ static int write_object, read_stdin, literally; static char **filenames; static const cli_opt_spec opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, - "display help about the " COMMAND_NAME " command" }, + CLI_COMMON_OPT, { CLI_OPT_TYPE_VALUE, NULL, 't', &type_name, 0, CLI_OPT_USAGE_DEFAULT, "type", "the type of object to hash (default: \"blob\")" }, diff --git a/src/cli/cmd_help.c b/src/cli/cmd_help.c index c9ac48aa96e..5e877e06dbf 100644 --- a/src/cli/cmd_help.c +++ b/src/cli/cmd_help.c @@ -16,8 +16,8 @@ static char *command; static int show_help; static const cli_opt_spec opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_HIDDEN, NULL, "display help about the help command" }, + CLI_COMMON_OPT, + { CLI_OPT_TYPE_ARG, "command", 0, &command, 0, CLI_OPT_USAGE_DEFAULT, "command", "the command to show help for" }, { 0 }, diff --git a/src/cli/common.h b/src/cli/common.h index 0d98c56cb12..3aed8ad8a42 100644 --- a/src/cli/common.h +++ b/src/cli/common.h @@ -44,4 +44,23 @@ extern int cli_repository_open( git_repository **out, cli_repository_open_options *opts); +/* + * Common command arguments. + */ + +#define CLI_COMMON_OPT_HELP \ + CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING +#define CLI_COMMON_OPT_CONFIG \ + CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ + CLI_OPT_USAGE_HIDDEN +#define CLI_COMMON_OPT_CONFIG_ENV \ + CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ + CLI_OPT_USAGE_HIDDEN + +#define CLI_COMMON_OPT \ + { CLI_COMMON_OPT_HELP }, \ + { CLI_COMMON_OPT_CONFIG }, \ + { CLI_COMMON_OPT_CONFIG_ENV } + #endif /* CLI_common_h__ */ From 4470ea3920e969bf7c9236bccccb8414a537f566 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Jul 2023 11:03:36 +0200 Subject: [PATCH 241/816] cli: use cli_repository_open --- src/cli/cmd_cat_file.c | 3 ++- src/cli/cmd_hash_object.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cli/cmd_cat_file.c b/src/cli/cmd_cat_file.c index f05449e7d9b..90ee6033e8c 100644 --- a/src/cli/cmd_cat_file.c +++ b/src/cli/cmd_cat_file.c @@ -137,6 +137,7 @@ static int print_pretty(git_object *object) int cmd_cat_file(int argc, char **argv) { + cli_repository_open_options open_opts = { argv + 1, argc - 1}; git_repository *repo = NULL; git_object *object = NULL; git_object_t type; @@ -151,7 +152,7 @@ int cmd_cat_file(int argc, char **argv) return 0; } - if (git_repository_open_ext(&repo, ".", GIT_REPOSITORY_OPEN_FROM_ENV, NULL) < 0) + if (cli_repository_open(&repo, &open_opts) < 0) return cli_error_git(); if ((giterr = git_revparse_single(&object, repo, object_spec)) < 0) { diff --git a/src/cli/cmd_hash_object.c b/src/cli/cmd_hash_object.c index a35f0666277..741debbeb2f 100644 --- a/src/cli/cmd_hash_object.c +++ b/src/cli/cmd_hash_object.c @@ -90,6 +90,7 @@ static int hash_buf( int cmd_hash_object(int argc, char **argv) { + cli_repository_open_options open_opts = { argv + 1, argc - 1}; git_repository *repo = NULL; git_odb *odb = NULL; git_oid_t oid_type; @@ -111,7 +112,7 @@ int cmd_hash_object(int argc, char **argv) return cli_error_usage("invalid object type '%s'", type_name); if (write_object && - (git_repository_open_ext(&repo, ".", GIT_REPOSITORY_OPEN_FROM_ENV, NULL) < 0 || + (cli_repository_open(&repo, &open_opts) < 0 || git_repository_odb(&odb, repo) < 0)) { ret = cli_error_git(); goto done; From a7512e68039c512c08208cd45136507c181607f9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Jul 2023 17:30:47 +0200 Subject: [PATCH 242/816] cli: add file levels to config command --- src/cli/cmd_config.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/cli/cmd_config.c b/src/cli/cmd_config.c index c393fe8efce..31c4c09bb02 100644 --- a/src/cli/cmd_config.c +++ b/src/cli/cmd_config.c @@ -23,6 +23,8 @@ static int show_origin; static int show_scope; static int show_help; static int null_separator; +static int config_level; +static char *config_filename; static char *name; static const cli_opt_spec opts[] = { @@ -31,16 +33,25 @@ static const cli_opt_spec opts[] = { { CLI_OPT_TYPE_SWITCH, "null", 'z', &null_separator, 1, 0, NULL, "use NUL as a separator" }, - { CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET, + { CLI_OPT_TYPE_SWITCH, "system", 0, &config_level, GIT_CONFIG_LEVEL_SYSTEM, + 0, NULL, "read/write to system configuration" }, + { CLI_OPT_TYPE_SWITCH, "global", 0, &config_level, GIT_CONFIG_LEVEL_GLOBAL, + CLI_OPT_USAGE_CHOICE, NULL, "read/write to global configuration" }, + { CLI_OPT_TYPE_SWITCH, "local", 0, &config_level, GIT_CONFIG_LEVEL_LOCAL, + CLI_OPT_USAGE_CHOICE, NULL, "read/write to local configuration" }, + { CLI_OPT_TYPE_VALUE, "file", 0, &config_filename, 0, + CLI_OPT_USAGE_CHOICE, "filename", "read/write to specified configuration file" }, + + { CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET, CLI_OPT_USAGE_REQUIRED, NULL, "get a configuration value" }, - { CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST, + { CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST, CLI_OPT_USAGE_CHOICE | CLI_OPT_USAGE_SHOW_LONG, NULL, "list all configuration entries" }, - { CLI_OPT_TYPE_SWITCH, "show-origin", 0, &show_origin, 1, + { CLI_OPT_TYPE_SWITCH, "show-origin", 0, &show_origin, 1, 0, NULL, "show origin of configuration" }, - { CLI_OPT_TYPE_SWITCH, "show-scope", 0, &show_scope, 1, + { CLI_OPT_TYPE_SWITCH, "show-scope", 0, &show_scope, 1, 0, NULL, "show scope of configuration" }, - { CLI_OPT_TYPE_ARG, "name", 0, &name, 0, + { CLI_OPT_TYPE_ARG, "name", 0, &name, 0, 0, "name", "name of configuration entry" }, { 0 }, }; @@ -148,10 +159,25 @@ int cmd_config(int argc, char **argv) return 0; } - if (cli_repository_open(&repo, &open_opts) < 0 || - git_repository_config(&config, repo) < 0) { - ret = cli_error_git(); - goto done; + if (config_filename) { + if (git_config_new(&config) < 0 || + git_config_add_file_ondisk(config, config_filename, + GIT_CONFIG_LEVEL_APP, NULL, 0) < 0) { + ret = cli_error_git(); + goto done; + } + } else { + if (cli_repository_open(&repo, &open_opts) < 0 || + git_repository_config(&config, repo) < 0) { + ret = cli_error_git(); + goto done; + } + + if (config_level && + git_config_open_level(&config, config, config_level) < 0) { + ret = cli_error_git(); + goto done; + } } switch (action) { From 929ec75451943085821f38f069ec667c902f6bf8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Jul 2023 18:15:00 +0200 Subject: [PATCH 243/816] cli: add `--add` and `--replace-all` to config --- src/cli/cmd_config.c | 48 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/cli/cmd_config.c b/src/cli/cmd_config.c index 31c4c09bb02..6b9d373cee6 100644 --- a/src/cli/cmd_config.c +++ b/src/cli/cmd_config.c @@ -15,6 +15,8 @@ typedef enum { ACTION_NONE = 0, ACTION_GET, + ACTION_ADD, + ACTION_REPLACE_ALL, ACTION_LIST } action_t; @@ -25,7 +27,7 @@ static int show_help; static int null_separator; static int config_level; static char *config_filename; -static char *name; +static char *name, *value, *value_pattern; static const cli_opt_spec opts[] = { CLI_COMMON_OPT, \ @@ -44,6 +46,10 @@ static const cli_opt_spec opts[] = { { CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET, CLI_OPT_USAGE_REQUIRED, NULL, "get a configuration value" }, + { CLI_OPT_TYPE_SWITCH, "add", 0, &action, ACTION_ADD, + CLI_OPT_USAGE_CHOICE, NULL, "add a configuration value" }, + { CLI_OPT_TYPE_SWITCH, "replace-all", 0, &action, ACTION_REPLACE_ALL, + CLI_OPT_USAGE_CHOICE, NULL, "add a configuration value, replacing any old values" }, { CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST, CLI_OPT_USAGE_CHOICE | CLI_OPT_USAGE_SHOW_LONG, NULL, "list all configuration entries" }, @@ -53,6 +59,10 @@ static const cli_opt_spec opts[] = { 0, NULL, "show scope of configuration" }, { CLI_OPT_TYPE_ARG, "name", 0, &name, 0, 0, "name", "name of configuration entry" }, + { CLI_OPT_TYPE_ARG, "value", 0, &value, 0, + 0, "value", "value of configuration entry" }, + { CLI_OPT_TYPE_ARG, "regexp", 0, &value_pattern, 0, + 0, "regexp", "regular expression of values to replace" }, { 0 }, }; @@ -87,6 +97,22 @@ static int get_config(git_config *config) return 0; } +static int add_config(git_config *config) +{ + if (git_config_set_multivar(config, name, "$^", value) < 0) + return cli_error_git(); + + return 0; +} + +static int replace_all_config(git_config *config) +{ + if (git_config_set_multivar(config, name, value_pattern ? value_pattern : ".*", value) < 0) + return cli_error_git(); + + return 0; +} + static const char *level_name(git_config_level_t level) { switch (level) { @@ -181,11 +207,17 @@ int cmd_config(int argc, char **argv) } switch (action) { - case ACTION_LIST: - if (name) - ret = cli_error_usage("%s --list does not take an argument", COMMAND_NAME); + case ACTION_ADD: + if (!name || !value || value_pattern) + ret = cli_error_usage("%s --add requires two arguments", COMMAND_NAME); else - ret = list_config(config); + ret = add_config(config); + break; + case ACTION_REPLACE_ALL: + if (!name || !value) + ret = cli_error_usage("%s --replace-all requires two or three arguments", COMMAND_NAME); + else + ret = replace_all_config(config); break; case ACTION_GET: if (!name) @@ -193,6 +225,12 @@ int cmd_config(int argc, char **argv) else ret = get_config(config); break; + case ACTION_LIST: + if (name) + ret = cli_error_usage("%s --list does not take an argument", COMMAND_NAME); + else + ret = list_config(config); + break; default: ret = cli_error_usage("unknown action"); } From a79aa14206ca07c07ead829914d47090541d5376 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 31 Jul 2023 17:14:29 +0100 Subject: [PATCH 244/816] httpclient: safety --- src/libgit2/transports/httpclient.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index 0ad6cd4dcb9..a20b594930d 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -837,6 +837,11 @@ GIT_INLINE(int) server_setup_from_url( git_http_server *server, git_net_url *url) { + GIT_ASSERT_ARG(url); + GIT_ASSERT_ARG(url->scheme); + GIT_ASSERT_ARG(url->host); + GIT_ASSERT_ARG(url->port); + if (!server->url.scheme || strcmp(server->url.scheme, url->scheme) || !server->url.host || strcmp(server->url.host, url->host) || !server->url.port || strcmp(server->url.port, url->port)) { From 8c2c0fa80a14d2e1769e5b1836aa121e287f2498 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Aug 2023 11:58:53 +0100 Subject: [PATCH 245/816] net: refactor url parsing Refactor url parsing to simplify the state-passing (introducing a struct) and add a path parser for future reusability. --- src/util/net.c | 378 ++++++++++++++++++++++++----------------- tests/util/url/parse.c | 14 ++ 2 files changed, 235 insertions(+), 157 deletions(-) diff --git a/src/util/net.c b/src/util/net.c index dd8a1ba4670..15fff859213 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -19,6 +19,30 @@ #define DEFAULT_PORT_GIT "9418" #define DEFAULT_PORT_SSH "22" +#define GIT_NET_URL_PARSER_INIT { 0 } + +typedef struct { + int hierarchical : 1; + + const char *scheme; + const char *user; + const char *password; + const char *host; + const char *port; + const char *path; + const char *query; + const char *fragment; + + size_t scheme_len; + size_t user_len; + size_t password_len; + size_t host_len; + size_t port_len; + size_t path_len; + size_t query_len; + size_t fragment_len; +} git_net_url_parser; + bool git_net_hostname_matches_cert( const char *hostname, const char *pattern) @@ -63,6 +87,12 @@ bool git_net_hostname_matches_cert( return false; } +#define is_valid_scheme_char(c) \ + (((c) >= 'a' && (c) <= 'z') || \ + ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= '0' && (c) <= '9') || \ + (c) == '+' || (c) == '-' || (c) == '.') + bool git_net_str_is_url(const char *str) { const char *c; @@ -71,10 +101,7 @@ bool git_net_str_is_url(const char *str) if (*c == ':' && *(c+1) == '/' && *(c+2) == '/') return true; - if ((*c < 'a' || *c > 'z') && - (*c < 'A' || *c > 'Z') && - (*c < '0' || *c > '9') && - (*c != '+' && *c != '-' && *c != '.')) + if (!is_valid_scheme_char(*c)) break; } @@ -97,6 +124,16 @@ static const char *default_port_for_scheme(const char *scheme) return NULL; } +static bool is_ssh_scheme(const char *scheme, size_t scheme_len) +{ + if (!scheme_len) + return false; + + return strncasecmp(scheme, "ssh", scheme_len) == 0 || + strncasecmp(scheme, "ssh+git", scheme_len) == 0 || + strncasecmp(scheme, "git+ssh", scheme_len) == 0; +} + int git_net_url_dup(git_net_url *out, git_net_url *in) { if (in->scheme) { @@ -144,12 +181,9 @@ static int url_invalid(const char *message) } static int url_parse_authority( - const char **user_start, size_t *user_len, - const char **password_start, size_t *password_len, - const char **host_start, size_t *host_len, - const char **port_start, size_t *port_len, - const char *authority_start, size_t len, - const char *scheme_start, size_t scheme_len) + git_net_url_parser *parser, + const char *authority, + size_t len) { const char *c, *hostport_end, *host_end = NULL, *userpass_end, *user_end = NULL; @@ -165,14 +199,14 @@ static int url_parse_authority( * walk the authority backwards so that we can parse google code's * ssh urls that are not rfc compliant and allow @ in the username */ - for (hostport_end = authority_start + len, c = hostport_end - 1; - c >= authority_start && !user_end; + for (hostport_end = authority + len, c = hostport_end - 1; + c >= authority && !user_end; c--) { switch (state) { case HOSTPORT: if (*c == ':') { - *port_start = c + 1; - *port_len = hostport_end - *port_start; + parser->port = c + 1; + parser->port_len = hostport_end - parser->port; host_end = c; state = HOST; break; @@ -200,9 +234,10 @@ static int url_parse_authority( } else if (*c == '@') { - *host_start = c + 1; - *host_len = host_end ? host_end - *host_start : - hostport_end - *host_start; + parser->host = c + 1; + parser->host_len = host_end ? + host_end - parser->host : + hostport_end - parser->host; userpass_end = c; state = USERPASS; } @@ -215,8 +250,8 @@ static int url_parse_authority( case IPV6: if (*c == '[') { - *host_start = c + 1; - *host_len = host_end - *host_start; + parser->host = c + 1; + parser->host_len = host_end - parser->host; state = HOST_END; } @@ -240,12 +275,12 @@ static int url_parse_authority( case USERPASS: if (*c == '@' && - strncasecmp(scheme_start, "ssh", scheme_len)) + !is_ssh_scheme(parser->scheme, parser->scheme_len)) return url_invalid("malformed hostname"); if (*c == ':') { - *password_start = c + 1; - *password_len = userpass_end - *password_start; + parser->password = c + 1; + parser->password_len = userpass_end - parser->password; user_end = c; state = USER; break; @@ -260,24 +295,24 @@ static int url_parse_authority( switch (state) { case HOSTPORT: - *host_start = authority_start; - *host_len = (hostport_end - *host_start); + parser->host = authority; + parser->host_len = (hostport_end - parser->host); break; case HOST: - *host_start = authority_start; - *host_len = (host_end - *host_start); + parser->host = authority; + parser->host_len = (host_end - parser->host); break; case IPV6: return url_invalid("malformed hostname"); case HOST_END: break; case USERPASS: - *user_start = authority_start; - *user_len = (userpass_end - *user_start); + parser->user = authority; + parser->user_len = (userpass_end - parser->user); break; case USER: - *user_start = authority_start; - *user_len = (user_end - *user_start); + parser->user = authority; + parser->user_len = (user_end - parser->user); break; default: GIT_ASSERT(!"unhandled state"); @@ -286,97 +321,30 @@ static int url_parse_authority( return 0; } -int git_net_url_parse(git_net_url *url, const char *given) +static int url_parse_path( + git_net_url_parser *parser, + const char *path, + size_t len) { - const char *c, *scheme_start, *authority_start, *user_start, - *password_start, *host_start, *port_start, *path_start, - *query_start, *fragment_start, *default_port; - git_str scheme = GIT_STR_INIT, user = GIT_STR_INIT, - password = GIT_STR_INIT, host = GIT_STR_INIT, - port = GIT_STR_INIT, path = GIT_STR_INIT, - query = GIT_STR_INIT, fragment = GIT_STR_INIT; - size_t scheme_len = 0, user_len = 0, password_len = 0, host_len = 0, - port_len = 0, path_len = 0, query_len = 0, fragment_len = 0; - bool hierarchical = false; - int error = 0; + const char *c, *end; - enum { - SCHEME, - AUTHORITY_START, AUTHORITY, - PATH_START, PATH, - QUERY, - FRAGMENT - } state = SCHEME; + enum { PATH, QUERY, FRAGMENT } state = PATH; - memset(url, 0, sizeof(git_net_url)); + parser->path = path; + end = path + len; - for (c = scheme_start = given; *c; c++) { + for (c = path; c < end; c++) { switch (state) { - case SCHEME: - if (*c == ':') { - scheme_len = (c - scheme_start); - - if (*(c+1) == '/' && *(c+2) == '/') { - c += 2; - hierarchical = true; - state = AUTHORITY_START; - } else { - state = PATH_START; - } - } else if ((*c < 'A' || *c > 'Z') && - (*c < 'a' || *c > 'z') && - (*c < '0' || *c > '9') && - (*c != '+' && *c != '-' && *c != '.')) { - /* - * an illegal scheme character means that we - * were just given a relative path - */ - path_start = given; - state = PATH; - break; - } - break; - - case AUTHORITY_START: - authority_start = c; - state = AUTHORITY; - - /* fall through */ - - case AUTHORITY: - if (*c != '/') - break; - - /* - * authority is sufficiently complex that we parse - * it separately - */ - if ((error = url_parse_authority( - &user_start, &user_len, - &password_start,&password_len, - &host_start, &host_len, - &port_start, &port_len, - authority_start, (c - authority_start), - scheme_start, scheme_len)) < 0) - goto done; - - /* fall through */ - - case PATH_START: - path_start = c; - state = PATH; - /* fall through */ - case PATH: switch (*c) { case '?': - path_len = (c - path_start); - query_start = c + 1; + parser->path_len = (c - parser->path); + parser->query = c + 1; state = QUERY; break; case '#': - path_len = (c - path_start); - fragment_start = c + 1; + parser->path_len = (c - parser->path); + parser->fragment = c + 1; state = FRAGMENT; break; } @@ -384,8 +352,8 @@ int git_net_url_parse(git_net_url *url, const char *given) case QUERY: if (*c == '#') { - query_len = (c - query_start); - fragment_start = c + 1; + parser->query_len = (c - parser->query); + parser->fragment = c + 1; state = FRAGMENT; } break; @@ -399,82 +367,70 @@ int git_net_url_parse(git_net_url *url, const char *given) } switch (state) { - case SCHEME: - /* - * if we never saw a ':' then we were given a relative - * path, not a bare scheme - */ - path_start = given; - path_len = (c - scheme_start); - break; - case AUTHORITY_START: - break; - case AUTHORITY: - if ((error = url_parse_authority( - &user_start, &user_len, - &password_start,&password_len, - &host_start, &host_len, - &port_start, &port_len, - authority_start, (c - authority_start), - scheme_start, scheme_len)) < 0) - goto done; - break; - case PATH_START: - break; case PATH: - path_len = (c - path_start); + parser->path_len = (c - parser->path); break; case QUERY: - query_len = (c - query_start); + parser->query_len = (c - parser->query); break; case FRAGMENT: - fragment_len = (c - fragment_start); + parser->fragment_len = (c - parser->fragment); break; - default: - GIT_ASSERT(!"unhandled state"); } - if (scheme_len) { - if ((error = git_str_put(&scheme, scheme_start, scheme_len)) < 0) + return 0; +} + +static int url_parse_finalize(git_net_url *url, git_net_url_parser *parser) +{ + git_str scheme = GIT_STR_INIT, user = GIT_STR_INIT, + password = GIT_STR_INIT, host = GIT_STR_INIT, + port = GIT_STR_INIT, path = GIT_STR_INIT, + query = GIT_STR_INIT, fragment = GIT_STR_INIT; + const char *default_port; + int error = 0; + + if (parser->scheme_len) { + if ((error = git_str_put(&scheme, parser->scheme, parser->scheme_len)) < 0) goto done; git__strntolower(scheme.ptr, scheme.size); } - if (user_len && - (error = git_str_decode_percent(&user, user_start, user_len)) < 0) + if (parser->user_len && + (error = git_str_decode_percent(&user, parser->user, parser->user_len)) < 0) goto done; - if (password_len && - (error = git_str_decode_percent(&password, password_start, password_len)) < 0) + if (parser->password_len && + (error = git_str_decode_percent(&password, parser->password, parser->password_len)) < 0) goto done; - if (host_len && - (error = git_str_decode_percent(&host, host_start, host_len)) < 0) + if (parser->host_len && + (error = git_str_decode_percent(&host, parser->host, parser->host_len)) < 0) goto done; - if (port_len) - error = git_str_put(&port, port_start, port_len); - else if (scheme_len && (default_port = default_port_for_scheme(scheme.ptr)) != NULL) + if (parser->port_len) + error = git_str_put(&port, parser->port, parser->port_len); + else if (parser->scheme_len && (default_port = default_port_for_scheme(scheme.ptr)) != NULL) error = git_str_puts(&port, default_port); if (error < 0) goto done; - if (path_len) - error = git_str_put(&path, path_start, path_len); - else if (hierarchical) + if (parser->path_len) + error = git_str_put(&path, parser->path, parser->path_len); + else if (parser->hierarchical) error = git_str_puts(&path, "/"); if (error < 0) goto done; - if (query_len && - (error = git_str_decode_percent(&query, query_start, query_len)) < 0) + if (parser->query_len && + (error = git_str_decode_percent(&query, parser->query, parser->query_len)) < 0) goto done; - if (fragment_len && - (error = git_str_decode_percent(&fragment, fragment_start, fragment_len)) < 0) + if (parser->fragment_len && + (error = git_str_decode_percent(&fragment, parser->fragment, parser->fragment_len)) < 0) goto done; url->scheme = git_str_detach(&scheme); @@ -501,6 +457,114 @@ int git_net_url_parse(git_net_url *url, const char *given) return error; } +int git_net_url_parse(git_net_url *url, const char *given) +{ + git_net_url_parser parser = GIT_NET_URL_PARSER_INIT; + const char *c, *authority, *path; + size_t authority_len = 0, path_len = 0; + int error = 0; + + enum { + SCHEME_START, SCHEME, + AUTHORITY_START, AUTHORITY, + PATH_START, PATH + } state = SCHEME_START; + + memset(url, 0, sizeof(git_net_url)); + + for (c = given; *c; c++) { + switch (state) { + case SCHEME_START: + parser.scheme = c; + state = SCHEME; + + /* fall through */ + + case SCHEME: + if (*c == ':') { + parser.scheme_len = (c - parser.scheme); + + if (parser.scheme_len && + *(c+1) == '/' && *(c+2) == '/') { + c += 2; + parser.hierarchical = 1; + state = AUTHORITY_START; + } else { + state = PATH_START; + } + } else if (!is_valid_scheme_char(*c)) { + /* + * an illegal scheme character means that we + * were just given a relative path + */ + path = given; + state = PATH; + break; + } + break; + + case AUTHORITY_START: + authority = c; + state = AUTHORITY; + + /* fall through */ + case AUTHORITY: + if (*c != '/') + break; + + authority_len = (c - authority); + + /* fall through */ + case PATH_START: + path = c; + state = PATH; + break; + + case PATH: + break; + + default: + GIT_ASSERT(!"unhandled state"); + } + } + + switch (state) { + case SCHEME: + /* + * if we never saw a ':' then we were given a relative + * path, not a bare scheme + */ + path = given; + path_len = (c - path); + break; + case AUTHORITY_START: + break; + case AUTHORITY: + authority_len = (c - authority); + break; + case PATH_START: + break; + case PATH: + path_len = (c - path); + break; + default: + GIT_ASSERT(!"unhandled state"); + } + + if (authority_len && + (error = url_parse_authority(&parser, authority, authority_len)) < 0) + goto done; + + if (path_len && + (error = url_parse_path(&parser, path, path_len)) < 0) + goto done; + + error = url_parse_finalize(url, &parser); + +done: + return error; +} + static int scp_invalid(const char *message) { git_error_set(GIT_ERROR_NET, "invalid scp-style path: %s", message); diff --git a/tests/util/url/parse.c b/tests/util/url/parse.c index 631d9b456d9..35486f7b7a7 100644 --- a/tests/util/url/parse.c +++ b/tests/util/url/parse.c @@ -669,6 +669,20 @@ void test_url_parse__ipv6_invalid_addresses(void) /* Oddities */ +void test_url_parse__empty_scheme(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "://example.com/resource")); + cl_assert_equal_s(conndata.scheme, NULL); + cl_assert_equal_s(conndata.host, NULL); + cl_assert_equal_s(conndata.port, NULL); + cl_assert_equal_s(conndata.path, "//example.com/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + void test_url_parse__invalid_scheme_is_relative(void) { cl_git_pass(git_net_url_parse(&conndata, "foo!bar://host:42/path/to/project?query_string=yes")); From 8749655745d06b3be01222d512218dc16a359731 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Aug 2023 11:59:55 +0100 Subject: [PATCH 246/816] net: introduce http-biased url parsing Introduce a url parser that defaults to treating poorly specified URLs as http URLs. For example: `localhost:8080` is treated as `http://localhost:8080/` by the http-biased url parsing, instead of a URL with a scheme `localhost` and a path of `8080`.. --- src/util/net.c | 43 +++ src/util/net.h | 8 + tests/util/url/http.c | 752 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 803 insertions(+) create mode 100644 tests/util/url/http.c diff --git a/src/util/net.c b/src/util/net.c index 15fff859213..afd52ce0830 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -565,6 +565,49 @@ int git_net_url_parse(git_net_url *url, const char *given) return error; } +int git_net_url_parse_http( + git_net_url *url, + const char *given) +{ + git_net_url_parser parser = GIT_NET_URL_PARSER_INIT; + const char *c, *authority, *path = NULL; + size_t authority_len = 0, path_len = 0; + int error; + + /* Hopefully this is a proper URL with a scheme. */ + if (git_net_str_is_url(given)) + return git_net_url_parse(url, given); + + memset(url, 0, sizeof(git_net_url)); + + /* Without a scheme, we are in the host (authority) section. */ + for (c = authority = given; *c; c++) { + if (!path && *c == '/') { + authority_len = (c - authority); + path = c; + } + } + + if (path) + path_len = (c - path); + else + authority_len = (c - authority); + + parser.scheme = "http"; + parser.scheme_len = 4; + parser.hierarchical = 1; + + if (authority_len && + (error = url_parse_authority(&parser, authority, authority_len)) < 0) + return error; + + if (path_len && + (error = url_parse_path(&parser, path, path_len)) < 0) + return error; + + return url_parse_finalize(url, &parser); +} + static int scp_invalid(const char *message) { git_error_set(GIT_ERROR_NET, "invalid scp-style path: %s", message); diff --git a/src/util/net.h b/src/util/net.h index c9a84cb6cec..8024956ad0c 100644 --- a/src/util/net.h +++ b/src/util/net.h @@ -57,6 +57,14 @@ extern int git_net_url_parse_scp(git_net_url *url, const char *str); */ extern int git_net_url_parse_standard_or_scp(git_net_url *url, const char *str); +/** + * Parses a string containing an HTTP endpoint that may not be a + * well-formed URL. For example, "localhost" or "localhost:port". + */ +extern int git_net_url_parse_http( + git_net_url *url, + const char *str); + /** Appends a path and/or query string to the given URL */ extern int git_net_url_joinpath( git_net_url *out, diff --git a/tests/util/url/http.c b/tests/util/url/http.c new file mode 100644 index 00000000000..88238896257 --- /dev/null +++ b/tests/util/url/http.c @@ -0,0 +1,752 @@ +#include "clar_libgit2.h" +#include "net.h" + +static git_net_url conndata; + +void test_url_http__initialize(void) +{ + memset(&conndata, 0, sizeof(conndata)); +} + +void test_url_http__cleanup(void) +{ + git_net_url_dispose(&conndata); +} + +/* Hostname */ + +void test_url_http__has_scheme(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "http://example.com/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__no_scheme(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "example.com/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_root(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "example.com/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_implied_root(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "example.com")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_numeric(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "8888888/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "8888888"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_implied_root_custom_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "example.com:42")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__hostname_implied_root_empty_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "example.com:")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_encoded_password(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass%2fis%40bad@hostname.com:1234/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "hostname.com"); + cl_assert_equal_s(conndata.port, "1234"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass/is@bad"); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__hostname_user(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user@example.com/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_user_pass(void) +{ + /* user:pass@hostname.tld/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@example.com/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_port(void) +{ + /* hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "example.com:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__hostname_empty_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "example.com:/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__hostname_user_port(void) +{ + /* user@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "user@example.com:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__hostname_user_pass_port(void) +{ + /* user:pass@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@example.com:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__hostname_user_pass_port_query(void) +{ + /* user:pass@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@example.com:9191/resource?query=q&foo=bar&z=asdf")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_s(conndata.query, "query=q&foo=bar&z=asdf"); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__hostname_user_pass_port_fragment(void) +{ + /* user:pass@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@example.com:9191/resource#fragment")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_s(conndata.fragment, "fragment"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__hostname_user_pass_port_query_fragment(void) +{ + /* user:pass@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@example.com:9191/resource?query=q&foo=bar&z=asdf#fragment")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_s(conndata.query, "query=q&foo=bar&z=asdf"); + cl_assert_equal_s(conndata.fragment, "fragment"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__fragment_with_question_mark(void) +{ + /* user:pass@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@example.com:9191/resource#fragment_with?question_mark")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_s(conndata.fragment, "fragment_with?question_mark"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +/* IPv4 addresses */ + +void test_url_http__ipv4_trivial(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "192.168.1.1/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv4_root(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "192.168.1.1/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv4_implied_root(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "192.168.1.1")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv4_implied_root_custom_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "192.168.1.1:42")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv4_implied_root_empty_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "192.168.1.1:")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv4_encoded_password(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass%2fis%40bad@192.168.1.1:1234/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "1234"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass/is@bad"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv4_user(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user@192.168.1.1/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv4_user_pass(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@192.168.1.1/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv4_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "192.168.1.1:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv4_empty_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "192.168.1.1:/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv4_user_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user@192.168.1.1:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv4_user_pass_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@192.168.1.1:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +/* IPv6 addresses */ + +void test_url_http__ipv6_trivial(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "[fe80::dcad:beff:fe00:0001]/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv6_root(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "[fe80::dcad:beff:fe00:0001]/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv6_implied_root(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "[fe80::dcad:beff:fe00:0001]")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv6_implied_root_custom_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "[fe80::dcad:beff:fe00:0001]:42")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv6_implied_root_empty_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "[fe80::dcad:beff:fe00:0001]:")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv6_encoded_password(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001]:1234/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "1234"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass/is@bad"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv6_user(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user@[fe80::dcad:beff:fe00:0001]/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv6_user_pass(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@[fe80::dcad:beff:fe00:0001]/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv6_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv6_empty_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "[fe80::dcad:beff:fe00:0001]:/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__ipv6_user_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user@[fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv6_user_pass_port(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, + "user:pass@[fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_url_http__ipv6_invalid_addresses(void) +{ + /* Opening bracket missing */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001]/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001]")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001]:42")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001]:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001]:1234/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user@fe80::dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass@fe80::dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001]:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user@fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass@fe80::dcad:beff:fe00:0001]:9191/resource")); + + /* Closing bracket missing */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001:42")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001:1234/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user@[fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass@[fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user@[fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass@[fe80::dcad:beff:fe00:0001:9191/resource")); + + /* Both brackets missing */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001:42")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001:1234/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user@fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass@fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::dcad:beff:fe00:0001:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user@fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "user:pass@fe80::dcad:beff:fe00:0001:9191/resource")); + + /* Invalid character inside address */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, "[fe8o::dcad:beff:fe00:0001]/resource")); + + /* Characters before/after braces */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "fe80::[dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "cafe[fe80::dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_http(&conndata, + "[fe80::dcad:beff:fe00:0001]cafe/resource")); +} + +/* Oddities */ + +void test_url_http__invalid_scheme_is_relative(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "foo!bar://host:42/path/to/project?query_string=yes")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "foo!bar"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "//host:42/path/to/project"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_s(conndata.query, "query_string=yes"); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__scheme_case_is_normalized(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "GIT+SSH://host:42/path/to/project")); + cl_assert_equal_s(conndata.scheme, "git+ssh"); +} + +void test_url_http__no_scheme_relative_path(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "path")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "path"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__no_scheme_absolute_path(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "/path")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_p(conndata.host, NULL); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/path"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__empty_path_with_empty_authority(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_p(conndata.host, NULL); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_url_http__spaces_in_the_name(void) +{ + cl_git_pass(git_net_url_parse_http(&conndata, "libgit2@dev.azure.com/libgit2/test/_git/spaces%20in%20the%20name")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "dev.azure.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/libgit2/test/_git/spaces%20in%20the%20name"); + cl_assert_equal_s(conndata.username, "libgit2"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} From b6fdb3cbdf9ec0c663d4d34b0121c739a2d314fd Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Aug 2023 12:16:32 +0100 Subject: [PATCH 247/816] http: allow proxies to be specified in common format The common format for specifying proxy URLs is just 'host:port'. Handle the common case. --- src/libgit2/transports/http.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index eed51914549..8437674fcc9 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -335,7 +335,7 @@ static int lookup_proxy( } if (!proxy || - (error = git_net_url_parse(&transport->proxy.url, proxy)) < 0) + (error = git_net_url_parse_http(&transport->proxy.url, proxy)) < 0) goto done; if (!git_net_url_valid(&transport->proxy.url)) { From 5a64922408a5198c5ae00771b942fea1c76d2746 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Aug 2023 14:07:53 +0100 Subject: [PATCH 248/816] http: test proxies in url and host:port format Test proxies specified by both host:port format in configuration options, environment variables, and `http.proxy` configuration. --- tests/libgit2/online/clone.c | 124 ++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 17 deletions(-) diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 0c53514a425..5789e9654c3 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -43,7 +43,6 @@ static char *_github_ssh_privkey = NULL; static char *_github_ssh_passphrase = NULL; static char *_github_ssh_remotehostkey = NULL; -static int _orig_proxies_need_reset = 0; static char *_orig_http_proxy = NULL; static char *_orig_https_proxy = NULL; static char *_orig_no_proxy = NULL; @@ -99,10 +98,12 @@ void test_online_clone__initialize(void) _github_ssh_passphrase = cl_getenv("GITTEST_GITHUB_SSH_PASSPHRASE"); _github_ssh_remotehostkey = cl_getenv("GITTEST_GITHUB_SSH_REMOTE_HOSTKEY"); + _orig_http_proxy = cl_getenv("HTTP_PROXY"); + _orig_https_proxy = cl_getenv("HTTPS_PROXY"); + _orig_no_proxy = cl_getenv("NO_PROXY"); + if (_remote_expectcontinue) git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1); - - _orig_proxies_need_reset = 0; } void test_online_clone__cleanup(void) @@ -140,15 +141,13 @@ void test_online_clone__cleanup(void) git__free(_github_ssh_passphrase); git__free(_github_ssh_remotehostkey); - if (_orig_proxies_need_reset) { - cl_setenv("HTTP_PROXY", _orig_http_proxy); - cl_setenv("HTTPS_PROXY", _orig_https_proxy); - cl_setenv("NO_PROXY", _orig_no_proxy); + cl_setenv("HTTP_PROXY", _orig_http_proxy); + cl_setenv("HTTPS_PROXY", _orig_https_proxy); + cl_setenv("NO_PROXY", _orig_no_proxy); - git__free(_orig_http_proxy); - git__free(_orig_https_proxy); - git__free(_orig_no_proxy); - } + git__free(_orig_http_proxy); + git__free(_orig_https_proxy); + git__free(_orig_no_proxy); git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL); git_libgit2_opts(GIT_OPT_SET_SERVER_TIMEOUT, 0); @@ -968,6 +967,79 @@ static int proxy_cert_cb(git_cert *cert, int valid, const char *host, void *payl return valid ? 0 : GIT_ECERTIFICATE; } +void test_online_clone__proxy_http_host_port_in_opts(void) +{ + if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass) + cl_skip(); + + if (_remote_proxy_scheme && strcmp(_remote_proxy_scheme, "http") != 0) + cl_skip(); + + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED; + g_options.fetch_opts.proxy_opts.url = _remote_proxy_host; + g_options.fetch_opts.proxy_opts.credentials = proxy_cred_cb; + + called_proxy_creds = 0; + cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_assert(called_proxy_creds == 1); +} + +void test_online_clone__proxy_http_host_port_in_env(void) +{ + if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass) + cl_skip(); + + if (_remote_proxy_scheme && strcmp(_remote_proxy_scheme, "http") != 0) + cl_skip(); + + cl_setenv("HTTP_PROXY", _remote_proxy_host); + cl_setenv("HTTPS_PROXY", _remote_proxy_host); + cl_setenv("NO_PROXY", NULL); + + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; + g_options.fetch_opts.proxy_opts.credentials = proxy_cred_cb; + + called_proxy_creds = 0; + cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_assert(called_proxy_creds == 1); +} + +static int repository_create_with_proxy( + git_repository **out, + const char *path, + int bare, + void *payload) +{ + git_repository *repo; + git_config *config; + char *value = (char *)payload; + + cl_git_pass(git_repository_init(&repo, path, bare)); + cl_git_pass(git_repository_config(&config, repo)); + + cl_git_pass(git_config_set_string(config, "http.proxy", value)); + + git_config_free(config); + + *out = repo; + return 0; +} + +void test_online_clone__proxy_http_host_port_in_config(void) +{ + if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass) + cl_skip(); + + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; + g_options.fetch_opts.proxy_opts.credentials = proxy_cred_cb; + g_options.repository_cb = repository_create_with_proxy; + g_options.repository_cb_payload = _remote_proxy_host; + + called_proxy_creds = 0; + cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_assert(called_proxy_creds == 1); +} + void test_online_clone__proxy_invalid_url(void) { g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED; @@ -1003,7 +1075,7 @@ void test_online_clone__proxy_credentials_request(void) git_str_dispose(&url); } -void test_online_clone__proxy_credentials_in_url(void) +void test_online_clone__proxy_credentials_in_well_formed_url(void) { git_str url = GIT_STR_INIT; @@ -1024,17 +1096,35 @@ void test_online_clone__proxy_credentials_in_url(void) git_str_dispose(&url); } -void test_online_clone__proxy_credentials_in_environment(void) +void test_online_clone__proxy_credentials_in_host_port_format(void) { git_str url = GIT_STR_INIT; if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass) cl_skip(); - _orig_http_proxy = cl_getenv("HTTP_PROXY"); - _orig_https_proxy = cl_getenv("HTTPS_PROXY"); - _orig_no_proxy = cl_getenv("NO_PROXY"); - _orig_proxies_need_reset = 1; + if (_remote_proxy_scheme && strcmp(_remote_proxy_scheme, "http") != 0) + cl_skip(); + + cl_git_pass(git_str_printf(&url, "%s:%s@%s", + _remote_proxy_user, _remote_proxy_pass, _remote_proxy_host)); + + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED; + g_options.fetch_opts.proxy_opts.url = url.ptr; + g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb; + called_proxy_creds = 0; + cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_assert(called_proxy_creds == 0); + + git_str_dispose(&url); +} + +void test_online_clone__proxy_credentials_in_environment(void) +{ + git_str url = GIT_STR_INIT; + + if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass) + cl_skip(); g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb; From 38b60fd062c245b2efbb5079f1a2c868c915207d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 2 Aug 2023 11:02:44 +0100 Subject: [PATCH 249/816] winhttp: use new http-style url parser for proxies --- src/libgit2/transports/winhttp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index b7ffb9512ae..ae572c56d8e 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -443,7 +443,7 @@ static int winhttp_stream_connect(winhttp_stream *s) git_net_url_dispose(&t->proxy.url); - if ((error = git_net_url_parse(&t->proxy.url, proxy_url)) < 0) + if ((error = git_net_url_parse_http(&t->proxy.url, proxy_url)) < 0) goto on_error; if (!git_net_url_valid(&t->proxy.url)) { From 52db5d11c5f22e6109e0b7cb9ffba1e79f34382b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 10 Aug 2023 09:52:04 +0100 Subject: [PATCH 250/816] Revert "CMake: Search for ssh2 instead of libssh2." --- cmake/SelectSSH.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/SelectSSH.cmake b/cmake/SelectSSH.cmake index 968a63114f3..23dfc978521 100644 --- a/cmake/SelectSSH.cmake +++ b/cmake/SelectSSH.cmake @@ -1,6 +1,6 @@ # Optional external dependency: libssh2 if(USE_SSH) - find_pkglibraries(LIBSSH2 ssh2) + find_pkglibraries(LIBSSH2 libssh2) if(NOT LIBSSH2_FOUND) find_package(LibSSH2) set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR}) From 7f098da4597a95c5754637388bb57da67f794a4e Mon Sep 17 00:00:00 2001 From: Laurence McGlashan Date: Mon, 14 Aug 2023 16:11:32 +0100 Subject: [PATCH 251/816] README.md: Fix link to conan packages --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 711e848e0a5..3ed33df55f2 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ But if you _do_ want to use libgit2 directly - because you're building an application in C - then you may be able use an existing binary. There are packages for the [vcpkg](https://github.com/Microsoft/vcpkg) and -[conan](https://conan.io/center/libgit2) +[conan](https://conan.io/center/recipes/libgit2) package managers. And libgit2 is available in [Homebrew](https://formulae.brew.sh/formula/libgit2) and most Linux distributions. From 86872834c5fc40b78e4881255fad5b11bc866fd4 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sat, 19 Aug 2023 10:44:25 +0200 Subject: [PATCH 252/816] cmake: fix openssl build on win32 since f15c8ac71a916b libgit unconditionally depends on secur32 on Windows but only added it in cmake for the winhttp and schannel variants. In case libgit is built against openssl it would fail to link. This moves secur32 out of the https backend selection code into the global win32 condition (and while at it also adds ws2_32 to the .pc file) --- cmake/SelectHTTPSBackend.cmake | 8 ++++---- src/CMakeLists.txt | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index d14941643dc..0b3d63a790c 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -109,8 +109,8 @@ if(USE_HTTPS) elseif(USE_HTTPS STREQUAL "Schannel") set(GIT_SCHANNEL 1) - list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32" "secur32") - list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32" "-lsecur32") + list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") + list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") elseif(USE_HTTPS STREQUAL "WinHTTP") set(GIT_WINHTTP 1) @@ -125,8 +125,8 @@ if(USE_HTTPS) list(APPEND LIBGIT2_PC_LIBS "-lwinhttp") endif() - list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32" "secur32") - list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32" "-lsecur32") + list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") + list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") set(GIT_OPENSSL 1) set(GIT_OPENSSL_DYNAMIC 1) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8525acdd803..b412452c916 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -135,7 +135,8 @@ endif() # platform libraries if(WIN32) - list(APPEND LIBGIT2_SYSTEM_LIBS ws2_32) + list(APPEND LIBGIT2_SYSTEM_LIBS "ws2_32" "secur32") + list(APPEND LIBGIT2_PC_LIBS "-lws2_32" "-lsecur32") endif() if(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") From 2a99bc7b07544c289cb47028bbec24167bf1a17e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 23 Aug 2023 11:00:25 +0100 Subject: [PATCH 253/816] ci: retry flaky online tests --- ci/test.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ci/test.sh b/ci/test.sh index ee6801a79a2..30cd162dd95 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -78,6 +78,8 @@ run_test() { echo "" echo "Re-running flaky ${1} tests..." echo "" + + sleep 2 fi RETURN_CODE=0 @@ -269,11 +271,16 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then echo "## Running networking (online) tests" echo "##############################################################################" + # the online tests can fail due to network connectivity problems; + # allow them to retry up to 5 times + export GITTEST_FLAKY_RETRY=5 + export GITTEST_REMOTE_REDIRECT_INITIAL="http://localhost:9000/initial-redirect/libgit2/TestGitRepository" export GITTEST_REMOTE_REDIRECT_SUBSEQUENT="http://localhost:9000/subsequent-redirect/libgit2/TestGitRepository" export GITTEST_REMOTE_SPEED_SLOW="http://localhost:9000/speed-9600/test.git" export GITTEST_REMOTE_SPEED_TIMESOUT="http://localhost:9000/speed-0.5/test.git" run_test online + unset GITTEST_FLAKY_RETRY unset GITTEST_REMOTE_REDIRECT_INITIAL unset GITTEST_REMOTE_REDIRECT_SUBSEQUENT unset GITTEST_REMOTE_SPEED_SLOW From 1fc9cd52923c531252dca0fc1b5da4bcff3b512f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 23 Aug 2023 13:50:16 +0100 Subject: [PATCH 254/816] ci: retry (more) flaky online tests --- ci/test.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index 30cd162dd95..e5331362436 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -261,6 +261,10 @@ if [ -n "$RUN_INVASIVE_TESTS" ]; then unset GITTEST_INVASIVE_SPEED fi +# the various network tests can fail due to network connectivity problems; +# allow them to retry up to 5 times +export GITTEST_FLAKY_RETRY=5 + if [ -z "$SKIP_ONLINE_TESTS" ]; then # Run the online tests. The "online" test suite only includes the # default online tests that do not require additional configuration. @@ -271,16 +275,11 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then echo "## Running networking (online) tests" echo "##############################################################################" - # the online tests can fail due to network connectivity problems; - # allow them to retry up to 5 times - export GITTEST_FLAKY_RETRY=5 - export GITTEST_REMOTE_REDIRECT_INITIAL="http://localhost:9000/initial-redirect/libgit2/TestGitRepository" export GITTEST_REMOTE_REDIRECT_SUBSEQUENT="http://localhost:9000/subsequent-redirect/libgit2/TestGitRepository" export GITTEST_REMOTE_SPEED_SLOW="http://localhost:9000/speed-9600/test.git" export GITTEST_REMOTE_SPEED_TIMESOUT="http://localhost:9000/speed-0.5/test.git" run_test online - unset GITTEST_FLAKY_RETRY unset GITTEST_REMOTE_REDIRECT_INITIAL unset GITTEST_REMOTE_REDIRECT_SUBSEQUENT unset GITTEST_REMOTE_SPEED_SLOW @@ -438,6 +437,8 @@ if [ -z "$SKIP_SSH_TESTS" ]; then unset GITTEST_REMOTE_SSH_FINGERPRINT fi +unset GITTEST_FLAKY_RETRY + if [ -z "$SKIP_FUZZERS" ]; then echo "" echo "##############################################################################" From 14fa2ad70326e63729949260a4055b8ca4215477 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 25 Aug 2023 13:12:07 +0100 Subject: [PATCH 255/816] Update macOS build image to macos-12 --- .github/workflows/benchmark.yml | 2 +- .github/workflows/main.yml | 4 ++-- .github/workflows/nightly.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index bf2167464ec..f6d3a616afa 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -27,7 +27,7 @@ jobs: os: ubuntu-latest setup-script: ubuntu - name: "macOS" - os: macos-11 + os: macos-12 env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d84ded05ffd..84d476f78dc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,7 +63,7 @@ jobs: os: ubuntu-latest - name: "macOS" id: macos - os: macos-11 + os: macos-12 env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON @@ -177,7 +177,7 @@ jobs: os: ubuntu-latest - name: "macOS (SHA256)" id: macos - os: macos-11 + os: macos-12 env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 18328a7841d..fa7ef715fca 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -154,7 +154,7 @@ jobs: SKIP_SSH_TESTS: true os: ubuntu-latest - name: "macOS" - os: macos-11 + os: macos-12 env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON @@ -294,7 +294,7 @@ jobs: os: ubuntu-latest - name: "macOS (SHA256)" id: macos - os: macos-10.15 + os: macos-12 env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON From 0181b4cb82016d4f29d130205382cd35f13fedad Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 22 Apr 2023 14:04:09 +0100 Subject: [PATCH 256/816] Introduce `git_strlist` to manage string lists --- src/util/strlist.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/strlist.h | 20 ++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/util/strlist.c b/src/util/strlist.c index af9b4bbd34d..df5640c2a1f 100644 --- a/src/util/strlist.c +++ b/src/util/strlist.c @@ -28,6 +28,59 @@ int git_strlist_copy(char ***out, const char **in, size_t len) return 0; } +int git_strlist_copy_with_null(char ***out, const char **in, size_t len) +{ + char **dup; + size_t new_len, i; + + GIT_ERROR_CHECK_ALLOC_ADD(&new_len, len, 1); + + dup = git__calloc(new_len, sizeof(char *)); + GIT_ERROR_CHECK_ALLOC(dup); + + for (i = 0; i < len; i++) { + dup[i] = git__strdup(in[i]); + GIT_ERROR_CHECK_ALLOC(dup[i]); + } + + *out = dup; + return 0; +} + +bool git_strlist_contains_prefix( + const char **strings, + size_t len, + const char *str, + size_t n) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (strncmp(strings[i], str, n) == 0) + return true; + } + + return false; +} + +bool git_strlist_contains_key( + const char **strings, + size_t len, + const char *key, + char delimiter) +{ + const char *c; + + for (c = key; *c; c++) { + if (*c == delimiter) + break; + } + + return *c ? + git_strlist_contains_prefix(strings, len, key, (c - key)) : + false; +} + void git_strlist_free(char **strings, size_t len) { size_t i; @@ -40,3 +93,16 @@ void git_strlist_free(char **strings, size_t len) git__free(strings); } + +void git_strlist_free_with_null(char **strings) +{ + char **s; + + if (!strings) + return; + + for (s = strings; *s; s++) + git__free(*s); + + git__free(strings); +} diff --git a/src/util/strlist.h b/src/util/strlist.h index 089a8bb57b3..68fbf8fb263 100644 --- a/src/util/strlist.h +++ b/src/util/strlist.h @@ -11,6 +11,26 @@ #include "git2_util.h" extern int git_strlist_copy(char ***out, const char **in, size_t len); + +extern int git_strlist_copy_with_null( + char ***out, + const char **in, + size_t len); + +extern bool git_strlist_contains_prefix( + const char **strings, + size_t len, + const char *str, + size_t n); + +extern bool git_strlist_contains_key( + const char **strings, + size_t len, + const char *key, + char delimiter); + extern void git_strlist_free(char **strings, size_t len); +extern void git_strlist_free_with_null(char **strings); + #endif From bc97d01c039f004a05a5457bace11f3c3e26beb5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 15 Feb 2023 21:25:19 +0000 Subject: [PATCH 257/816] Introduce git_process class that invokes processes --- src/util/process.h | 156 ++++++++ src/util/unix/process.c | 499 ++++++++++++++++++++++++++ src/util/win32/process.c | 460 ++++++++++++++++++++++++ tests/resources/process/cat.bat | 2 + tests/resources/process/env.cmd | 2 + tests/resources/process/helloworld.sh | 3 + tests/resources/process/pwd.bat | 2 + tests/util/process/env.c | 111 ++++++ tests/util/process/start.c | 212 +++++++++++ tests/util/process/win32.c | 61 ++++ 10 files changed, 1508 insertions(+) create mode 100644 src/util/process.h create mode 100644 src/util/unix/process.c create mode 100644 src/util/win32/process.c create mode 100644 tests/resources/process/cat.bat create mode 100644 tests/resources/process/env.cmd create mode 100755 tests/resources/process/helloworld.sh create mode 100644 tests/resources/process/pwd.bat create mode 100644 tests/util/process/env.c create mode 100644 tests/util/process/start.c create mode 100644 tests/util/process/win32.c diff --git a/src/util/process.h b/src/util/process.h new file mode 100644 index 00000000000..55b2a104934 --- /dev/null +++ b/src/util/process.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_process_h__ +#define INCLUDE_process_h__ + +typedef struct git_process git_process; + +typedef struct { + int capture_in : 1, + capture_out : 1, + capture_err : 1, + exclude_env : 1; + + char *cwd; +} git_process_options; + +typedef enum { + GIT_PROCESS_STATUS_NONE, + GIT_PROCESS_STATUS_NORMAL, + GIT_PROCESS_STATUS_ERROR +} git_process_result_status; + +#define GIT_PROCESS_RESULT_INIT { GIT_PROCESS_STATUS_NONE } + +typedef struct { + git_process_result_status status; + int exitcode; + int signal; +} git_process_result; + +#define GIT_PROCESS_OPTIONS_INIT { 0 } + +/** + * Create a new process. The command to run should be specified as the + * element of the `arg` array. + * + * This function will add the given environment variables (in `env`) + * to the current environment. Operations on environment variables + * are not thread safe, so you may not modify the environment during + * this call. You can avoid this by setting `exclude_env` in the + * options and providing the entire environment yourself. + * + * @param out location to store the process + * @param args the command (with arguments) to run + * @param args_len the length of the args array + * @param env environment variables to add (or NULL) + * @param env_len the length of the env len + * @param opts the options for creating the process + * @return 0 or an error code + */ +extern int git_process_new( + git_process **out, + const char **args, + size_t args_len, + const char **env, + size_t env_len, + git_process_options *opts); + +#ifdef GIT_WIN32 + +/* Windows path parsing is tricky; this helper function is for testing. */ +extern int git_process__cmdline( + git_str *out, + const char **in, + size_t in_len); + +#endif + +/** + * Start the process. + * + * @param process the process to start + * @return 0 or an error code + */ +extern int git_process_start(git_process *process); + +/** + * Read from the process's stdout. The process must have been created with + * `capture_out` set to true. + * + * @param process the process to read from + * @param buf the buf to read into + * @param count maximum number of bytes to read + * @return number of bytes read or an error code + */ +extern ssize_t git_process_read(git_process *process, void *buf, size_t count); + +/** + * Write to the process's stdin. The process must have been created with + * `capture_in` set to true. + * + * @param process the process to write to + * @param buf the buf to write + * @param count maximum number of bytes to write + * @return number of bytes written or an error code + */ +extern ssize_t git_process_write(git_process *process, const void *buf, size_t count); + +/** + * Wait for the process to finish. + * + * @param result the result of the process or NULL + * @param process the process to wait on + */ +extern int git_process_wait(git_process_result *result, git_process *process); + +/** + * Close the input pipe from the child. + * + * @param process the process to close the pipe on + */ +extern int git_process_close_in(git_process *process); + +/** + * Close the output pipe from the child. + * + * @param process the process to close the pipe on + */ +extern int git_process_close_out(git_process *process); + +/** + * Close the error pipe from the child. + * + * @param process the process to close the pipe on + */ +extern int git_process_close_err(git_process *process); + +/** + * Close all resources that are used by the process. This does not + * wait for the process to complete. + * + * @parma process the process to close + */ +extern int git_process_close(git_process *process); + +/** + * Place a human-readable error message in the given git buffer. + * + * @param msg the buffer to store the message + * @param result the process result that produced an error + */ +extern int git_process_result_msg(git_str *msg, git_process_result *result); + +/** + * Free a process structure + * + * @param process the process to free + */ +extern void git_process_free(git_process *process); + +#endif diff --git a/src/util/unix/process.c b/src/util/unix/process.c new file mode 100644 index 00000000000..16171aec94c --- /dev/null +++ b/src/util/unix/process.c @@ -0,0 +1,499 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include + +#include "git2_util.h" +#include "vector.h" +#include "process.h" +#include "strlist.h" + +extern char **environ; + +struct git_process { + char **args; + char **env; + + char *cwd; + + unsigned int capture_in : 1, + capture_out : 1, + capture_err : 1; + + pid_t pid; + + int child_in; + int child_out; + int child_err; + git_process_result_status status; +}; + +GIT_INLINE(bool) is_delete_env(const char *env) +{ + char *c = index(env, '='); + + if (c == NULL) + return false; + + return *(c+1) == '\0'; +} + +static int merge_env( + char ***out, + const char **env, + size_t env_len, + bool exclude_env) +{ + git_vector merged = GIT_VECTOR_INIT; + char **kv, *dup; + size_t max, cnt; + int error = 0; + + for (max = env_len, kv = environ; !exclude_env && *kv; kv++) + max++; + + if ((error = git_vector_init(&merged, max, NULL)) < 0) + goto on_error; + + for (cnt = 0; env && cnt < env_len; cnt++) { + if (is_delete_env(env[cnt])) + continue; + + dup = git__strdup(env[cnt]); + GIT_ERROR_CHECK_ALLOC(dup); + + if ((error = git_vector_insert(&merged, dup)) < 0) + goto on_error; + } + + if (!exclude_env) { + for (kv = environ; *kv; kv++) { + if (env && git_strlist_contains_key(env, env_len, *kv, '=')) + continue; + + dup = git__strdup(*kv); + GIT_ERROR_CHECK_ALLOC(dup); + + if ((error = git_vector_insert(&merged, dup)) < 0) + goto on_error; + } + } + + if (merged.length == 0) { + *out = NULL; + error = 0; + goto on_error; + } + + git_vector_insert(&merged, NULL); + + *out = (char **)merged.contents; + + return 0; + +on_error: + git_vector_free_deep(&merged); + return error; +} + +int git_process_new( + git_process **out, + const char **args, + size_t args_len, + const char **env, + size_t env_len, + git_process_options *opts) +{ + git_process *process; + + GIT_ASSERT_ARG(out && args && args_len > 0); + + *out = NULL; + + process = git__calloc(sizeof(git_process), 1); + GIT_ERROR_CHECK_ALLOC(process); + + if (git_strlist_copy_with_null(&process->args, args, args_len) < 0 || + merge_env(&process->env, env, env_len, opts->exclude_env) < 0) { + git_process_free(process); + return -1; + } + + if (opts) { + process->capture_in = opts->capture_in; + process->capture_out = opts->capture_out; + process->capture_err = opts->capture_err; + + if (opts->cwd) { + process->cwd = git__strdup(opts->cwd); + GIT_ERROR_CHECK_ALLOC(process->cwd); + } + } + + process->child_in = -1; + process->child_out = -1; + process->child_err = -1; + process->status = -1; + + *out = process; + return 0; +} + +#define CLOSE_FD(fd) \ + if (fd >= 0) { \ + close(fd); \ + fd = -1; \ + } + +static int try_read(size_t *out, int fd, void *buf, size_t len) +{ + size_t read_len = 0; + int ret = -1; + + while (ret && read_len < len) { + ret = read(fd, buf + read_len, len - read_len); + + if (ret < 0 && errno != EAGAIN && errno != EINTR) { + git_error_set(GIT_ERROR_OS, "could not read child status"); + return -1; + } + + read_len += ret; + } + + *out = read_len; + return 0; +} + + +static int read_status(int fd) +{ + size_t status_len = sizeof(int) * 3, read_len = 0; + char buffer[status_len], fn[128]; + int error, fn_error, os_error, fn_len = 0; + + if ((error = try_read(&read_len, fd, buffer, status_len)) < 0) + return error; + + /* Immediate EOF indicates the exec succeeded. */ + if (read_len == 0) + return 0; + + if (read_len < status_len) { + git_error_set(GIT_ERROR_INVALID, "child status truncated"); + return -1; + } + + memcpy(&fn_error, &buffer[0], sizeof(int)); + memcpy(&os_error, &buffer[sizeof(int)], sizeof(int)); + memcpy(&fn_len, &buffer[sizeof(int) * 2], sizeof(int)); + + if (fn_len > 0) { + fn_len = min(fn_len, (int)(ARRAY_SIZE(fn) - 1)); + + if ((error = try_read(&read_len, fd, fn, fn_len)) < 0) + return error; + + fn[fn_len] = '\0'; + } else { + fn[0] = '\0'; + } + + if (fn_error) { + errno = os_error; + git_error_set(GIT_ERROR_OS, "could not %s", fn[0] ? fn : "(unknown)"); + } + + return fn_error; +} + +static bool try_write(int fd, const void *buf, size_t len) +{ + size_t write_len; + int ret; + + for (write_len = 0; write_len < len; ) { + ret = write(fd, buf + write_len, len - write_len); + + if (ret <= 0) + break; + + write_len += ret; + } + + return (len == write_len); +} + +static void write_status(int fd, const char *fn, int error, int os_error) +{ + size_t status_len = sizeof(int) * 3, fn_len; + char buffer[status_len]; + + fn_len = strlen(fn); + + if (fn_len > INT_MAX) + fn_len = INT_MAX; + + memcpy(&buffer[0], &error, sizeof(int)); + memcpy(&buffer[sizeof(int)], &os_error, sizeof(int)); + memcpy(&buffer[sizeof(int) * 2], &fn_len, sizeof(int)); + + /* Do our best effort to write all the status. */ + if (!try_write(fd, buffer, status_len)) + return; + + if (fn_len) + try_write(fd, fn, fn_len); +} + +int git_process_start(git_process *process) +{ + int in[2] = { -1, -1 }, out[2] = { -1, -1 }, + err[2] = { -1, -1 }, status[2] = { -1, -1 }; + int fdflags, state, error; + pid_t pid; + + /* Set up the pipes to read from/write to the process */ + if ((process->capture_in && pipe(in) < 0) || + (process->capture_out && pipe(out) < 0) || + (process->capture_err && pipe(err) < 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + /* Set up a self-pipe for status from the forked process. */ + if (pipe(status) < 0 || + (fdflags = fcntl(status[1], F_GETFD)) < 0 || + fcntl(status[1], F_SETFD, fdflags | FD_CLOEXEC) < 0) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + switch (pid = fork()) { + case -1: + git_error_set(GIT_ERROR_OS, "could not fork"); + goto on_error; + + /* Child: start the process. */ + case 0: + /* Close the opposing side of the pipes */ + CLOSE_FD(status[0]); + + if (process->capture_in) { + CLOSE_FD(in[1]); + dup2(in[0], STDIN_FILENO); + } + + if (process->capture_out) { + CLOSE_FD(out[0]); + dup2(out[1], STDOUT_FILENO); + } + + if (process->capture_err) { + CLOSE_FD(err[0]); + dup2(err[1], STDERR_FILENO); + } + + if (process->cwd && (error = chdir(process->cwd)) < 0) { + write_status(status[1], "chdir", error, errno); + exit(0); + } + + /* + * Exec the process and write the results back if the + * call fails. If it succeeds, we'll close the status + * pipe (via CLOEXEC) and the parent will know. + */ + error = execve(process->args[0], + process->args, + process->env); + + write_status(status[1], "execve", error, errno); + exit(0); + + /* Parent: make sure the child process exec'd correctly. */ + default: + /* Close the opposing side of the pipes */ + CLOSE_FD(status[1]); + + if (process->capture_in) { + CLOSE_FD(in[0]); + process->child_in = in[1]; + } + + if (process->capture_out) { + CLOSE_FD(out[1]); + process->child_out = out[0]; + } + + if (process->capture_err) { + CLOSE_FD(err[1]); + process->child_err = err[0]; + } + + /* Try to read the status */ + process->status = status[0]; + if ((error = read_status(status[0])) < 0) { + waitpid(process->pid, &state, 0); + goto on_error; + } + + process->pid = pid; + return 0; + } + +on_error: + CLOSE_FD(in[0]); CLOSE_FD(in[1]); + CLOSE_FD(out[0]); CLOSE_FD(out[1]); + CLOSE_FD(err[0]); CLOSE_FD(err[1]); + CLOSE_FD(status[0]); CLOSE_FD(status[1]); + return -1; +} + +ssize_t git_process_read(git_process *process, void *buf, size_t count) +{ + ssize_t ret; + + GIT_ASSERT_ARG(process); + GIT_ASSERT(process->capture_out); + + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if ((ret = read(process->child_out, buf, count)) < 0) { + git_error_set(GIT_ERROR_OS, "could not read from child process"); + return -1; + } + + return ret; +} + +ssize_t git_process_write(git_process *process, const void *buf, size_t count) +{ + ssize_t ret; + + GIT_ASSERT_ARG(process); + GIT_ASSERT(process->capture_in); + + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if ((ret = write(process->child_in, buf, count)) < 0) { + git_error_set(GIT_ERROR_OS, "could not write to child process"); + return -1; + } + + return ret; +} + +int git_process_close_in(git_process *process) +{ + if (!process->capture_in) { + git_error_set(GIT_ERROR_INVALID, "input is not open"); + return -1; + } + + CLOSE_FD(process->child_in); + return 0; +} + +int git_process_close_out(git_process *process) +{ + if (!process->capture_out) { + git_error_set(GIT_ERROR_INVALID, "output is not open"); + return -1; + } + + CLOSE_FD(process->child_out); + return 0; +} + +int git_process_close_err(git_process *process) +{ + if (!process->capture_err) { + git_error_set(GIT_ERROR_INVALID, "error is not open"); + return -1; + } + + CLOSE_FD(process->child_err); + return 0; +} + +int git_process_close(git_process *process) +{ + CLOSE_FD(process->child_in); + CLOSE_FD(process->child_out); + CLOSE_FD(process->child_err); + CLOSE_FD(process->status); + + return 0; +} + +int git_process_wait(git_process_result *result, git_process *process) +{ + int state; + + if (result) + memset(result, 0, sizeof(git_process_result)); + + if (!process->pid) { + git_error_set(GIT_ERROR_INVALID, "process is stopped"); + return -1; + } + + if (waitpid(process->pid, &state, 0) < 0) { + git_error_set(GIT_ERROR_OS, "could not wait for child"); + return -1; + } + + process->pid = 0; + + if (result) { + if (WIFEXITED(state)) { + result->status = GIT_PROCESS_STATUS_NORMAL; + result->exitcode = WEXITSTATUS(state); + } else if (WIFSIGNALED(state)) { + result->status = GIT_PROCESS_STATUS_ERROR; + result->signal = WTERMSIG(state); + } else { + result->status = GIT_PROCESS_STATUS_ERROR; + } + } + + return 0; +} + +int git_process_result_msg(git_str *out, git_process_result *result) +{ + if (result->status == GIT_PROCESS_STATUS_NONE) { + return git_str_puts(out, "process not started"); + } else if (result->status == GIT_PROCESS_STATUS_NORMAL) { + return git_str_printf(out, "process exited with code %d", + result->exitcode); + } else if (result->signal) { + return git_str_printf(out, "process exited on signal %d", + result->signal); + } + + return git_str_puts(out, "unknown error"); +} + +void git_process_free(git_process *process) +{ + if (!process) + return; + + if (process->pid) + git_process_close(process); + + git__free(process->cwd); + git_strlist_free_with_null(process->args); + git_strlist_free_with_null(process->env); + git__free(process); +} diff --git a/src/util/win32/process.c b/src/util/win32/process.c new file mode 100644 index 00000000000..6b8dd084015 --- /dev/null +++ b/src/util/win32/process.c @@ -0,0 +1,460 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include + +#include "git2_util.h" +#include "process.h" +#include "strlist.h" + +#ifndef DWORD_MAX +# define DWORD_MAX INT32_MAX +#endif + +#define ENV_MAX 32767 + +struct git_process { + wchar_t *appname; + wchar_t *cmdline; + wchar_t *env; + + wchar_t *cwd; + + unsigned int capture_in : 1, + capture_out : 1, + capture_err : 1; + + PROCESS_INFORMATION process_info; + + HANDLE child_in; + HANDLE child_out; + HANDLE child_err; + + git_process_result_status status; +}; + +/* + * Windows processes have a single command-line that is split by the + * invoked application into arguments (instead of an array of + * command-line arguments). This command-line is split by space or + * tab delimiters, unless that whitespace is within a double quote. + * Literal double-quotes themselves can be escaped by a backslash, + * but only when not within double quotes. Literal backslashes can + * be escaped by a backslash. + * + * Effectively, this means that instead of thinking about quoting + * individual strings, think about double quotes as an escaping + * mechanism for whitespace. + * + * In other words (using ` as a string boundary): + * [ `foo`, `bar` ] => `foo bar` + * [ `foo bar` ] => `foo" "bar` + * [ `foo bar`, `foo bar` ] => `foo" "bar foo" "bar` + * [ `foo "bar" foo` ] => `foo" "\"bar\"" "foo` + */ +int git_process__cmdline( + git_str *out, + const char **in, + size_t in_len) +{ + bool quoted = false; + const char *c; + size_t i; + + for (i = 0; i < in_len; i++) { + /* Arguments are delimited by an unquoted space */ + if (i) + git_str_putc(out, ' '); + + for (c = in[i]; *c; c++) { + /* Start or stop quoting spaces within an argument */ + if ((*c == ' ' || *c == '\t') && !quoted) { + git_str_putc(out, '"'); + quoted = true; + } else if (*c != ' ' && *c != '\t' && quoted) { + git_str_putc(out, '"'); + quoted = false; + } + + /* Escape double-quotes and backslashes */ + if (*c == '"' || *c == '\\') + git_str_putc(out, '\\'); + + git_str_putc(out, *c); + } + } + + return git_str_oom(out) ? -1 : 0; +} + +GIT_INLINE(bool) is_delete_env(const char *env) +{ + char *c = strchr(env, '='); + + if (c == NULL) + return false; + + return *(c+1) == '\0'; +} + +static int merge_env(wchar_t **out, const char **in, size_t in_len, bool exclude_env) +{ + git_str merged = GIT_STR_INIT; + wchar_t *in16 = NULL, *env = NULL, *e; + char *e8 = NULL; + size_t e_len; + int ret = 0; + size_t i; + + *out = NULL; + + in16 = git__malloc(ENV_MAX * sizeof(wchar_t)); + GIT_ERROR_CHECK_ALLOC(in16); + + e8 = git__malloc(ENV_MAX); + GIT_ERROR_CHECK_ALLOC(e8); + + for (i = 0; in && i < in_len; i++) { + if (is_delete_env(in[i])) + continue; + + if ((ret = git_utf8_to_16(in16, ENV_MAX, in[i])) < 0) + goto done; + + git_str_put(&merged, (const char *)in16, ret * 2); + git_str_put(&merged, "\0\0", 2); + } + + if (!exclude_env) { + env = GetEnvironmentStringsW(); + + for (e = env; *e; e += (e_len + 1)) { + e_len = wcslen(e); + + if ((ret = git_utf8_from_16(e8, ENV_MAX, e)) < 0) + goto done; + + if (git_strlist_contains_key(in, in_len, e8, '=')) + continue; + + git_str_put(&merged, (const char *)e, e_len * 2); + git_str_put(&merged, "\0\0", 2); + } + } + + git_str_put(&merged, "\0\0", 2); + + *out = (wchar_t *)git_str_detach(&merged); + +done: + if (env) + FreeEnvironmentStringsW(env); + + git_str_dispose(&merged); + git__free(e8); + git__free(in16); + + return ret < 0 ? -1 : 0; +} + +int git_process_new( + git_process **out, + const char **args, + size_t args_len, + const char **env, + size_t env_len, + git_process_options *opts) +{ + git_process *process; + git_str cmdline = GIT_STR_INIT; + int error; + + GIT_ASSERT_ARG(out && args && args_len > 0); + + *out = NULL; + + process = git__calloc(1, sizeof(git_process)); + GIT_ERROR_CHECK_ALLOC(process); + + if ((error = git_process__cmdline(&cmdline, args, args_len)) < 0) + goto done; + + if (git_utf8_to_16_alloc(&process->appname, args[0]) < 0 || + git_utf8_to_16_alloc(&process->cmdline, cmdline.ptr) < 0) { + error = -1; + goto done; + } + + if (opts && opts->cwd && + git_utf8_to_16_alloc(&process->cwd, opts->cwd) < 0) { + error = -1; + goto done; + } + + if (env && (error = merge_env(&process->env, env, env_len, opts && opts->exclude_env) < 0)) + goto done; + + if (opts) { + process->capture_in = opts->capture_in; + process->capture_out = opts->capture_out; + process->capture_err = opts->capture_err; + } + +done: + if (error) + git_process_free(process); + else + *out = process; + + git_str_dispose(&cmdline); + return error; +} + +#define CLOSE_HANDLE(h) do { if ((h) != NULL) CloseHandle(h); } while(0) + +int git_process_start(git_process *process) +{ + STARTUPINFOW startup_info; + SECURITY_ATTRIBUTES security_attrs; + DWORD flags = CREATE_UNICODE_ENVIRONMENT; + HANDLE in[2] = { NULL, NULL }, + out[2] = { NULL, NULL }, + err[2] = { NULL, NULL }; + + memset(&security_attrs, 0, sizeof(SECURITY_ATTRIBUTES)); + security_attrs.bInheritHandle = TRUE; + + memset(&startup_info, 0, sizeof(STARTUPINFOW)); + startup_info.cb = sizeof(STARTUPINFOW); + startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + if (process->capture_in) { + if (!CreatePipe(&in[0], &in[1], &security_attrs, 0) || + !SetHandleInformation(in[1], HANDLE_FLAG_INHERIT, 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + startup_info.hStdInput = in[0]; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + } + + if (process->capture_out) { + if (!CreatePipe(&out[0], &out[1], &security_attrs, 0) || + !SetHandleInformation(out[0], HANDLE_FLAG_INHERIT, 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + startup_info.hStdOutput = out[1]; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + } + + if (process->capture_err) { + if (!CreatePipe(&err[0], &err[1], &security_attrs, 0) || + !SetHandleInformation(err[0], HANDLE_FLAG_INHERIT, 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + startup_info.hStdError = err[1]; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + } + + memset(&process->process_info, 0, sizeof(PROCESS_INFORMATION)); + + if (!CreateProcessW(process->appname, process->cmdline, + NULL, NULL, TRUE, flags, process->env, + process->cwd, + &startup_info, + &process->process_info)) { + git_error_set(GIT_ERROR_OS, "could not create process"); + goto on_error; + } + + CLOSE_HANDLE(in[0]); process->child_in = in[1]; + CLOSE_HANDLE(out[1]); process->child_out = out[0]; + CLOSE_HANDLE(err[1]); process->child_err = err[0]; + + return 0; + +on_error: + CLOSE_HANDLE(in[0]); CLOSE_HANDLE(in[1]); + CLOSE_HANDLE(out[0]); CLOSE_HANDLE(out[1]); + CLOSE_HANDLE(err[0]); CLOSE_HANDLE(err[1]); + return -1; +} + +ssize_t git_process_read(git_process *process, void *buf, size_t count) +{ + DWORD ret; + + if (count > DWORD_MAX) + count = DWORD_MAX; + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if (!ReadFile(process->child_out, buf, (DWORD)count, &ret, NULL)) { + if (GetLastError() == ERROR_BROKEN_PIPE) + return 0; + + git_error_set(GIT_ERROR_OS, "could not read"); + return -1; + } + + return ret; +} + +ssize_t git_process_write(git_process *process, const void *buf, size_t count) +{ + DWORD ret; + + if (count > DWORD_MAX) + count = DWORD_MAX; + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if (!WriteFile(process->child_in, buf, (DWORD)count, &ret, NULL)) { + git_error_set(GIT_ERROR_OS, "could not write"); + return -1; + } + + return ret; +} + +int git_process_close_in(git_process *process) +{ + if (!process->capture_in) { + git_error_set(GIT_ERROR_INVALID, "input is not open"); + return -1; + } + + if (process->child_in) { + CloseHandle(process->child_in); + process->child_in = NULL; + } + + return 0; +} + +int git_process_close_out(git_process *process) +{ + if (!process->capture_out) { + git_error_set(GIT_ERROR_INVALID, "output is not open"); + return -1; + } + + if (process->child_out) { + CloseHandle(process->child_out); + process->child_out = NULL; + } + + return 0; +} + +int git_process_close_err(git_process *process) +{ + if (!process->capture_err) { + git_error_set(GIT_ERROR_INVALID, "error is not open"); + return -1; + } + + if (process->child_err) { + CloseHandle(process->child_err); + process->child_err = NULL; + } + + return 0; +} + +int git_process_close(git_process *process) +{ + if (process->child_in) { + CloseHandle(process->child_in); + process->child_in = NULL; + } + + if (process->child_out) { + CloseHandle(process->child_out); + process->child_out = NULL; + } + + if (process->child_err) { + CloseHandle(process->child_err); + process->child_err = NULL; + } + + CloseHandle(process->process_info.hProcess); + process->process_info.hProcess = NULL; + + CloseHandle(process->process_info.hThread); + process->process_info.hThread = NULL; + + return 0; +} + +int git_process_wait(git_process_result *result, git_process *process) +{ + DWORD exitcode; + + if (result) + memset(result, 0, sizeof(git_process_result)); + + if (!process->process_info.dwProcessId) { + git_error_set(GIT_ERROR_INVALID, "process is stopped"); + return -1; + } + + if (WaitForSingleObject(process->process_info.hProcess, INFINITE) == WAIT_FAILED) { + git_error_set(GIT_ERROR_OS, "could not wait for process"); + return -1; + } + + if (!GetExitCodeProcess(process->process_info.hProcess, &exitcode)) { + git_error_set(GIT_ERROR_OS, "could not get process exit code"); + return -1; + } + + result->status = GIT_PROCESS_STATUS_NORMAL; + result->exitcode = exitcode; + + memset(&process->process_info, 0, sizeof(PROCESS_INFORMATION)); + return 0; +} + +int git_process_result_msg(git_str *out, git_process_result *result) +{ + if (result->status == GIT_PROCESS_STATUS_NONE) { + return git_str_puts(out, "process not started"); + } else if (result->status == GIT_PROCESS_STATUS_NORMAL) { + return git_str_printf(out, "process exited with code %d", + result->exitcode); + } else if (result->signal) { + return git_str_printf(out, "process exited on signal %d", + result->signal); + } + + return git_str_puts(out, "unknown error"); +} + +void git_process_free(git_process *process) +{ + if (!process) + return; + + if (process->process_info.hProcess) + git_process_close(process); + + git__free(process->env); + git__free(process->cwd); + git__free(process->cmdline); + git__free(process->appname); + git__free(process); +} diff --git a/tests/resources/process/cat.bat b/tests/resources/process/cat.bat new file mode 100644 index 00000000000..af9b573c793 --- /dev/null +++ b/tests/resources/process/cat.bat @@ -0,0 +1,2 @@ +@ECHO OFF +FOR /F "tokens=*" %%a IN ('more') DO ECHO %%a diff --git a/tests/resources/process/env.cmd b/tests/resources/process/env.cmd new file mode 100644 index 00000000000..62675cf9edd --- /dev/null +++ b/tests/resources/process/env.cmd @@ -0,0 +1,2 @@ +@ECHO OFF +SET diff --git a/tests/resources/process/helloworld.sh b/tests/resources/process/helloworld.sh new file mode 100755 index 00000000000..0c4aefc384d --- /dev/null +++ b/tests/resources/process/helloworld.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Hello, world." diff --git a/tests/resources/process/pwd.bat b/tests/resources/process/pwd.bat new file mode 100644 index 00000000000..82e4fb60f17 --- /dev/null +++ b/tests/resources/process/pwd.bat @@ -0,0 +1,2 @@ +@ECHO OFF +ECHO %CD% diff --git a/tests/util/process/env.c b/tests/util/process/env.c new file mode 100644 index 00000000000..bb7dbcdcdfd --- /dev/null +++ b/tests/util/process/env.c @@ -0,0 +1,111 @@ +#include "clar_libgit2.h" +#include "process.h" +#include "vector.h" + +static git_str env_cmd = GIT_STR_INIT; +static git_str accumulator = GIT_STR_INIT; +static git_vector env_result = GIT_VECTOR_INIT; + +void test_process_env__initialize(void) +{ +#ifdef GIT_WIN32 + git_str_printf(&env_cmd, "%s/env.cmd", cl_fixture("process")); +#else + git_str_puts(&env_cmd, "/usr/bin/env"); +#endif + + cl_git_pass(git_vector_init(&env_result, 32, git__strcmp_cb)); +} + +void test_process_env__cleanup(void) +{ + git_vector_free(&env_result); + git_str_dispose(&accumulator); + git_str_dispose(&env_cmd); +} + +static void run_env(const char **env_array, size_t env_len, bool exclude_env) +{ + const char *args_array[] = { env_cmd.ptr }; + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + git_process_result result = GIT_PROCESS_RESULT_INIT; + + char buf[1024], *tok; + ssize_t ret; + + opts.capture_out = 1; + opts.exclude_env = exclude_env; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), env_array, env_len, &opts)); + cl_git_pass(git_process_start(process)); + + while ((ret = git_process_read(process, buf, 1024)) > 0) + cl_git_pass(git_str_put(&accumulator, buf, (size_t)ret)); + + cl_assert_equal_i(0, ret); + + cl_git_pass(git_process_wait(&result, process)); + + cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status); + cl_assert_equal_i(0, result.exitcode); + cl_assert_equal_i(0, result.signal); + + for (tok = strtok(accumulator.ptr, "\n"); tok; tok = strtok(NULL, "\n")) { +#ifdef GIT_WIN32 + if (strlen(tok) && tok[strlen(tok) - 1] == '\r') + tok[strlen(tok) - 1] = '\0'; +#endif + + cl_git_pass(git_vector_insert(&env_result, tok)); + } + + git_process_close(process); + git_process_free(process); +} + +void test_process_env__can_add_env(void) +{ + const char *env_array[] = { "TEST_NEW_ENV=added", "TEST_OTHER_ENV=also_added" }; + run_env(env_array, 2, false); + + cl_git_pass(git_vector_search(NULL, &env_result, "TEST_NEW_ENV=added")); + cl_git_pass(git_vector_search(NULL, &env_result, "TEST_OTHER_ENV=also_added")); +} + +void test_process_env__can_propagate_env(void) +{ + cl_setenv("TEST_NEW_ENV", "propagated"); + run_env(NULL, 0, false); + + cl_git_pass(git_vector_search(NULL, &env_result, "TEST_NEW_ENV=propagated")); +} + +void test_process_env__can_remove_env(void) +{ + const char *env_array[] = { "TEST_NEW_ENV=" }; + char *str; + size_t i; + + cl_setenv("TEST_NEW_ENV", "propagated"); + run_env(env_array, 1, false); + + git_vector_foreach(&env_result, i, str) + cl_assert(git__prefixcmp(str, "TEST_NEW_ENV=") != 0); +} + +void test_process_env__can_clear_env(void) +{ + const char *env_array[] = { "TEST_NEW_ENV=added", "TEST_OTHER_ENV=also_added" }; + + cl_setenv("SOME_EXISTING_ENV", "propagated"); + run_env(env_array, 2, true); + + /* + * We can't simply test that the environment is precisely what we + * provided. Some systems (eg win32) will add environment variables + * to all processes. + */ + cl_assert_equal_i(GIT_ENOTFOUND, git_vector_search(NULL, &env_result, "SOME_EXISTING_ENV=propagated")); +} diff --git a/tests/util/process/start.c b/tests/util/process/start.c new file mode 100644 index 00000000000..0e4944b6567 --- /dev/null +++ b/tests/util/process/start.c @@ -0,0 +1,212 @@ +#include "clar_libgit2.h" +#include "process.h" +#include "vector.h" + +#ifndef SIGPIPE +# define SIGPIPE 42 +#endif + +static git_str helloworld_cmd = GIT_STR_INIT; +static git_str cat_cmd = GIT_STR_INIT; +static git_str pwd_cmd = GIT_STR_INIT; + +void test_process_start__initialize(void) +{ +#ifdef GIT_WIN32 + git_str_printf(&helloworld_cmd, "%s/helloworld.bat", cl_fixture("process")); + git_str_printf(&cat_cmd, "%s/cat.bat", cl_fixture("process")); + git_str_printf(&pwd_cmd, "%s/pwd.bat", cl_fixture("process")); +#else + git_str_printf(&helloworld_cmd, "%s/helloworld.sh", cl_fixture("process")); +#endif +} + +void test_process_start__cleanup(void) +{ + git_str_dispose(&pwd_cmd); + git_str_dispose(&cat_cmd); + git_str_dispose(&helloworld_cmd); +} + +void test_process_start__returncode(void) +{ +#ifdef GIT_WIN32 + const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", "exit", "1" }; +#elif __APPLE__ + const char *args_array[] = { "/usr/bin/false" }; +#else + const char *args_array[] = { "/bin/false" }; +#endif + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + git_process_result result = GIT_PROCESS_RESULT_INIT; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts)); + cl_git_pass(git_process_start(process)); + cl_git_pass(git_process_wait(&result, process)); + + cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status); + cl_assert_equal_i(1, result.exitcode); + cl_assert_equal_i(0, result.signal); + + git_process_free(process); +} + +void test_process_start__not_found(void) +{ +#ifdef GIT_WIN32 + const char *args_array[] = { "C:\\a\\b\\z\\y\\not_found" }; +#else + const char *args_array[] = { "/a/b/z/y/not_found" }; +#endif + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts)); + cl_git_fail(git_process_start(process)); + git_process_free(process); +} + +static void write_all(git_process *process, char *buf) +{ + size_t buf_len = strlen(buf); + ssize_t ret; + + while (buf_len) { + ret = git_process_write(process, buf, buf_len); + cl_git_pass(ret < 0 ? (int)ret : 0); + + buf += ret; + buf_len -= ret; + } +} + +static void read_all(git_str *out, git_process *process) +{ + char buf[32]; + size_t buf_len = 32; + ssize_t ret; + + while ((ret = git_process_read(process, buf, buf_len)) > 0) + cl_git_pass(git_str_put(out, buf, ret)); + + cl_git_pass(ret < 0 ? (int)ret : 0); +} + +void test_process_start__redirect_stdio(void) +{ +#ifdef GIT_WIN32 + const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", cat_cmd.ptr }; +#else + const char *args_array[] = { "/bin/cat" }; +#endif + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + git_process_result result = GIT_PROCESS_RESULT_INIT; + git_str buf = GIT_STR_INIT; + + opts.capture_in = 1; + opts.capture_out = 1; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts)); + cl_git_pass(git_process_start(process)); + + write_all(process, "Hello, world.\r\nHello!\r\n"); + cl_git_pass(git_process_close_in(process)); + + read_all(&buf, process); + cl_assert_equal_s("Hello, world.\r\nHello!\r\n", buf.ptr); + + cl_git_pass(git_process_wait(&result, process)); + + cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status); + cl_assert_equal_i(0, result.exitcode); + cl_assert_equal_i(0, result.signal); + + git_str_dispose(&buf); + git_process_free(process); +} + +void test_process_start__catch_signal(void) +{ +#ifndef GIT_WIN32 + const char *args_array[] = { helloworld_cmd.ptr }; + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + git_process_result result = GIT_PROCESS_RESULT_INIT; + + opts.capture_out = 1; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts)); + cl_git_pass(git_process_start(process)); + cl_git_pass(git_process_close(process)); + cl_git_pass(git_process_wait(&result, process)); + + cl_assert_equal_i(GIT_PROCESS_STATUS_ERROR, result.status); + cl_assert_equal_i(0, result.exitcode); + cl_assert_equal_i(SIGPIPE, result.signal); + + git_process_free(process); +#endif +} + +void test_process_start__can_chdir(void) +{ +#ifdef GIT_WIN32 + const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", pwd_cmd.ptr }; + char *startwd = "C:\\"; +#else + const char *args_array[] = { "/bin/pwd" }; + char *startwd = "/"; +#endif + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + git_process_result result = GIT_PROCESS_RESULT_INIT; + git_str buf = GIT_STR_INIT; + + opts.cwd = startwd; + opts.capture_out = 1; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts)); + cl_git_pass(git_process_start(process)); + + read_all(&buf, process); + git_str_rtrim(&buf); + + cl_assert_equal_s(startwd, buf.ptr); + + cl_git_pass(git_process_wait(&result, process)); + + cl_assert_equal_i(GIT_PROCESS_STATUS_NORMAL, result.status); + cl_assert_equal_i(0, result.exitcode); + cl_assert_equal_i(0, result.signal); + + git_str_dispose(&buf); + git_process_free(process); +} + +void test_process_start__cannot_chdir_to_nonexistent_dir(void) +{ +#ifdef GIT_WIN32 + const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", pwd_cmd.ptr }; + char *startwd = "C:\\a\\b\\z\\y\\not_found"; +#else + const char *args_array[] = { "/bin/pwd" }; + char *startwd = "/a/b/z/y/not_found"; +#endif + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + + opts.cwd = startwd; + opts.capture_out = 1; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts)); + cl_git_fail(git_process_start(process)); + git_process_free(process); +} diff --git a/tests/util/process/win32.c b/tests/util/process/win32.c new file mode 100644 index 00000000000..914504d6263 --- /dev/null +++ b/tests/util/process/win32.c @@ -0,0 +1,61 @@ +#include "clar_libgit2.h" +#include "process.h" +#include "vector.h" + +#ifdef GIT_WIN32 +static git_str result; + +# define assert_cmdline(expected, given) do { \ + cl_git_pass(git_process__cmdline(&result, given, ARRAY_SIZE(given))); \ + cl_assert_equal_s(expected, result.ptr); \ + git_str_dispose(&result); \ + } while(0) +#endif + +void test_process_win32__cmdline_is_whitespace_delimited(void) +{ +#ifdef GIT_WIN32 + const char *one[] = { "one" }; + const char *two[] = { "one", "two" }; + const char *three[] = { "one", "two", "three" }; + const char *four[] = { "one", "two", "three", "four" }; + + assert_cmdline("one", one); + assert_cmdline("one two", two); + assert_cmdline("one two three", three); + assert_cmdline("one two three four", four); +#endif +} + +void test_process_win32__cmdline_escapes_whitespace(void) +{ +#ifdef GIT_WIN32 + const char *spaces[] = { "one with spaces" }; + const char *tabs[] = { "one\twith\ttabs" }; + const char *multiple[] = { "one with many spaces" }; + + assert_cmdline("one\" \"with\" \"spaces", spaces); + assert_cmdline("one\"\t\"with\"\t\"tabs", tabs); + assert_cmdline("one\" \"with\" \"many\" \"spaces", multiple); +#endif +} + +void test_process_win32__cmdline_escapes_quotes(void) +{ +#ifdef GIT_WIN32 + const char *one[] = { "echo", "\"hello world\"" }; + + assert_cmdline("echo \\\"hello\" \"world\\\"", one); +#endif +} + +void test_process_win32__cmdline_escapes_backslash(void) +{ +#ifdef GIT_WIN32 + const char *one[] = { "foo\\bar", "foo\\baz" }; + const char *two[] = { "c:\\program files\\foo bar\\foo bar.exe", "c:\\path\\to\\other\\", "/a", "/b" }; + + assert_cmdline("foo\\\\bar foo\\\\baz", one); + assert_cmdline("c:\\\\program\" \"files\\\\foo\" \"bar\\\\foo\" \"bar.exe c:\\\\path\\\\to\\\\other\\\\ /a /b", two); +#endif +} From 67ab8f07c987b9bb2c23471219945e44db9a91d7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 23 Feb 2023 22:50:35 +0000 Subject: [PATCH 258/816] ssh: refactor libssh2-specific bits into their own file --- src/libgit2/libgit2.c | 4 +- src/libgit2/transports/ssh.c | 1110 +------------------------ src/libgit2/transports/ssh.h | 14 - src/libgit2/transports/ssh_libssh2.c | 1113 ++++++++++++++++++++++++++ src/libgit2/transports/ssh_libssh2.h | 28 + 5 files changed, 1161 insertions(+), 1108 deletions(-) delete mode 100644 src/libgit2/transports/ssh.h create mode 100644 src/libgit2/transports/ssh_libssh2.c create mode 100644 src/libgit2/transports/ssh_libssh2.h diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index ce287147a70..56b90321f4a 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -34,7 +34,7 @@ #include "streams/socket.h" #include "transports/smart.h" #include "transports/http.h" -#include "transports/ssh.h" +#include "transports/ssh_libssh2.h" #ifdef GIT_WIN32 # include "win32/w32_leakcheck.h" @@ -80,7 +80,7 @@ int git_libgit2_init(void) git_sysdir_global_init, git_filter_global_init, git_merge_driver_global_init, - git_transport_ssh_global_init, + git_transport_ssh_libssh2_global_init, git_stream_registry_global_init, git_socket_stream_global_init, git_openssl_stream_global_init, diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c index de63d454ee6..bef0b14409f 100644 --- a/src/libgit2/transports/ssh.c +++ b/src/libgit2/transports/ssh.c @@ -5,1086 +5,38 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "ssh.h" +#include "ssh_libssh2.h" -#ifdef GIT_SSH -#include -#endif - -#include "runtime.h" -#include "net.h" -#include "smart.h" -#include "streams/socket.h" -#include "sysdir.h" - -#include "git2/credential.h" -#include "git2/sys/credential.h" - -#ifdef GIT_SSH - -#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) - -static const char cmd_uploadpack[] = "git-upload-pack"; -static const char cmd_receivepack[] = "git-receive-pack"; - -typedef struct { - git_smart_subtransport_stream parent; - git_stream *io; - LIBSSH2_SESSION *session; - LIBSSH2_CHANNEL *channel; - const char *cmd; - git_net_url url; - unsigned sent_command : 1; -} ssh_stream; - -typedef struct { - git_smart_subtransport parent; - transport_smart *owner; - ssh_stream *current_stream; - git_credential *cred; - char *cmd_uploadpack; - char *cmd_receivepack; -} ssh_subtransport; - -static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username); - -static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg) -{ - char *ssherr; - libssh2_session_last_error(session, &ssherr, NULL, 0); - - git_error_set(GIT_ERROR_SSH, "%s: %s", errmsg, ssherr); -} - -/* - * Create a git protocol request. - * - * For example: git-upload-pack '/libgit2/libgit2' - */ -static int gen_proto(git_str *request, const char *cmd, git_net_url *url) -{ - const char *repo; - - repo = url->path; - - if (repo && repo[0] == '/' && repo[1] == '~') - repo++; - - if (!repo || !repo[0]) { - git_error_set(GIT_ERROR_NET, "malformed git protocol URL"); - return -1; - } - - git_str_puts(request, cmd); - git_str_puts(request, " '"); - git_str_puts(request, repo); - git_str_puts(request, "'"); - - if (git_str_oom(request)) - return -1; - - return 0; -} - -static int send_command(ssh_stream *s) -{ - int error; - git_str request = GIT_STR_INIT; - - error = gen_proto(&request, s->cmd, &s->url); - if (error < 0) - goto cleanup; - - error = libssh2_channel_exec(s->channel, request.ptr); - if (error < LIBSSH2_ERROR_NONE) { - ssh_error(s->session, "SSH could not execute request"); - goto cleanup; - } - - s->sent_command = 1; - -cleanup: - git_str_dispose(&request); - return error; -} - -static int ssh_stream_read( - git_smart_subtransport_stream *stream, - char *buffer, - size_t buf_size, - size_t *bytes_read) -{ - int rc; - ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); - - *bytes_read = 0; - - if (!s->sent_command && send_command(s) < 0) - return -1; - - if ((rc = libssh2_channel_read(s->channel, buffer, buf_size)) < LIBSSH2_ERROR_NONE) { - ssh_error(s->session, "SSH could not read data"); - return -1; - } - - /* - * If we can't get anything out of stdout, it's typically a - * not-found error, so read from stderr and signal EOF on - * stderr. - */ - if (rc == 0) { - if ((rc = libssh2_channel_read_stderr(s->channel, buffer, buf_size)) > 0) { - git_error_set(GIT_ERROR_SSH, "%*s", rc, buffer); - return GIT_EEOF; - } else if (rc < LIBSSH2_ERROR_NONE) { - ssh_error(s->session, "SSH could not read stderr"); - return -1; - } - } - - - *bytes_read = rc; - - return 0; -} - -static int ssh_stream_write( - git_smart_subtransport_stream *stream, - const char *buffer, - size_t len) -{ - ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); - size_t off = 0; - ssize_t ret = 0; - - if (!s->sent_command && send_command(s) < 0) - return -1; - - do { - ret = libssh2_channel_write(s->channel, buffer + off, len - off); - if (ret < 0) - break; - - off += ret; - - } while (off < len); - - if (ret < 0) { - ssh_error(s->session, "SSH could not write data"); - return -1; - } - - return 0; -} - -static void ssh_stream_free(git_smart_subtransport_stream *stream) -{ - ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); - ssh_subtransport *t; - - if (!stream) - return; - - t = OWNING_SUBTRANSPORT(s); - t->current_stream = NULL; - - if (s->channel) { - libssh2_channel_close(s->channel); - libssh2_channel_free(s->channel); - s->channel = NULL; - } - - if (s->session) { - libssh2_session_disconnect(s->session, "closing transport"); - libssh2_session_free(s->session); - s->session = NULL; - } - - if (s->io) { - git_stream_close(s->io); - git_stream_free(s->io); - s->io = NULL; - } - - git_net_url_dispose(&s->url); - git__free(s); -} - -static int ssh_stream_alloc( - ssh_subtransport *t, - const char *cmd, - git_smart_subtransport_stream **stream) -{ - ssh_stream *s; - - GIT_ASSERT_ARG(stream); - - s = git__calloc(sizeof(ssh_stream), 1); - GIT_ERROR_CHECK_ALLOC(s); - - s->parent.subtransport = &t->parent; - s->parent.read = ssh_stream_read; - s->parent.write = ssh_stream_write; - s->parent.free = ssh_stream_free; - - s->cmd = cmd; - - *stream = &s->parent; - return 0; -} - -static int ssh_agent_auth(LIBSSH2_SESSION *session, git_credential_ssh_key *c) { - int rc = LIBSSH2_ERROR_NONE; - - struct libssh2_agent_publickey *curr, *prev = NULL; - - LIBSSH2_AGENT *agent = libssh2_agent_init(session); - - if (agent == NULL) - return -1; - - rc = libssh2_agent_connect(agent); - - if (rc != LIBSSH2_ERROR_NONE) { - rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; - goto shutdown; - } - - rc = libssh2_agent_list_identities(agent); - - if (rc != LIBSSH2_ERROR_NONE) - goto shutdown; - - while (1) { - rc = libssh2_agent_get_identity(agent, &curr, prev); - - if (rc < 0) - goto shutdown; - - /* rc is set to 1 whenever the ssh agent ran out of keys to check. - * Set the error code to authentication failure rather than erroring - * out with an untranslatable error code. - */ - if (rc == 1) { - rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; - goto shutdown; - } - - rc = libssh2_agent_userauth(agent, c->username, curr); - - if (rc == 0) - break; - - prev = curr; - } - -shutdown: - - if (rc != LIBSSH2_ERROR_NONE) - ssh_error(session, "error authenticating"); - - libssh2_agent_disconnect(agent); - libssh2_agent_free(agent); - - return rc; -} - -static int _git_ssh_authenticate_session( - LIBSSH2_SESSION *session, - git_credential *cred) -{ - int rc; - - do { - git_error_clear(); - switch (cred->credtype) { - case GIT_CREDENTIAL_USERPASS_PLAINTEXT: { - git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred; - rc = libssh2_userauth_password(session, c->username, c->password); - break; - } - case GIT_CREDENTIAL_SSH_KEY: { - git_credential_ssh_key *c = (git_credential_ssh_key *)cred; - - if (c->privatekey) - rc = libssh2_userauth_publickey_fromfile( - session, c->username, c->publickey, - c->privatekey, c->passphrase); - else - rc = ssh_agent_auth(session, c); - - break; - } - case GIT_CREDENTIAL_SSH_CUSTOM: { - git_credential_ssh_custom *c = (git_credential_ssh_custom *)cred; - - rc = libssh2_userauth_publickey( - session, c->username, (const unsigned char *)c->publickey, - c->publickey_len, c->sign_callback, &c->payload); - break; - } - case GIT_CREDENTIAL_SSH_INTERACTIVE: { - void **abstract = libssh2_session_abstract(session); - git_credential_ssh_interactive *c = (git_credential_ssh_interactive *)cred; - - /* ideally, we should be able to set this by calling - * libssh2_session_init_ex() instead of libssh2_session_init(). - * libssh2's API is inconsistent here i.e. libssh2_userauth_publickey() - * allows you to pass the `abstract` as part of the call, whereas - * libssh2_userauth_keyboard_interactive() does not! - * - * The only way to set the `abstract` pointer is by calling - * libssh2_session_abstract(), which will replace the existing - * pointer as is done below. This is safe for now (at time of writing), - * but may not be valid in future. - */ - *abstract = c->payload; - - rc = libssh2_userauth_keyboard_interactive( - session, c->username, c->prompt_callback); - break; - } -#ifdef GIT_SSH_MEMORY_CREDENTIALS - case GIT_CREDENTIAL_SSH_MEMORY: { - git_credential_ssh_key *c = (git_credential_ssh_key *)cred; - - GIT_ASSERT(c->username); - GIT_ASSERT(c->privatekey); - - rc = libssh2_userauth_publickey_frommemory( - session, - c->username, - strlen(c->username), - c->publickey, - c->publickey ? strlen(c->publickey) : 0, - c->privatekey, - strlen(c->privatekey), - c->passphrase); - break; - } -#endif - default: - rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; - } - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); - - if (rc == LIBSSH2_ERROR_PASSWORD_EXPIRED || - rc == LIBSSH2_ERROR_AUTHENTICATION_FAILED || - rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) - return GIT_EAUTH; - - if (rc != LIBSSH2_ERROR_NONE) { - if (!git_error_last()) - ssh_error(session, "Failed to authenticate SSH session"); - return -1; - } - - return 0; -} - -static int request_creds(git_credential **out, ssh_subtransport *t, const char *user, int auth_methods) -{ - int error, no_callback = 0; - git_credential *cred = NULL; - - if (!t->owner->connect_opts.callbacks.credentials) { - no_callback = 1; - } else { - error = t->owner->connect_opts.callbacks.credentials( - &cred, - t->owner->url, - user, - auth_methods, - t->owner->connect_opts.callbacks.payload); - - if (error == GIT_PASSTHROUGH) { - no_callback = 1; - } else if (error < 0) { - return error; - } else if (!cred) { - git_error_set(GIT_ERROR_SSH, "callback failed to initialize SSH credentials"); - return -1; - } - } - - if (no_callback) { - git_error_set(GIT_ERROR_SSH, "authentication required but no callback set"); - return GIT_EAUTH; - } - - if (!(cred->credtype & auth_methods)) { - cred->free(cred); - git_error_set(GIT_ERROR_SSH, "authentication callback returned unsupported credentials type"); - return GIT_EAUTH; - } - - *out = cred; - - return 0; -} - -#define SSH_DIR ".ssh" -#define KNOWN_HOSTS_FILE "known_hosts" - -/* - * Load the known_hosts file. - * - * Returns success but leaves the output NULL if we couldn't find the file. - */ -static int load_known_hosts(LIBSSH2_KNOWNHOSTS **hosts, LIBSSH2_SESSION *session) -{ - git_str path = GIT_STR_INIT, sshdir = GIT_STR_INIT; - LIBSSH2_KNOWNHOSTS *known_hosts = NULL; - int error; - - GIT_ASSERT_ARG(hosts); - - if ((error = git_sysdir_expand_homedir_file(&sshdir, SSH_DIR)) < 0 || - (error = git_str_joinpath(&path, git_str_cstr(&sshdir), KNOWN_HOSTS_FILE)) < 0) - goto out; - - if ((known_hosts = libssh2_knownhost_init(session)) == NULL) { - ssh_error(session, "error initializing known hosts"); - error = -1; - goto out; - } - - /* - * Try to read the file and consider not finding it as not trusting the - * host rather than an error. - */ - error = libssh2_knownhost_readfile(known_hosts, git_str_cstr(&path), LIBSSH2_KNOWNHOST_FILE_OPENSSH); - if (error == LIBSSH2_ERROR_FILE) - error = 0; - if (error < 0) - ssh_error(session, "error reading known_hosts"); - -out: - *hosts = known_hosts; - - git_str_dispose(&sshdir); - git_str_dispose(&path); - - return error; -} - -static void add_hostkey_pref_if_avail( - LIBSSH2_KNOWNHOSTS *known_hosts, - const char *hostname, - int port, - git_str *prefs, - int type, - const char *type_name) -{ - struct libssh2_knownhost *host = NULL; - const char key = '\0'; - int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW | type; - int error; - - error = libssh2_knownhost_checkp(known_hosts, hostname, port, &key, 1, mask, &host); - if (error == LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { - if (git_str_len(prefs) > 0) { - git_str_putc(prefs, ','); - } - git_str_puts(prefs, type_name); - } -} - -/* - * We figure out what kind of key we want to ask the remote for by trying to - * look it up with a nonsense key and using that mismatch to figure out what key - * we do have stored for the host. - * - * Populates prefs with the string to pass to libssh2_session_method_pref. - */ -static void find_hostkey_preference( - LIBSSH2_KNOWNHOSTS *known_hosts, - const char *hostname, - int port, - git_str *prefs) -{ - /* - * The order here is important as it indicates the priority of what will - * be preferred. - */ -#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 - add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ED25519, "ssh-ed25519"); -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 - add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_256, "ecdsa-sha2-nistp256"); - add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_384, "ecdsa-sha2-nistp384"); - add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_521, "ecdsa-sha2-nistp521"); -#endif - add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_SSHRSA, "ssh-rsa"); -} - -static int _git_ssh_session_create( - LIBSSH2_SESSION **session, - LIBSSH2_KNOWNHOSTS **hosts, - const char *hostname, - int port, - git_stream *io) -{ - git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent); - LIBSSH2_SESSION *s; - LIBSSH2_KNOWNHOSTS *known_hosts; - git_str prefs = GIT_STR_INIT; - int rc = 0; - - GIT_ASSERT_ARG(session); - GIT_ASSERT_ARG(hosts); - - s = libssh2_session_init(); - if (!s) { - git_error_set(GIT_ERROR_NET, "failed to initialize SSH session"); - return -1; - } - - if ((rc = load_known_hosts(&known_hosts, s)) < 0) { - ssh_error(s, "error loading known_hosts"); - libssh2_session_free(s); - return -1; - } - - find_hostkey_preference(known_hosts, hostname, port, &prefs); - if (git_str_len(&prefs) > 0) { - do { - rc = libssh2_session_method_pref(s, LIBSSH2_METHOD_HOSTKEY, git_str_cstr(&prefs)); - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); - if (rc != LIBSSH2_ERROR_NONE) { - ssh_error(s, "failed to set hostkey preference"); - goto on_error; - } - } - git_str_dispose(&prefs); - - do { - rc = libssh2_session_handshake(s, socket->s); - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); - - if (rc != LIBSSH2_ERROR_NONE) { - ssh_error(s, "failed to start SSH session"); - goto on_error; - } - - libssh2_session_set_blocking(s, 1); - - *session = s; - *hosts = known_hosts; - - return 0; - -on_error: - libssh2_knownhost_free(known_hosts); - libssh2_session_free(s); - return -1; -} - - -/* - * Returns the typemask argument to pass to libssh2_knownhost_check{,p} based on - * the type of key that libssh2_session_hostkey returns. - */ -static int fingerprint_type_mask(int keytype) -{ - int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW; - return mask; - - switch (keytype) { - case LIBSSH2_HOSTKEY_TYPE_RSA: - mask |= LIBSSH2_KNOWNHOST_KEY_SSHRSA; - break; - case LIBSSH2_HOSTKEY_TYPE_DSS: - mask |= LIBSSH2_KNOWNHOST_KEY_SSHDSS; - break; -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 - case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: - mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_256; - break; - case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: - mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_384; - break; - case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: - mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_521; - break; -#endif -#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 - case LIBSSH2_HOSTKEY_TYPE_ED25519: - mask |= LIBSSH2_KNOWNHOST_KEY_ED25519; - break; -#endif - } - - return mask; -} - -/* - * Check the host against the user's known_hosts file. - * - * Returns 1/0 for valid/''not-valid or <0 for an error - */ -static int check_against_known_hosts( - LIBSSH2_SESSION *session, - LIBSSH2_KNOWNHOSTS *known_hosts, - const char *hostname, - int port, - const char *key, - size_t key_len, - int key_type) -{ - int check, typemask, ret = 0; - struct libssh2_knownhost *host = NULL; - - if (known_hosts == NULL) - return 0; - - typemask = fingerprint_type_mask(key_type); - check = libssh2_knownhost_checkp(known_hosts, hostname, port, key, key_len, typemask, &host); - if (check == LIBSSH2_KNOWNHOST_CHECK_FAILURE) { - ssh_error(session, "error checking for known host"); - return -1; - } - - ret = check == LIBSSH2_KNOWNHOST_CHECK_MATCH ? 1 : 0; - - return ret; -} - -/* - * Perform the check for the session's certificate against known hosts if - * possible and then ask the user if they have a callback. - * - * Returns 1/0 for valid/not-valid or <0 for an error - */ -static int check_certificate( - LIBSSH2_SESSION *session, - LIBSSH2_KNOWNHOSTS *known_hosts, - git_transport_certificate_check_cb check_cb, - void *check_cb_payload, - const char *host, - int port) -{ - git_cert_hostkey cert = {{ 0 }}; - const char *key; - size_t cert_len; - int cert_type, cert_valid = 0, error = 0; - - if ((key = libssh2_session_hostkey(session, &cert_len, &cert_type)) == NULL) { - ssh_error(session, "failed to retrieve hostkey"); - return -1; - } - - if ((cert_valid = check_against_known_hosts(session, known_hosts, host, port, key, cert_len, cert_type)) < 0) - return -1; - - cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2; - if (key != NULL) { - cert.type |= GIT_CERT_SSH_RAW; - cert.hostkey = key; - cert.hostkey_len = cert_len; - switch (cert_type) { - case LIBSSH2_HOSTKEY_TYPE_RSA: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_RSA; - break; - case LIBSSH2_HOSTKEY_TYPE_DSS: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_DSS; - break; - -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 - case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256; - break; - case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384; - break; - case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521; - break; -#endif - -#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 - case LIBSSH2_HOSTKEY_TYPE_ED25519: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ED25519; - break; -#endif - default: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_UNKNOWN; - } - } - -#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256); - if (key != NULL) { - cert.type |= GIT_CERT_SSH_SHA256; - memcpy(&cert.hash_sha256, key, 32); - } -#endif - - key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); - if (key != NULL) { - cert.type |= GIT_CERT_SSH_SHA1; - memcpy(&cert.hash_sha1, key, 20); - } - - key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); - if (key != NULL) { - cert.type |= GIT_CERT_SSH_MD5; - memcpy(&cert.hash_md5, key, 16); - } - - if (cert.type == 0) { - git_error_set(GIT_ERROR_SSH, "unable to get the host key"); - return -1; - } - - git_error_clear(); - error = 0; - if (!cert_valid) { - git_error_set(GIT_ERROR_SSH, "invalid or unknown remote ssh hostkey"); - error = GIT_ECERTIFICATE; - } - - if (check_cb != NULL) { - git_cert_hostkey *cert_ptr = &cert; - git_error_state previous_error = {0}; - - git_error_state_capture(&previous_error, error); - error = check_cb((git_cert *) cert_ptr, cert_valid, host, check_cb_payload); - if (error == GIT_PASSTHROUGH) { - error = git_error_state_restore(&previous_error); - } else if (error < 0 && !git_error_last()) { - git_error_set(GIT_ERROR_NET, "unknown remote host key"); - } - - git_error_state_free(&previous_error); - } - - return error; -} - -#define SSH_DEFAULT_PORT "22" - -static int _git_ssh_setup_conn( - ssh_subtransport *t, - const char *url, - const char *cmd, - git_smart_subtransport_stream **stream) -{ - int auth_methods, error = 0, port; - ssh_stream *s; - git_credential *cred = NULL; - LIBSSH2_SESSION *session=NULL; - LIBSSH2_CHANNEL *channel=NULL; - LIBSSH2_KNOWNHOSTS *known_hosts = NULL; - - t->current_stream = NULL; - - *stream = NULL; - if (ssh_stream_alloc(t, cmd, stream) < 0) - return -1; - - s = (ssh_stream *)*stream; - s->session = NULL; - s->channel = NULL; - - if ((error = git_net_url_parse_standard_or_scp(&s->url, url)) < 0 || - (error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 || - (error = git_stream_connect(s->io)) < 0) - goto done; - - /* - * Try to parse the port as a number, if we can't then fall back to - * default. It would be nice if we could get the port that was resolved - * as part of the stream connection, but that's not something that's - * exposed. - */ - if (git__strntol32(&port, s->url.port, strlen(s->url.port), NULL, 10) < 0) { - git_error_set(GIT_ERROR_NET, "invalid port to ssh: %s", s->url.port); - error = -1; - goto done; - } - - if ((error = _git_ssh_session_create(&session, &known_hosts, s->url.host, port, s->io)) < 0) - goto done; - - if ((error = check_certificate(session, known_hosts, t->owner->connect_opts.callbacks.certificate_check, t->owner->connect_opts.callbacks.payload, s->url.host, port)) < 0) - goto done; - - /* we need the username to ask for auth methods */ - if (!s->url.username) { - if ((error = request_creds(&cred, t, NULL, GIT_CREDENTIAL_USERNAME)) < 0) - goto done; - - s->url.username = git__strdup(((git_credential_username *) cred)->username); - cred->free(cred); - cred = NULL; - if (!s->url.username) - goto done; - } else if (s->url.username && s->url.password) { - if ((error = git_credential_userpass_plaintext_new(&cred, s->url.username, s->url.password)) < 0) - goto done; - } - - if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) - goto done; - - error = GIT_EAUTH; - /* if we already have something to try */ - if (cred && auth_methods & cred->credtype) - error = _git_ssh_authenticate_session(session, cred); - - while (error == GIT_EAUTH) { - if (cred) { - cred->free(cred); - cred = NULL; - } - - if ((error = request_creds(&cred, t, s->url.username, auth_methods)) < 0) - goto done; - - if (strcmp(s->url.username, git_credential_get_username(cred))) { - git_error_set(GIT_ERROR_SSH, "username does not match previous request"); - error = -1; - goto done; - } - - error = _git_ssh_authenticate_session(session, cred); - - if (error == GIT_EAUTH) { - /* refresh auth methods */ - if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) - goto done; - else - error = GIT_EAUTH; - } - } - - if (error < 0) - goto done; - - channel = libssh2_channel_open_session(session); - if (!channel) { - error = -1; - ssh_error(session, "Failed to open SSH channel"); - goto done; - } - - libssh2_channel_set_blocking(channel, 1); - - s->session = session; - s->channel = channel; - - t->current_stream = s; - -done: - if (known_hosts) - libssh2_knownhost_free(known_hosts); - - if (error < 0) { - ssh_stream_free(*stream); - - if (session) - libssh2_session_free(session); - } - - if (cred) - cred->free(cred); - - return error; -} - -static int ssh_uploadpack_ls( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - const char *cmd = t->cmd_uploadpack ? t->cmd_uploadpack : cmd_uploadpack; - - return _git_ssh_setup_conn(t, url, cmd, stream); -} - -static int ssh_uploadpack( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - GIT_UNUSED(url); - - if (t->current_stream) { - *stream = &t->current_stream->parent; - return 0; - } - - git_error_set(GIT_ERROR_NET, "must call UPLOADPACK_LS before UPLOADPACK"); - return -1; -} - -static int ssh_receivepack_ls( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - const char *cmd = t->cmd_receivepack ? t->cmd_receivepack : cmd_receivepack; - - - return _git_ssh_setup_conn(t, url, cmd, stream); -} - -static int ssh_receivepack( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - GIT_UNUSED(url); - - if (t->current_stream) { - *stream = &t->current_stream->parent; - return 0; - } - - git_error_set(GIT_ERROR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK"); - return -1; -} - -static int _ssh_action( - git_smart_subtransport_stream **stream, - git_smart_subtransport *subtransport, - const char *url, - git_smart_service_t action) -{ - ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); - - switch (action) { - case GIT_SERVICE_UPLOADPACK_LS: - return ssh_uploadpack_ls(t, url, stream); - - case GIT_SERVICE_UPLOADPACK: - return ssh_uploadpack(t, url, stream); - - case GIT_SERVICE_RECEIVEPACK_LS: - return ssh_receivepack_ls(t, url, stream); - - case GIT_SERVICE_RECEIVEPACK: - return ssh_receivepack(t, url, stream); - } - - *stream = NULL; - return -1; -} - -static int _ssh_close(git_smart_subtransport *subtransport) -{ - ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); - - GIT_ASSERT(!t->current_stream); - - GIT_UNUSED(t); - - return 0; -} - -static void _ssh_free(git_smart_subtransport *subtransport) -{ - ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); - - git__free(t->cmd_uploadpack); - git__free(t->cmd_receivepack); - git__free(t); -} - -#define SSH_AUTH_PUBLICKEY "publickey" -#define SSH_AUTH_PASSWORD "password" -#define SSH_AUTH_KEYBOARD_INTERACTIVE "keyboard-interactive" - -static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username) -{ - const char *list, *ptr; - - *out = 0; - - list = libssh2_userauth_list(session, username, strlen(username)); - - /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */ - if (list == NULL && !libssh2_userauth_authenticated(session)) { - ssh_error(session, "remote rejected authentication"); - return GIT_EAUTH; - } - - ptr = list; - while (ptr) { - if (*ptr == ',') - ptr++; - - if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) { - *out |= GIT_CREDENTIAL_SSH_KEY; - *out |= GIT_CREDENTIAL_SSH_CUSTOM; -#ifdef GIT_SSH_MEMORY_CREDENTIALS - *out |= GIT_CREDENTIAL_SSH_MEMORY; -#endif - ptr += strlen(SSH_AUTH_PUBLICKEY); - continue; - } - - if (!git__prefixcmp(ptr, SSH_AUTH_PASSWORD)) { - *out |= GIT_CREDENTIAL_USERPASS_PLAINTEXT; - ptr += strlen(SSH_AUTH_PASSWORD); - continue; - } - - if (!git__prefixcmp(ptr, SSH_AUTH_KEYBOARD_INTERACTIVE)) { - *out |= GIT_CREDENTIAL_SSH_INTERACTIVE; - ptr += strlen(SSH_AUTH_KEYBOARD_INTERACTIVE); - continue; - } - - /* Skip it if we don't know it */ - ptr = strchr(ptr, ','); - } - - return 0; -} -#endif +#include "transports/smart.h" int git_smart_subtransport_ssh( - git_smart_subtransport **out, git_transport *owner, void *param) + git_smart_subtransport **out, + git_transport *owner, + void *param) { #ifdef GIT_SSH - ssh_subtransport *t; - - GIT_ASSERT_ARG(out); - - GIT_UNUSED(param); - - t = git__calloc(sizeof(ssh_subtransport), 1); - GIT_ERROR_CHECK_ALLOC(t); - - t->owner = (transport_smart *)owner; - t->parent.action = _ssh_action; - t->parent.close = _ssh_close; - t->parent.free = _ssh_free; - - *out = (git_smart_subtransport *) t; - return 0; + return git_smart_subtransport_ssh_libssh2(out, owner, param); #else + GIT_UNUSED(out); GIT_UNUSED(owner); GIT_UNUSED(param); - GIT_ASSERT_ARG(out); - *out = NULL; - git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support"); return -1; #endif } -int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *payload) +int git_transport_ssh_with_paths( + git_transport **out, + git_remote *owner, + void *payload) { #ifdef GIT_SSH git_strarray *paths = (git_strarray *) payload; git_transport *transport; transport_smart *smart; - ssh_subtransport *t; int error; + git_smart_subtransport_definition ssh_definition = { git_smart_subtransport_ssh, 0, /* no RPC */ @@ -1100,48 +52,22 @@ int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *p return error; smart = (transport_smart *) transport; - t = (ssh_subtransport *) smart->wrapped; - t->cmd_uploadpack = git__strdup(paths->strings[0]); - GIT_ERROR_CHECK_ALLOC(t->cmd_uploadpack); - t->cmd_receivepack = git__strdup(paths->strings[1]); - GIT_ERROR_CHECK_ALLOC(t->cmd_receivepack); + if ((error = git_smart_subtransport_ssh_libssh2_set_paths( + (git_smart_subtransport *)smart->wrapped, + paths->strings[0], + paths->strings[1])) < 0) + return error; *out = transport; return 0; #else + GIT_UNUSED(out); GIT_UNUSED(owner); GIT_UNUSED(payload); - GIT_ASSERT_ARG(out); - *out = NULL; - git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support"); return -1; #endif } -#ifdef GIT_SSH -static void shutdown_ssh(void) -{ - libssh2_exit(); -} -#endif - -int git_transport_ssh_global_init(void) -{ -#ifdef GIT_SSH - if (libssh2_init(0) < 0) { - git_error_set(GIT_ERROR_SSH, "unable to initialize libssh2"); - return -1; - } - - return git_runtime_shutdown_register(shutdown_ssh); - -#else - - /* Nothing to initialize */ - return 0; - -#endif -} diff --git a/src/libgit2/transports/ssh.h b/src/libgit2/transports/ssh.h deleted file mode 100644 index d3e741f1d9e..00000000000 --- a/src/libgit2/transports/ssh.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_transports_ssh_h__ -#define INCLUDE_transports_ssh_h__ - -#include "common.h" - -int git_transport_ssh_global_init(void); - -#endif diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c new file mode 100644 index 00000000000..154d022944b --- /dev/null +++ b/src/libgit2/transports/ssh_libssh2.c @@ -0,0 +1,1113 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "ssh_libssh2.h" + +#ifdef GIT_SSH + +#include + +#include "runtime.h" +#include "net.h" +#include "smart.h" +#include "streams/socket.h" +#include "sysdir.h" + +#include "git2/credential.h" +#include "git2/sys/credential.h" + +#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) + +static const char cmd_uploadpack[] = "git-upload-pack"; +static const char cmd_receivepack[] = "git-receive-pack"; + +typedef struct { + git_smart_subtransport_stream parent; + git_stream *io; + LIBSSH2_SESSION *session; + LIBSSH2_CHANNEL *channel; + const char *cmd; + git_net_url url; + unsigned sent_command : 1; +} ssh_stream; + +typedef struct { + git_smart_subtransport parent; + transport_smart *owner; + ssh_stream *current_stream; + git_credential *cred; + char *cmd_uploadpack; + char *cmd_receivepack; +} ssh_subtransport; + +static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username); + +static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg) +{ + char *ssherr; + libssh2_session_last_error(session, &ssherr, NULL, 0); + + git_error_set(GIT_ERROR_SSH, "%s: %s", errmsg, ssherr); +} + +/* + * Create a git protocol request. + * + * For example: git-upload-pack '/libgit2/libgit2' + */ +static int gen_proto(git_str *request, const char *cmd, git_net_url *url) +{ + const char *repo; + + repo = url->path; + + if (repo && repo[0] == '/' && repo[1] == '~') + repo++; + + if (!repo || !repo[0]) { + git_error_set(GIT_ERROR_NET, "malformed git protocol URL"); + return -1; + } + + git_str_puts(request, cmd); + git_str_puts(request, " '"); + git_str_puts(request, repo); + git_str_puts(request, "'"); + + if (git_str_oom(request)) + return -1; + + return 0; +} + +static int send_command(ssh_stream *s) +{ + int error; + git_str request = GIT_STR_INIT; + + error = gen_proto(&request, s->cmd, &s->url); + if (error < 0) + goto cleanup; + + error = libssh2_channel_exec(s->channel, request.ptr); + if (error < LIBSSH2_ERROR_NONE) { + ssh_error(s->session, "SSH could not execute request"); + goto cleanup; + } + + s->sent_command = 1; + +cleanup: + git_str_dispose(&request); + return error; +} + +static int ssh_stream_read( + git_smart_subtransport_stream *stream, + char *buffer, + size_t buf_size, + size_t *bytes_read) +{ + int rc; + ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); + + *bytes_read = 0; + + if (!s->sent_command && send_command(s) < 0) + return -1; + + if ((rc = libssh2_channel_read(s->channel, buffer, buf_size)) < LIBSSH2_ERROR_NONE) { + ssh_error(s->session, "SSH could not read data"); + return -1; + } + + /* + * If we can't get anything out of stdout, it's typically a + * not-found error, so read from stderr and signal EOF on + * stderr. + */ + if (rc == 0) { + if ((rc = libssh2_channel_read_stderr(s->channel, buffer, buf_size)) > 0) { + git_error_set(GIT_ERROR_SSH, "%*s", rc, buffer); + return GIT_EEOF; + } else if (rc < LIBSSH2_ERROR_NONE) { + ssh_error(s->session, "SSH could not read stderr"); + return -1; + } + } + + + *bytes_read = rc; + + return 0; +} + +static int ssh_stream_write( + git_smart_subtransport_stream *stream, + const char *buffer, + size_t len) +{ + ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); + size_t off = 0; + ssize_t ret = 0; + + if (!s->sent_command && send_command(s) < 0) + return -1; + + do { + ret = libssh2_channel_write(s->channel, buffer + off, len - off); + if (ret < 0) + break; + + off += ret; + + } while (off < len); + + if (ret < 0) { + ssh_error(s->session, "SSH could not write data"); + return -1; + } + + return 0; +} + +static void ssh_stream_free(git_smart_subtransport_stream *stream) +{ + ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); + ssh_subtransport *t; + + if (!stream) + return; + + t = OWNING_SUBTRANSPORT(s); + t->current_stream = NULL; + + if (s->channel) { + libssh2_channel_close(s->channel); + libssh2_channel_free(s->channel); + s->channel = NULL; + } + + if (s->session) { + libssh2_session_disconnect(s->session, "closing transport"); + libssh2_session_free(s->session); + s->session = NULL; + } + + if (s->io) { + git_stream_close(s->io); + git_stream_free(s->io); + s->io = NULL; + } + + git_net_url_dispose(&s->url); + git__free(s); +} + +static int ssh_stream_alloc( + ssh_subtransport *t, + const char *cmd, + git_smart_subtransport_stream **stream) +{ + ssh_stream *s; + + GIT_ASSERT_ARG(stream); + + s = git__calloc(sizeof(ssh_stream), 1); + GIT_ERROR_CHECK_ALLOC(s); + + s->parent.subtransport = &t->parent; + s->parent.read = ssh_stream_read; + s->parent.write = ssh_stream_write; + s->parent.free = ssh_stream_free; + + s->cmd = cmd; + + *stream = &s->parent; + return 0; +} + +static int ssh_agent_auth(LIBSSH2_SESSION *session, git_credential_ssh_key *c) { + int rc = LIBSSH2_ERROR_NONE; + + struct libssh2_agent_publickey *curr, *prev = NULL; + + LIBSSH2_AGENT *agent = libssh2_agent_init(session); + + if (agent == NULL) + return -1; + + rc = libssh2_agent_connect(agent); + + if (rc != LIBSSH2_ERROR_NONE) { + rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; + goto shutdown; + } + + rc = libssh2_agent_list_identities(agent); + + if (rc != LIBSSH2_ERROR_NONE) + goto shutdown; + + while (1) { + rc = libssh2_agent_get_identity(agent, &curr, prev); + + if (rc < 0) + goto shutdown; + + /* rc is set to 1 whenever the ssh agent ran out of keys to check. + * Set the error code to authentication failure rather than erroring + * out with an untranslatable error code. + */ + if (rc == 1) { + rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; + goto shutdown; + } + + rc = libssh2_agent_userauth(agent, c->username, curr); + + if (rc == 0) + break; + + prev = curr; + } + +shutdown: + + if (rc != LIBSSH2_ERROR_NONE) + ssh_error(session, "error authenticating"); + + libssh2_agent_disconnect(agent); + libssh2_agent_free(agent); + + return rc; +} + +static int _git_ssh_authenticate_session( + LIBSSH2_SESSION *session, + git_credential *cred) +{ + int rc; + + do { + git_error_clear(); + switch (cred->credtype) { + case GIT_CREDENTIAL_USERPASS_PLAINTEXT: { + git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred; + rc = libssh2_userauth_password(session, c->username, c->password); + break; + } + case GIT_CREDENTIAL_SSH_KEY: { + git_credential_ssh_key *c = (git_credential_ssh_key *)cred; + + if (c->privatekey) + rc = libssh2_userauth_publickey_fromfile( + session, c->username, c->publickey, + c->privatekey, c->passphrase); + else + rc = ssh_agent_auth(session, c); + + break; + } + case GIT_CREDENTIAL_SSH_CUSTOM: { + git_credential_ssh_custom *c = (git_credential_ssh_custom *)cred; + + rc = libssh2_userauth_publickey( + session, c->username, (const unsigned char *)c->publickey, + c->publickey_len, c->sign_callback, &c->payload); + break; + } + case GIT_CREDENTIAL_SSH_INTERACTIVE: { + void **abstract = libssh2_session_abstract(session); + git_credential_ssh_interactive *c = (git_credential_ssh_interactive *)cred; + + /* ideally, we should be able to set this by calling + * libssh2_session_init_ex() instead of libssh2_session_init(). + * libssh2's API is inconsistent here i.e. libssh2_userauth_publickey() + * allows you to pass the `abstract` as part of the call, whereas + * libssh2_userauth_keyboard_interactive() does not! + * + * The only way to set the `abstract` pointer is by calling + * libssh2_session_abstract(), which will replace the existing + * pointer as is done below. This is safe for now (at time of writing), + * but may not be valid in future. + */ + *abstract = c->payload; + + rc = libssh2_userauth_keyboard_interactive( + session, c->username, c->prompt_callback); + break; + } +#ifdef GIT_SSH_MEMORY_CREDENTIALS + case GIT_CREDENTIAL_SSH_MEMORY: { + git_credential_ssh_key *c = (git_credential_ssh_key *)cred; + + GIT_ASSERT(c->username); + GIT_ASSERT(c->privatekey); + + rc = libssh2_userauth_publickey_frommemory( + session, + c->username, + strlen(c->username), + c->publickey, + c->publickey ? strlen(c->publickey) : 0, + c->privatekey, + strlen(c->privatekey), + c->passphrase); + break; + } +#endif + default: + rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; + } + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + if (rc == LIBSSH2_ERROR_PASSWORD_EXPIRED || + rc == LIBSSH2_ERROR_AUTHENTICATION_FAILED || + rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) + return GIT_EAUTH; + + if (rc != LIBSSH2_ERROR_NONE) { + if (!git_error_last()) + ssh_error(session, "Failed to authenticate SSH session"); + return -1; + } + + return 0; +} + +static int request_creds(git_credential **out, ssh_subtransport *t, const char *user, int auth_methods) +{ + int error, no_callback = 0; + git_credential *cred = NULL; + + if (!t->owner->connect_opts.callbacks.credentials) { + no_callback = 1; + } else { + error = t->owner->connect_opts.callbacks.credentials( + &cred, + t->owner->url, + user, + auth_methods, + t->owner->connect_opts.callbacks.payload); + + if (error == GIT_PASSTHROUGH) { + no_callback = 1; + } else if (error < 0) { + return error; + } else if (!cred) { + git_error_set(GIT_ERROR_SSH, "callback failed to initialize SSH credentials"); + return -1; + } + } + + if (no_callback) { + git_error_set(GIT_ERROR_SSH, "authentication required but no callback set"); + return GIT_EAUTH; + } + + if (!(cred->credtype & auth_methods)) { + cred->free(cred); + git_error_set(GIT_ERROR_SSH, "authentication callback returned unsupported credentials type"); + return GIT_EAUTH; + } + + *out = cred; + + return 0; +} + +#define SSH_DIR ".ssh" +#define KNOWN_HOSTS_FILE "known_hosts" + +/* + * Load the known_hosts file. + * + * Returns success but leaves the output NULL if we couldn't find the file. + */ +static int load_known_hosts(LIBSSH2_KNOWNHOSTS **hosts, LIBSSH2_SESSION *session) +{ + git_str path = GIT_STR_INIT, sshdir = GIT_STR_INIT; + LIBSSH2_KNOWNHOSTS *known_hosts = NULL; + int error; + + GIT_ASSERT_ARG(hosts); + + if ((error = git_sysdir_expand_homedir_file(&sshdir, SSH_DIR)) < 0 || + (error = git_str_joinpath(&path, git_str_cstr(&sshdir), KNOWN_HOSTS_FILE)) < 0) + goto out; + + if ((known_hosts = libssh2_knownhost_init(session)) == NULL) { + ssh_error(session, "error initializing known hosts"); + error = -1; + goto out; + } + + /* + * Try to read the file and consider not finding it as not trusting the + * host rather than an error. + */ + error = libssh2_knownhost_readfile(known_hosts, git_str_cstr(&path), LIBSSH2_KNOWNHOST_FILE_OPENSSH); + if (error == LIBSSH2_ERROR_FILE) + error = 0; + if (error < 0) + ssh_error(session, "error reading known_hosts"); + +out: + *hosts = known_hosts; + + git_str_dispose(&sshdir); + git_str_dispose(&path); + + return error; +} + +static void add_hostkey_pref_if_avail( + LIBSSH2_KNOWNHOSTS *known_hosts, + const char *hostname, + int port, + git_str *prefs, + int type, + const char *type_name) +{ + struct libssh2_knownhost *host = NULL; + const char key = '\0'; + int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW | type; + int error; + + error = libssh2_knownhost_checkp(known_hosts, hostname, port, &key, 1, mask, &host); + if (error == LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { + if (git_str_len(prefs) > 0) { + git_str_putc(prefs, ','); + } + git_str_puts(prefs, type_name); + } +} + +/* + * We figure out what kind of key we want to ask the remote for by trying to + * look it up with a nonsense key and using that mismatch to figure out what key + * we do have stored for the host. + * + * Populates prefs with the string to pass to libssh2_session_method_pref. + */ +static void find_hostkey_preference( + LIBSSH2_KNOWNHOSTS *known_hosts, + const char *hostname, + int port, + git_str *prefs) +{ + /* + * The order here is important as it indicates the priority of what will + * be preferred. + */ +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ED25519, "ssh-ed25519"); +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_256, "ecdsa-sha2-nistp256"); + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_384, "ecdsa-sha2-nistp384"); + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_521, "ecdsa-sha2-nistp521"); +#endif + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_SSHRSA, "ssh-rsa"); +} + +static int _git_ssh_session_create( + LIBSSH2_SESSION **session, + LIBSSH2_KNOWNHOSTS **hosts, + const char *hostname, + int port, + git_stream *io) +{ + git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent); + LIBSSH2_SESSION *s; + LIBSSH2_KNOWNHOSTS *known_hosts; + git_str prefs = GIT_STR_INIT; + int rc = 0; + + GIT_ASSERT_ARG(session); + GIT_ASSERT_ARG(hosts); + + s = libssh2_session_init(); + if (!s) { + git_error_set(GIT_ERROR_NET, "failed to initialize SSH session"); + return -1; + } + + if ((rc = load_known_hosts(&known_hosts, s)) < 0) { + ssh_error(s, "error loading known_hosts"); + libssh2_session_free(s); + return -1; + } + + find_hostkey_preference(known_hosts, hostname, port, &prefs); + if (git_str_len(&prefs) > 0) { + do { + rc = libssh2_session_method_pref(s, LIBSSH2_METHOD_HOSTKEY, git_str_cstr(&prefs)); + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + if (rc != LIBSSH2_ERROR_NONE) { + ssh_error(s, "failed to set hostkey preference"); + goto on_error; + } + } + git_str_dispose(&prefs); + + do { + rc = libssh2_session_handshake(s, socket->s); + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + if (rc != LIBSSH2_ERROR_NONE) { + ssh_error(s, "failed to start SSH session"); + goto on_error; + } + + libssh2_session_set_blocking(s, 1); + + *session = s; + *hosts = known_hosts; + + return 0; + +on_error: + libssh2_knownhost_free(known_hosts); + libssh2_session_free(s); + return -1; +} + + +/* + * Returns the typemask argument to pass to libssh2_knownhost_check{,p} based on + * the type of key that libssh2_session_hostkey returns. + */ +static int fingerprint_type_mask(int keytype) +{ + int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW; + return mask; + + switch (keytype) { + case LIBSSH2_HOSTKEY_TYPE_RSA: + mask |= LIBSSH2_KNOWNHOST_KEY_SSHRSA; + break; + case LIBSSH2_HOSTKEY_TYPE_DSS: + mask |= LIBSSH2_KNOWNHOST_KEY_SSHDSS; + break; +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: + mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_256; + break; + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: + mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_384; + break; + case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: + mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_521; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 + case LIBSSH2_HOSTKEY_TYPE_ED25519: + mask |= LIBSSH2_KNOWNHOST_KEY_ED25519; + break; +#endif + } + + return mask; +} + +/* + * Check the host against the user's known_hosts file. + * + * Returns 1/0 for valid/''not-valid or <0 for an error + */ +static int check_against_known_hosts( + LIBSSH2_SESSION *session, + LIBSSH2_KNOWNHOSTS *known_hosts, + const char *hostname, + int port, + const char *key, + size_t key_len, + int key_type) +{ + int check, typemask, ret = 0; + struct libssh2_knownhost *host = NULL; + + if (known_hosts == NULL) + return 0; + + typemask = fingerprint_type_mask(key_type); + check = libssh2_knownhost_checkp(known_hosts, hostname, port, key, key_len, typemask, &host); + if (check == LIBSSH2_KNOWNHOST_CHECK_FAILURE) { + ssh_error(session, "error checking for known host"); + return -1; + } + + ret = check == LIBSSH2_KNOWNHOST_CHECK_MATCH ? 1 : 0; + + return ret; +} + +/* + * Perform the check for the session's certificate against known hosts if + * possible and then ask the user if they have a callback. + * + * Returns 1/0 for valid/not-valid or <0 for an error + */ +static int check_certificate( + LIBSSH2_SESSION *session, + LIBSSH2_KNOWNHOSTS *known_hosts, + git_transport_certificate_check_cb check_cb, + void *check_cb_payload, + const char *host, + int port) +{ + git_cert_hostkey cert = {{ 0 }}; + const char *key; + size_t cert_len; + int cert_type, cert_valid = 0, error = 0; + + if ((key = libssh2_session_hostkey(session, &cert_len, &cert_type)) == NULL) { + ssh_error(session, "failed to retrieve hostkey"); + return -1; + } + + if ((cert_valid = check_against_known_hosts(session, known_hosts, host, port, key, cert_len, cert_type)) < 0) + return -1; + + cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2; + if (key != NULL) { + cert.type |= GIT_CERT_SSH_RAW; + cert.hostkey = key; + cert.hostkey_len = cert_len; + switch (cert_type) { + case LIBSSH2_HOSTKEY_TYPE_RSA: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_RSA; + break; + case LIBSSH2_HOSTKEY_TYPE_DSS: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_DSS; + break; + +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256; + break; + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384; + break; + case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521; + break; +#endif + +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 + case LIBSSH2_HOSTKEY_TYPE_ED25519: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ED25519; + break; +#endif + default: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_UNKNOWN; + } + } + +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_SHA256; + memcpy(&cert.hash_sha256, key, 32); + } +#endif + + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_SHA1; + memcpy(&cert.hash_sha1, key, 20); + } + + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_MD5; + memcpy(&cert.hash_md5, key, 16); + } + + if (cert.type == 0) { + git_error_set(GIT_ERROR_SSH, "unable to get the host key"); + return -1; + } + + git_error_clear(); + error = 0; + if (!cert_valid) { + git_error_set(GIT_ERROR_SSH, "invalid or unknown remote ssh hostkey"); + error = GIT_ECERTIFICATE; + } + + if (check_cb != NULL) { + git_cert_hostkey *cert_ptr = &cert; + git_error_state previous_error = {0}; + + git_error_state_capture(&previous_error, error); + error = check_cb((git_cert *) cert_ptr, cert_valid, host, check_cb_payload); + if (error == GIT_PASSTHROUGH) { + error = git_error_state_restore(&previous_error); + } else if (error < 0 && !git_error_last()) { + git_error_set(GIT_ERROR_NET, "unknown remote host key"); + } + + git_error_state_free(&previous_error); + } + + return error; +} + +#define SSH_DEFAULT_PORT "22" + +static int _git_ssh_setup_conn( + ssh_subtransport *t, + const char *url, + const char *cmd, + git_smart_subtransport_stream **stream) +{ + int auth_methods, error = 0, port; + ssh_stream *s; + git_credential *cred = NULL; + LIBSSH2_SESSION *session=NULL; + LIBSSH2_CHANNEL *channel=NULL; + LIBSSH2_KNOWNHOSTS *known_hosts = NULL; + + t->current_stream = NULL; + + *stream = NULL; + if (ssh_stream_alloc(t, cmd, stream) < 0) + return -1; + + s = (ssh_stream *)*stream; + s->session = NULL; + s->channel = NULL; + + if (git_net_str_is_url(url)) + error = git_net_url_parse(&s->url, url); + else + error = git_net_url_parse_scp(&s->url, url); + + if (error < 0) + goto done; + + if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 || + (error = git_stream_connect(s->io)) < 0) + goto done; + + /* + * Try to parse the port as a number, if we can't then fall back to + * default. It would be nice if we could get the port that was resolved + * as part of the stream connection, but that's not something that's + * exposed. + */ + if (git__strntol32(&port, s->url.port, strlen(s->url.port), NULL, 10) < 0) + port = -1; + + if ((error = _git_ssh_session_create(&session, &known_hosts, s->url.host, port, s->io)) < 0) + goto done; + + if ((error = check_certificate(session, known_hosts, t->owner->connect_opts.callbacks.certificate_check, t->owner->connect_opts.callbacks.payload, s->url.host, port)) < 0) + goto done; + + /* we need the username to ask for auth methods */ + if (!s->url.username) { + if ((error = request_creds(&cred, t, NULL, GIT_CREDENTIAL_USERNAME)) < 0) + goto done; + + s->url.username = git__strdup(((git_credential_username *) cred)->username); + cred->free(cred); + cred = NULL; + if (!s->url.username) + goto done; + } else if (s->url.username && s->url.password) { + if ((error = git_credential_userpass_plaintext_new(&cred, s->url.username, s->url.password)) < 0) + goto done; + } + + if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) + goto done; + + error = GIT_EAUTH; + /* if we already have something to try */ + if (cred && auth_methods & cred->credtype) + error = _git_ssh_authenticate_session(session, cred); + + while (error == GIT_EAUTH) { + if (cred) { + cred->free(cred); + cred = NULL; + } + + if ((error = request_creds(&cred, t, s->url.username, auth_methods)) < 0) + goto done; + + if (strcmp(s->url.username, git_credential_get_username(cred))) { + git_error_set(GIT_ERROR_SSH, "username does not match previous request"); + error = -1; + goto done; + } + + error = _git_ssh_authenticate_session(session, cred); + + if (error == GIT_EAUTH) { + /* refresh auth methods */ + if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) + goto done; + else + error = GIT_EAUTH; + } + } + + if (error < 0) + goto done; + + channel = libssh2_channel_open_session(session); + if (!channel) { + error = -1; + ssh_error(session, "Failed to open SSH channel"); + goto done; + } + + libssh2_channel_set_blocking(channel, 1); + + s->session = session; + s->channel = channel; + + t->current_stream = s; + +done: + if (known_hosts) + libssh2_knownhost_free(known_hosts); + + if (error < 0) { + ssh_stream_free(*stream); + + if (session) + libssh2_session_free(session); + } + + if (cred) + cred->free(cred); + + return error; +} + +static int ssh_uploadpack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + const char *cmd = t->cmd_uploadpack ? t->cmd_uploadpack : cmd_uploadpack; + + return _git_ssh_setup_conn(t, url, cmd, stream); +} + +static int ssh_uploadpack( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + GIT_UNUSED(url); + + if (t->current_stream) { + *stream = &t->current_stream->parent; + return 0; + } + + git_error_set(GIT_ERROR_NET, "must call UPLOADPACK_LS before UPLOADPACK"); + return -1; +} + +static int ssh_receivepack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + const char *cmd = t->cmd_receivepack ? t->cmd_receivepack : cmd_receivepack; + + + return _git_ssh_setup_conn(t, url, cmd, stream); +} + +static int ssh_receivepack( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + GIT_UNUSED(url); + + if (t->current_stream) { + *stream = &t->current_stream->parent; + return 0; + } + + git_error_set(GIT_ERROR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK"); + return -1; +} + +static int _ssh_action( + git_smart_subtransport_stream **stream, + git_smart_subtransport *subtransport, + const char *url, + git_smart_service_t action) +{ + ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); + + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + return ssh_uploadpack_ls(t, url, stream); + + case GIT_SERVICE_UPLOADPACK: + return ssh_uploadpack(t, url, stream); + + case GIT_SERVICE_RECEIVEPACK_LS: + return ssh_receivepack_ls(t, url, stream); + + case GIT_SERVICE_RECEIVEPACK: + return ssh_receivepack(t, url, stream); + } + + *stream = NULL; + return -1; +} + +static int _ssh_close(git_smart_subtransport *subtransport) +{ + ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); + + GIT_ASSERT(!t->current_stream); + + GIT_UNUSED(t); + + return 0; +} + +static void _ssh_free(git_smart_subtransport *subtransport) +{ + ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); + + git__free(t->cmd_uploadpack); + git__free(t->cmd_receivepack); + git__free(t); +} + +#define SSH_AUTH_PUBLICKEY "publickey" +#define SSH_AUTH_PASSWORD "password" +#define SSH_AUTH_KEYBOARD_INTERACTIVE "keyboard-interactive" + +static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username) +{ + const char *list, *ptr; + + *out = 0; + + list = libssh2_userauth_list(session, username, strlen(username)); + + /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */ + if (list == NULL && !libssh2_userauth_authenticated(session)) { + ssh_error(session, "remote rejected authentication"); + return GIT_EAUTH; + } + + ptr = list; + while (ptr) { + if (*ptr == ',') + ptr++; + + if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) { + *out |= GIT_CREDENTIAL_SSH_KEY; + *out |= GIT_CREDENTIAL_SSH_CUSTOM; +#ifdef GIT_SSH_MEMORY_CREDENTIALS + *out |= GIT_CREDENTIAL_SSH_MEMORY; +#endif + ptr += strlen(SSH_AUTH_PUBLICKEY); + continue; + } + + if (!git__prefixcmp(ptr, SSH_AUTH_PASSWORD)) { + *out |= GIT_CREDENTIAL_USERPASS_PLAINTEXT; + ptr += strlen(SSH_AUTH_PASSWORD); + continue; + } + + if (!git__prefixcmp(ptr, SSH_AUTH_KEYBOARD_INTERACTIVE)) { + *out |= GIT_CREDENTIAL_SSH_INTERACTIVE; + ptr += strlen(SSH_AUTH_KEYBOARD_INTERACTIVE); + continue; + } + + /* Skip it if we don't know it */ + ptr = strchr(ptr, ','); + } + + return 0; +} + +int git_smart_subtransport_ssh_libssh2( + git_smart_subtransport **out, + git_transport *owner, + void *param) +{ + ssh_subtransport *t; + + GIT_ASSERT_ARG(out); + + GIT_UNUSED(param); + + t = git__calloc(sizeof(ssh_subtransport), 1); + GIT_ERROR_CHECK_ALLOC(t); + + t->owner = (transport_smart *)owner; + t->parent.action = _ssh_action; + t->parent.close = _ssh_close; + t->parent.free = _ssh_free; + + *out = (git_smart_subtransport *) t; + return 0; +} + +int git_smart_subtransport_ssh_libssh2_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack) +{ + ssh_subtransport *t = (ssh_subtransport *)subtransport; + + git__free(t->cmd_uploadpack); + git__free(t->cmd_receivepack); + + t->cmd_uploadpack = git__strdup(cmd_uploadpack); + GIT_ERROR_CHECK_ALLOC(t->cmd_uploadpack); + + t->cmd_receivepack = git__strdup(cmd_receivepack); + GIT_ERROR_CHECK_ALLOC(t->cmd_receivepack); + + return 0; +} + +static void shutdown_libssh2(void) +{ + libssh2_exit(); +} + +int git_transport_ssh_libssh2_global_init(void) +{ + if (libssh2_init(0) < 0) { + git_error_set(GIT_ERROR_SSH, "unable to initialize libssh2"); + return -1; + } + + return git_runtime_shutdown_register(shutdown_libssh2); +} + +#else /* GIT_SSH */ + +int git_transport_ssh_libssh2_global_init(void) +{ + return 0; +} + +#endif diff --git a/src/libgit2/transports/ssh_libssh2.h b/src/libgit2/transports/ssh_libssh2.h new file mode 100644 index 00000000000..3f8cc2a8ad9 --- /dev/null +++ b/src/libgit2/transports/ssh_libssh2.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_transports_libssh2_h__ +#define INCLUDE_transports_libssh2_h__ + +#include "common.h" + +#include "git2.h" +#include "git2/transport.h" +#include "git2/sys/transport.h" + +int git_transport_ssh_libssh2_global_init(void); + +int git_smart_subtransport_ssh_libssh2( + git_smart_subtransport **out, + git_transport *owner, + void *param); + +int git_smart_subtransport_ssh_libssh2_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack); + +#endif From 3fccf7468ba7a9a9f764984435db83f4588ec905 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 24 Feb 2023 00:30:50 +0000 Subject: [PATCH 259/816] ssh: GIT_SSH_LIBSSH2 is now distinct from GIT_SSH We may want to support SSH but with a different provider that is not libssh2. Add GIT_SSH to indicate that we have some inbuilt SSH support and GIT_SSH_LIBSSH2 to indicate that support is via libssh2. This is similar to how we support GIT_HTTPS and GIT_OPENSSL, for example. --- CMakeLists.txt | 2 +- cmake/SelectSSH.cmake | 33 ++++++++++++++-------------- src/libgit2/libgit2.c | 4 ++-- src/libgit2/transport.c | 3 +++ src/libgit2/transports/credential.c | 2 +- src/libgit2/transports/ssh.c | 4 ++-- src/libgit2/transports/ssh_libssh2.c | 6 ++--- src/util/git2_features.h.in | 3 ++- tests/libgit2/online/clone.c | 4 ++-- 9 files changed, 32 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81e2bc8aca1..17ca7576834 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ option(USE_THREADS "Use threads for parallel processing when possibl option(USE_NSEC "Support nanosecond precision file mtimes and ctimes" ON) # Backend selection -option(USE_SSH "Link with libssh2 to enable SSH support" OFF) +option(USE_SSH "Enable SSH support. Can be set to a specific backend" OFF) option(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON) option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS" ON) option(USE_SHA256 "Enable SHA256. Can be set to HTTPS/Builtin" ON) diff --git a/cmake/SelectSSH.cmake b/cmake/SelectSSH.cmake index 23dfc978521..ae9619900b6 100644 --- a/cmake/SelectSSH.cmake +++ b/cmake/SelectSSH.cmake @@ -1,6 +1,7 @@ -# Optional external dependency: libssh2 -if(USE_SSH) +# find libssh2 +if(USE_SSH STREQUAL ON OR USE_SSH STREQUAL "libssh2") find_pkglibraries(LIBSSH2 libssh2) + if(NOT LIBSSH2_FOUND) find_package(LibSSH2) set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR}) @@ -12,30 +13,28 @@ if(USE_SSH) if(NOT LIBSSH2_FOUND) message(FATAL_ERROR "LIBSSH2 not found. Set CMAKE_PREFIX_PATH if it is installed outside of the default search path.") endif() -endif() -if(LIBSSH2_FOUND) - set(GIT_SSH 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${LIBSSH2_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${LIBSSH2_LIBRARIES}) list(APPEND LIBGIT2_PC_LIBS ${LIBSSH2_LDFLAGS}) check_library_exists("${LIBSSH2_LIBRARIES}" libssh2_userauth_publickey_frommemory "${LIBSSH2_LIBRARY_DIRS}" HAVE_LIBSSH2_MEMORY_CREDENTIALS) if(HAVE_LIBSSH2_MEMORY_CREDENTIALS) - set(GIT_SSH_MEMORY_CREDENTIALS 1) + set(GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1) endif() -else() - message(STATUS "LIBSSH2 not found. Set CMAKE_PREFIX_PATH if it is installed outside of the default search path.") -endif() -if(WIN32 AND EMBED_SSH_PATH) - file(GLOB SSH_SRC "${EMBED_SSH_PATH}/src/*.c") - list(SORT SSH_SRC) - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS ${SSH_SRC}) + if(WIN32 AND EMBED_SSH_PATH) + file(GLOB SSH_SRC "${EMBED_SSH_PATH}/src/*.c") + list(SORT SSH_SRC) + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS ${SSH_SRC}) + + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${EMBED_SSH_PATH}/include") + file(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"") + endif() - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${EMBED_SSH_PATH}/include") - file(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"") set(GIT_SSH 1) + set(GIT_SSH_LIBSSH2 1) + add_feature_info(SSH ON "using libssh2") +else() + add_feature_info(SSH OFF "SSH transport support") endif() - -add_feature_info(SSH GIT_SSH "SSH transport support") diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 56b90321f4a..ec4a699a2ee 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -126,10 +126,10 @@ int git_libgit2_features(void) #ifdef GIT_HTTPS | GIT_FEATURE_HTTPS #endif -#if defined(GIT_SSH) +#ifdef GIT_SSH | GIT_FEATURE_SSH #endif -#if defined(GIT_USE_NSEC) +#ifdef GIT_USE_NSEC | GIT_FEATURE_NSEC #endif ; diff --git a/src/libgit2/transport.c b/src/libgit2/transport.c index 640ccacaee3..c61d0a68b7e 100644 --- a/src/libgit2/transport.c +++ b/src/libgit2/transport.c @@ -22,6 +22,7 @@ typedef struct transport_definition { static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1, NULL }; static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0, NULL }; + #ifdef GIT_SSH static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0, NULL }; #endif @@ -33,11 +34,13 @@ static transport_definition transports[] = { { "http://", git_transport_smart, &http_subtransport_definition }, { "https://", git_transport_smart, &http_subtransport_definition }, { "file://", git_transport_local, NULL }, + #ifdef GIT_SSH { "ssh://", git_transport_smart, &ssh_subtransport_definition }, { "ssh+git://", git_transport_smart, &ssh_subtransport_definition }, { "git+ssh://", git_transport_smart, &ssh_subtransport_definition }, #endif + { NULL, 0, 0 } }; diff --git a/src/libgit2/transports/credential.c b/src/libgit2/transports/credential.c index 6e00b028243..b47bd63a198 100644 --- a/src/libgit2/transports/credential.c +++ b/src/libgit2/transports/credential.c @@ -204,7 +204,7 @@ int git_credential_ssh_key_memory_new( const char *privatekey, const char *passphrase) { -#ifdef GIT_SSH_MEMORY_CREDENTIALS +#ifdef GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS return git_credential_ssh_key_type_new( cred, username, diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c index bef0b14409f..7171e9cb3a8 100644 --- a/src/libgit2/transports/ssh.c +++ b/src/libgit2/transports/ssh.c @@ -14,7 +14,7 @@ int git_smart_subtransport_ssh( git_transport *owner, void *param) { -#ifdef GIT_SSH +#ifdef GIT_SSH_LIBSSH2 return git_smart_subtransport_ssh_libssh2(out, owner, param); #else GIT_UNUSED(out); @@ -31,7 +31,7 @@ int git_transport_ssh_with_paths( git_remote *owner, void *payload) { -#ifdef GIT_SSH +#ifdef GIT_SSH_LIBSSH2 git_strarray *paths = (git_strarray *) payload; git_transport *transport; transport_smart *smart; diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index 154d022944b..76c08c2e1a5 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -7,7 +7,7 @@ #include "ssh_libssh2.h" -#ifdef GIT_SSH +#ifdef GIT_SSH_LIBSSH2 #include @@ -342,7 +342,7 @@ static int _git_ssh_authenticate_session( session, c->username, c->prompt_callback); break; } -#ifdef GIT_SSH_MEMORY_CREDENTIALS +#ifdef GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS case GIT_CREDENTIAL_SSH_MEMORY: { git_credential_ssh_key *c = (git_credential_ssh_key *)cred; @@ -1020,7 +1020,7 @@ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *use if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) { *out |= GIT_CREDENTIAL_SSH_KEY; *out |= GIT_CREDENTIAL_SSH_CUSTOM; -#ifdef GIT_SSH_MEMORY_CREDENTIALS +#ifdef GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS *out |= GIT_CREDENTIAL_SSH_MEMORY; #endif ptr += strlen(SSH_AUTH_PUBLICKEY); diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index a84ea895635..21399116df0 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -30,7 +30,8 @@ #cmakedefine GIT_QSORT_MSC #cmakedefine GIT_SSH 1 -#cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1 +#cmakedefine GIT_SSH_LIBSSH2 1 +#cmakedefine GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1 #cmakedefine GIT_NTLM 1 #cmakedefine GIT_GSSAPI 1 diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 5789e9654c3..ea47b89985a 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -675,7 +675,7 @@ void test_online_clone__ssh_auth_methods(void) */ void test_online_clone__ssh_certcheck_accepts_unknown(void) { -#if !defined(GIT_SSH) || !defined(GIT_SSH_MEMORY_CREDENTIALS) +#if !defined(GIT_SSH_LIBSSH2) || !defined(GIT_SSH_MEMORY_CREDENTIALS) clar__skip(); #endif @@ -793,7 +793,7 @@ static int cred_foo_bar(git_credential **cred, const char *url, const char *user void test_online_clone__ssh_cannot_change_username(void) { -#ifndef GIT_SSH +#ifndef GIT_SSH_LIBSSH2 clar__skip(); #endif g_options.fetch_opts.callbacks.credentials = cred_foo_bar; From a8b052faab34db9d8b8a4ea620545a8155e06bed Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 24 Feb 2023 00:34:06 +0000 Subject: [PATCH 260/816] ssh: introduce GIT_SSH_EXEC for external OpenSSH We can now use the `git_process` class to invoke OpenSSH and use it as an SSH transport. This may be preferred over libssh2 for a variety of callers. --- cmake/SelectSSH.cmake | 8 +- src/libgit2/transports/ssh.c | 3 + src/libgit2/transports/ssh_exec.c | 273 ++++++++++++++++++++++++++++++ src/libgit2/transports/ssh_exec.h | 26 +++ src/util/git2_features.h.in | 1 + 5 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 src/libgit2/transports/ssh_exec.c create mode 100644 src/libgit2/transports/ssh_exec.h diff --git a/cmake/SelectSSH.cmake b/cmake/SelectSSH.cmake index ae9619900b6..079857f502b 100644 --- a/cmake/SelectSSH.cmake +++ b/cmake/SelectSSH.cmake @@ -1,5 +1,9 @@ -# find libssh2 -if(USE_SSH STREQUAL ON OR USE_SSH STREQUAL "libssh2") +if(USE_SSH STREQUAL "exec") + set(GIT_SSH 1) + set(GIT_SSH_EXEC 1) + + add_feature_info(SSH ON "using OpenSSH exec support") +elseif(USE_SSH STREQUAL ON OR USE_SSH STREQUAL "libssh2") find_pkglibraries(LIBSSH2 libssh2) if(NOT LIBSSH2_FOUND) diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c index 7171e9cb3a8..98e1be2d131 100644 --- a/src/libgit2/transports/ssh.c +++ b/src/libgit2/transports/ssh.c @@ -5,6 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ +#include "ssh_exec.h" #include "ssh_libssh2.h" #include "transports/smart.h" @@ -16,6 +17,8 @@ int git_smart_subtransport_ssh( { #ifdef GIT_SSH_LIBSSH2 return git_smart_subtransport_ssh_libssh2(out, owner, param); +#elif GIT_SSH_EXEC + return git_smart_subtransport_ssh_exec(out, owner, param); #else GIT_UNUSED(out); GIT_UNUSED(owner); diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c new file mode 100644 index 00000000000..2b2c8a08eb2 --- /dev/null +++ b/src/libgit2/transports/ssh_exec.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "ssh_exec.h" + +#ifdef GIT_SSH_EXEC + +#include "common.h" + +#include "net.h" +#include "path.h" +#include "futils.h" +#include "process.h" + +typedef struct { + git_smart_subtransport_stream parent; +} ssh_exec_subtransport_stream; + +typedef struct { + git_smart_subtransport parent; + git_transport *owner; + + ssh_exec_subtransport_stream *current_stream; + + git_smart_service_t action; + git_process *process; +} ssh_exec_subtransport; + +static int ssh_exec_subtransport_stream_read( + git_smart_subtransport_stream *s, + char *buffer, + size_t buf_size, + size_t *bytes_read) +{ + ssh_exec_subtransport *transport; + ssh_exec_subtransport_stream *stream = (ssh_exec_subtransport_stream *)s; + ssize_t ret; + + GIT_ASSERT_ARG(stream); + GIT_ASSERT(stream->parent.subtransport); + + transport = (ssh_exec_subtransport *)stream->parent.subtransport; + + if ((ret = git_process_read(transport->process, buffer, buf_size)) < 0) + return (int)ret; + + *bytes_read = (size_t)ret; + return 0; +} + +static int ssh_exec_subtransport_stream_write( + git_smart_subtransport_stream *s, + const char *buffer, + size_t len) +{ + ssh_exec_subtransport *transport; + ssh_exec_subtransport_stream *stream = (ssh_exec_subtransport_stream *)s; + ssize_t ret; + + GIT_ASSERT(stream && stream->parent.subtransport); + + transport = (ssh_exec_subtransport *)stream->parent.subtransport; + + while (len > 0) { + if ((ret = git_process_write(transport->process, buffer, len)) < 0) + return (int)ret; + + len -= ret; + } + + return 0; +} + +static void ssh_exec_subtransport_stream_free(git_smart_subtransport_stream *s) +{ + ssh_exec_subtransport_stream *stream = (ssh_exec_subtransport_stream *)s; + + git__free(stream); +} + +static int ssh_exec_subtransport_stream_init( + ssh_exec_subtransport_stream **out, + ssh_exec_subtransport *transport) +{ + GIT_ASSERT_ARG(out); + + *out = git__calloc(sizeof(ssh_exec_subtransport_stream), 1); + GIT_ERROR_CHECK_ALLOC(*out); + + (*out)->parent.subtransport = &transport->parent; + (*out)->parent.read = ssh_exec_subtransport_stream_read; + (*out)->parent.write = ssh_exec_subtransport_stream_write; + (*out)->parent.free = ssh_exec_subtransport_stream_free; + + return 0; +} + +GIT_INLINE(int) ensure_transport_state( + ssh_exec_subtransport *transport, + git_smart_service_t expected, + git_smart_service_t next) +{ + if (transport->action != expected && transport->action != next) { + git_error_set(GIT_ERROR_NET, "invalid transport state"); + + return -1; + } + + return 0; +} + +static int start_ssh( + ssh_exec_subtransport *transport, + git_smart_service_t action, + const char *sshpath) +{ + const char *args[6]; + const char *env[] = { "GIT_DIR=" }; + + git_process_options process_opts = GIT_PROCESS_OPTIONS_INIT; + git_net_url url = GIT_NET_URL_INIT; + git_str userhost = GIT_STR_INIT; + const char *command; + int error; + + process_opts.capture_in = 1; + process_opts.capture_out = 1; + process_opts.capture_err = 1; + + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + command = "git-upload-pack"; + break; + case GIT_SERVICE_RECEIVEPACK_LS: + command = "git-receive-pack"; + break; + default: + git_error_set(GIT_ERROR_NET, "invalid action"); + error = -1; + goto done; + } + + if (git_net_str_is_url(sshpath)) + error = git_net_url_parse(&url, sshpath); + else + error = git_net_url_parse_scp(&url, sshpath); + + if (error < 0) + goto done; + + if (url.username) { + git_str_puts(&userhost, url.username); + git_str_putc(&userhost, '@'); + } + git_str_puts(&userhost, url.host); + + args[0] = "/usr/bin/ssh"; + args[1] = "-p"; + args[2] = url.port; + args[3] = userhost.ptr; + args[4] = command; + args[5] = url.path; + + if ((error = git_process_new(&transport->process, args, ARRAY_SIZE(args), env, ARRAY_SIZE(env), &process_opts)) < 0 || + (error = git_process_start(transport->process)) < 0) { + git_process_free(transport->process); + transport->process = NULL; + goto done; + } + +done: + git_str_dispose(&userhost); + git_net_url_dispose(&url); + return error; +} + +static int ssh_exec_subtransport_action( + git_smart_subtransport_stream **out, + git_smart_subtransport *t, + const char *sshpath, + git_smart_service_t action) +{ + ssh_exec_subtransport *transport = (ssh_exec_subtransport *)t; + ssh_exec_subtransport_stream *stream = NULL; + git_smart_service_t expected; + int error; + + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + case GIT_SERVICE_RECEIVEPACK_LS: + if ((error = ensure_transport_state(transport, 0, 0)) < 0 || + (error = ssh_exec_subtransport_stream_init(&stream, transport)) < 0 || + (error = start_ssh(transport, action, sshpath)) < 0) + goto on_error; + + transport->current_stream = stream; + break; + + case GIT_SERVICE_UPLOADPACK: + case GIT_SERVICE_RECEIVEPACK: + expected = (action == GIT_SERVICE_UPLOADPACK) ? + GIT_SERVICE_UPLOADPACK_LS : GIT_SERVICE_RECEIVEPACK_LS; + + if ((error = ensure_transport_state(transport, expected, action)) < 0) + goto on_error; + + break; + + default: + git_error_set(GIT_ERROR_INVALID, "invalid service request"); + goto on_error; + } + + transport->action = action; + *out = &transport->current_stream->parent; + + return 0; + +on_error: + if (stream != NULL) + ssh_exec_subtransport_stream_free(&stream->parent); + + return -1; +} + +static int ssh_exec_subtransport_close(git_smart_subtransport *t) +{ + ssh_exec_subtransport *transport = (ssh_exec_subtransport *)t; + + if (transport->process) { + git_process_close(transport->process); + git_process_free(transport->process); + transport->process = NULL; + } + + transport->action = 0; + + return 0; +} + +static void ssh_exec_subtransport_free(git_smart_subtransport *t) +{ + ssh_exec_subtransport *transport = (ssh_exec_subtransport *)t; + + git__free(transport); +} + +int git_smart_subtransport_ssh_exec( + git_smart_subtransport **out, + git_transport *owner, + void *payload) +{ + ssh_exec_subtransport *transport; + + GIT_UNUSED(payload); + + transport = git__calloc(sizeof(ssh_exec_subtransport), 1); + GIT_ERROR_CHECK_ALLOC(transport); + + transport->owner = owner; + transport->parent.action = ssh_exec_subtransport_action; + transport->parent.close = ssh_exec_subtransport_close; + transport->parent.free = ssh_exec_subtransport_free; + + *out = (git_smart_subtransport *) transport; + return 0; +} + +#endif diff --git a/src/libgit2/transports/ssh_exec.h b/src/libgit2/transports/ssh_exec.h new file mode 100644 index 00000000000..4bcba06b16b --- /dev/null +++ b/src/libgit2/transports/ssh_exec.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_transports_ssh_exec_h__ +#define INCLUDE_transports_ssh_exec_h__ + +#include "common.h" + +#include "git2.h" +#include "git2/transport.h" +#include "git2/sys/transport.h" + +int git_smart_subtransport_ssh_exec( + git_smart_subtransport **out, + git_transport *owner, + void *param); + +int git_smart_subtransport_ssh_exec_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack); + +#endif diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 21399116df0..a328f77cb00 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -30,6 +30,7 @@ #cmakedefine GIT_QSORT_MSC #cmakedefine GIT_SSH 1 +#cmakedefine GIT_SSH_EXEC 1 #cmakedefine GIT_SSH_LIBSSH2 1 #cmakedefine GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1 From 38b16b01e36936c697a0a3a6d8076936f4a443a0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 27 Mar 2023 12:08:19 +0100 Subject: [PATCH 261/816] ci: split ssh into exec and libssh2 --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84d476f78dc..eba3b055a6d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,40 +25,40 @@ jobs: strategy: matrix: platform: - - name: "Linux (Xenial, GCC, OpenSSL)" + - name: "Linux (Xenial, GCC, OpenSSL, libssh2)" id: xenial-gcc-openssl container: name: xenial env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON os: ubuntu-latest - - name: Linux (Xenial, GCC, mbedTLS) + - name: Linux (Xenial, GCC, mbedTLS, OpenSSH) id: xenial-gcc-mbedtls container: name: xenial env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec os: ubuntu-latest - - name: "Linux (Xenial, Clang, OpenSSL)" + - name: "Linux (Xenial, Clang, OpenSSL, OpenSSH)" id: xenial-clang-openssl container: name: xenial env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec os: ubuntu-latest - - name: "Linux (Xenial, Clang, mbedTLS)" + - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" id: xenial-clang-mbedtls container: name: xenial env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 CMAKE_GENERATOR: Ninja os: ubuntu-latest - name: "macOS" From 7a8c4d8bd2b619061e432b021d9bfb1a6858637d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 27 Mar 2023 17:31:51 +0100 Subject: [PATCH 262/816] process: test SIGTERM detection We can't reliably detect SIGPIPE on close because of platform differences. Track `pid` and send `SIGTERM` to a function and ensure that we can detect it. --- src/util/process.h | 15 ++++++++++++++ src/util/unix/process.c | 13 +++++++++++++ src/util/win32/process.c | 13 +++++++++++++ tests/util/process/start.c | 40 +++++++++++++++++++++++++++++++++++--- 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/util/process.h b/src/util/process.h index 55b2a104934..81081d10356 100644 --- a/src/util/process.h +++ b/src/util/process.h @@ -35,6 +35,12 @@ typedef struct { #define GIT_PROCESS_OPTIONS_INIT { 0 } +#ifdef GIT_WIN32 +# define p_pid_t DWORD +#else +# define p_pid_t pid_t +#endif + /** * Create a new process. The command to run should be specified as the * element of the `arg` array. @@ -79,6 +85,15 @@ extern int git_process__cmdline( */ extern int git_process_start(git_process *process); +/** + * Returns the process id of the process. + * + * @param out pointer to a pid_t to store the process id + * @param process the process to query + * @return 0 or an error code + */ +extern int git_process_id(p_pid_t *out, git_process *process); + /** * Read from the process's stdout. The process must have been created with * `capture_out` set to true. diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 16171aec94c..3d734ffb53a 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -356,6 +356,19 @@ int git_process_start(git_process *process) return -1; } +int git_process_id(p_pid_t *out, git_process *process) +{ + GIT_ASSERT(out && process); + + if (!process->pid) { + git_error_set(GIT_ERROR_INVALID, "process not running"); + return -1; + } + + *out = process->pid; + return 0; +} + ssize_t git_process_read(git_process *process, void *buf, size_t count) { ssize_t ret; diff --git a/src/util/win32/process.c b/src/util/win32/process.c index 6b8dd084015..932119ab95e 100644 --- a/src/util/win32/process.c +++ b/src/util/win32/process.c @@ -292,6 +292,19 @@ int git_process_start(git_process *process) return -1; } +int git_process_id(p_pid_t *out, git_process *process) +{ + GIT_ASSERT(out && process); + + if (!process->process_info.dwProcessId) { + git_error_set(GIT_ERROR_INVALID, "process not running"); + return -1; + } + + *out = process->process_info.dwProcessId; + return 0; +} + ssize_t git_process_read(git_process *process, void *buf, size_t count) { DWORD ret; diff --git a/tests/util/process/start.c b/tests/util/process/start.c index 0e4944b6567..d130c7efbbb 100644 --- a/tests/util/process/start.c +++ b/tests/util/process/start.c @@ -2,6 +2,14 @@ #include "process.h" #include "vector.h" +#ifndef GIT_WIN32 +# include +#endif + +#ifndef SIGTERM +# define SIGTERM 42 +#endif + #ifndef SIGPIPE # define SIGPIPE 42 #endif @@ -130,9 +138,35 @@ void test_process_start__redirect_stdio(void) git_process_free(process); } -void test_process_start__catch_signal(void) +/* +void test_process_start__catch_sigterm(void) +{ + const char *args_array[] = { "/bin/cat" }; + + git_process *process; + git_process_options opts = GIT_PROCESS_OPTIONS_INIT; + git_process_result result = GIT_PROCESS_RESULT_INIT; + p_pid_t pid; + + opts.capture_out = 1; + + cl_git_pass(git_process_new(&process, args_array, ARRAY_SIZE(args_array), NULL, 0, &opts)); + cl_git_pass(git_process_start(process)); + cl_git_pass(git_process_id(&pid, process)); + + cl_must_pass(kill(pid, SIGTERM)); + + cl_git_pass(git_process_wait(&result, process)); + + cl_assert_equal_i(GIT_PROCESS_STATUS_ERROR, result.status); + cl_assert_equal_i(0, result.exitcode); + cl_assert_equal_i(SIGTERM, result.signal); + + git_process_free(process); +} + +void test_process_start__catch_sigpipe(void) { -#ifndef GIT_WIN32 const char *args_array[] = { helloworld_cmd.ptr }; git_process *process; @@ -151,8 +185,8 @@ void test_process_start__catch_signal(void) cl_assert_equal_i(SIGPIPE, result.signal); git_process_free(process); -#endif } +*/ void test_process_start__can_chdir(void) { From cf133a82217a2f22349a6b8bc7cc0227420025d5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 May 2023 10:44:02 +0100 Subject: [PATCH 263/816] tests: use cl_fail_with correctly --- tests/libgit2/online/clone.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index ea47b89985a..e2ddd6428e6 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -908,12 +908,12 @@ void test_online_clone__certificate_invalid(void) { g_options.fetch_opts.callbacks.certificate_check = fail_certificate_check; - cl_git_fail_with(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options), - GIT_ECERTIFICATE); + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options)); #ifdef GIT_SSH - cl_git_fail_with(git_clone(&g_repo, "ssh://github.com/libgit2/TestGitRepository", "./foo", &g_options), - GIT_ECERTIFICATE); + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "ssh://github.com/libgit2/TestGitRepository", "./foo", &g_options)); #endif } From 10fbb5c940d7712c8e81e0099823808424e0c41c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 May 2023 10:47:13 +0100 Subject: [PATCH 264/816] ssh: only test callbacks for libssh2 There are no custom callbacks for OpenSSH; don't test them. --- tests/libgit2/online/clone.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index e2ddd6428e6..1dc76d507a4 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -653,7 +653,7 @@ void test_online_clone__ssh_auth_methods(void) { int with_user; -#ifndef GIT_SSH +#ifndef GIT_SSH_LIBSSH2 clar__skip(); #endif g_options.fetch_opts.callbacks.credentials = check_ssh_auth_methods; @@ -796,6 +796,7 @@ void test_online_clone__ssh_cannot_change_username(void) #ifndef GIT_SSH_LIBSSH2 clar__skip(); #endif + g_options.fetch_opts.callbacks.credentials = cred_foo_bar; cl_git_fail(git_clone(&g_repo, "ssh://git@github.com/libgit2/TestGitRepository", "./foo", &g_options)); @@ -837,6 +838,10 @@ static int ssh_certificate_check(git_cert *cert, int valid, const char *host, vo void test_online_clone__ssh_cert(void) { +#ifndef GIT_SSH_LIBSSH2 + cl_skip(); +#endif + g_options.fetch_opts.callbacks.certificate_check = ssh_certificate_check; if (!_remote_ssh_fingerprint) @@ -911,7 +916,7 @@ void test_online_clone__certificate_invalid(void) cl_git_fail_with(GIT_ECERTIFICATE, git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options)); -#ifdef GIT_SSH +#ifdef GIT_SSH_LIBSSH2 cl_git_fail_with(GIT_ECERTIFICATE, git_clone(&g_repo, "ssh://github.com/libgit2/TestGitRepository", "./foo", &g_options)); #endif From a283c1bd1b0b66b9bc0c5b3c66bcfe8ea221701d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 May 2023 11:17:46 +0100 Subject: [PATCH 265/816] ci: valgrind shouldn't report on exited children Now that we (may) exec a child process to do ssh, we don't want valgrind reporting on that. Suppress children in valgrind runs. --- script/valgrind.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/valgrind.sh b/script/valgrind.sh index b5deed2b06e..aacd767a7c8 100755 --- a/script/valgrind.sh +++ b/script/valgrind.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec valgrind --leak-check=full --show-reachable=yes --error-exitcode=125 --num-callers=50 --suppressions="$(dirname "${BASH_SOURCE[0]}")/valgrind.supp" "$@" +exec valgrind --leak-check=full --show-reachable=yes --child-silent-after-fork=yes --error-exitcode=125 --num-callers=50 --suppressions="$(dirname "${BASH_SOURCE[0]}")/valgrind.supp" "$@" From 1c72c59aa5e6af4e051025b06afde4bb558a7aa6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 May 2023 10:35:59 +0100 Subject: [PATCH 266/816] smart: don't assume directionality A transport may want to validate that it's in a sane state; when flushing on close, don't assume that we're doing an upload-pack; send the correct direction. --- src/libgit2/transports/smart.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index 53727282850..fe3fe970ae1 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -370,17 +370,27 @@ static int git_smart__close(git_transport *transport) git_vector *common = &t->common; unsigned int i; git_pkt *p; + git_smart_service_t service; int ret; git_smart_subtransport_stream *stream; const char flush[] = "0000"; + if (t->direction == GIT_DIRECTION_FETCH) { + service = GIT_SERVICE_UPLOADPACK; + } else if (t->direction == GIT_DIRECTION_PUSH) { + service = GIT_SERVICE_RECEIVEPACK; + } else { + git_error_set(GIT_ERROR_NET, "invalid direction"); + return -1; + } + /* * If we're still connected at this point and not using RPC, * we should say goodbye by sending a flush, or git-daemon * will complain that we disconnected unexpectedly. */ if (t->connected && !t->rpc && - !t->wrapped->action(&stream, t->wrapped, t->url, GIT_SERVICE_UPLOADPACK)) { + !t->wrapped->action(&stream, t->wrapped, t->url, service)) { t->current_stream->write(t->current_stream, flush, 4); } From 0e6261551516b28680e0632beee081552a0e2fc2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 May 2023 10:36:33 +0100 Subject: [PATCH 267/816] smart: unique error messages Instead of "early EOF", provide information on _when_ we're seeing the EOF for debugging. --- src/libgit2/transports/smart_protocol.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index c9c422d4c85..9646abb705b 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -59,7 +59,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) return recvd; if (recvd == 0) { - git_error_set(GIT_ERROR_NET, "early EOF"); + git_error_set(GIT_ERROR_NET, "early EOF receiving refs"); return GIT_EEOF; } @@ -285,7 +285,7 @@ static int recv_pkt( if ((ret = git_smart__recv(t)) < 0) { return ret; } else if (ret == 0) { - git_error_set(GIT_ERROR_NET, "early EOF"); + git_error_set(GIT_ERROR_NET, "early EOF receiving packet"); return GIT_EEOF; } } while (error); @@ -940,7 +940,7 @@ static int parse_report(transport_smart *transport, git_push *push) } if (recvd == 0) { - git_error_set(GIT_ERROR_NET, "early EOF"); + git_error_set(GIT_ERROR_NET, "early EOF receiving report"); error = GIT_EEOF; goto done; } From ac07db3fb706f891880ae2666e89e57a2ee59c4e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 May 2023 11:57:46 +0100 Subject: [PATCH 268/816] process: sigpipe suppression Suppress SIGPIPEs during writes to our piped process. On single-threaded applications, this is as simple as ignoring the signal. But since this is process-wide, on multi-threaded applications, we need to use some cumbersome `pthread_sigmask` manipulation. Thanks to https://www.doof.me.uk/2020/09/23/sigpipe-and-how-to-ignore-it/ and http://www.microhowto.info:80/howto/ignore_sigpipe_without_affecting_other_threads_in_a_process.html --- src/util/unix/process.c | 93 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 3 deletions(-) diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 3d734ffb53a..08499e24cc8 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -7,6 +7,7 @@ #include #include +#include #include #include "git2_util.h" @@ -387,8 +388,90 @@ ssize_t git_process_read(git_process *process, void *buf, size_t count) return ret; } +#ifdef GIT_THREADS + +# define signal_state sigset_t + +/* + * Since signal-handling is process-wide, we cannot simply use + * SIG_IGN to avoid SIGPIPE. Instead: http://www.microhowto.info:80/howto/ignore_sigpipe_without_affecting_other_threads_in_a_process.html + */ + +GIT_INLINE(int) disable_signals(sigset_t *saved_mask) +{ + sigset_t sigpipe_mask; + + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, saved_mask) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal mask"); + return -1; + } + + return 0; +} + +GIT_INLINE(int) restore_signals(sigset_t *saved_mask) +{ + sigset_t sigpipe_mask, pending; + int signal; + + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + + if (sigpending(&pending) < 0) { + git_error_set(GIT_ERROR_OS, "could not examine pending signals"); + return -1; + } + + if (sigismember(&pending, SIGPIPE) == 1 && + sigwait(&sigpipe_mask, &signal) < 0) { + git_error_set(GIT_ERROR_OS, "could not wait for (blocking) signal delivery"); + return -1; + } + + if (pthread_sigmask(SIG_SETMASK, saved_mask, 0) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal mask"); + return -1; + } + + return 0; +} + +#else + +# define signal_state struct sigaction + +GIT_INLINE(int) disable_signals(struct sigaction *saved_handler) +{ + struct sigaction ign_handler = { 0 }; + + ign_handler.sa_handler = SIG_IGN; + + if (sigaction(SIGPIPE, &ign_handler, saved_handler) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal handler"); + return -1; + } + + return 0; +} + +GIT_INLINE(int) restore_signals(struct sigaction *saved_handler) +{ + if (sigaction(SIGPIPE, saved_handler, NULL) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal handler"); + return -1; + } + + return 0; +} + +#endif + ssize_t git_process_write(git_process *process, const void *buf, size_t count) { + signal_state saved_signal; ssize_t ret; GIT_ASSERT_ARG(process); @@ -397,12 +480,16 @@ ssize_t git_process_write(git_process *process, const void *buf, size_t count) if (count > SSIZE_MAX) count = SSIZE_MAX; - if ((ret = write(process->child_in, buf, count)) < 0) { + if (disable_signals(&saved_signal) < 0) + return -1; + + if ((ret = write(process->child_in, buf, count)) < 0) git_error_set(GIT_ERROR_OS, "could not write to child process"); + + if (restore_signals(&saved_signal) < 0) return -1; - } - return ret; + return (ret < 0) ? -1 : ret; } int git_process_close_in(git_process *process) From 18474f7d699fc2d22ec217d620bb6a9fc5cac130 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 20 May 2023 15:59:28 +0100 Subject: [PATCH 269/816] process: reader for stderr Provide a mechanism for callers to read from stderr. --- src/util/process.h | 11 +++++++++++ src/util/unix/process.c | 35 ++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/util/process.h b/src/util/process.h index 81081d10356..816be67fd98 100644 --- a/src/util/process.h +++ b/src/util/process.h @@ -105,6 +105,17 @@ extern int git_process_id(p_pid_t *out, git_process *process); */ extern ssize_t git_process_read(git_process *process, void *buf, size_t count); +/** + * Read from the process's stderr. The process must have been created with + * `capture_err` set to true. + * + * @param process the process to read from + * @param buf the buf to read into + * @param count maximum number of bytes to read + * @return number of bytes read or an error code + */ +extern ssize_t git_process_read_err(git_process *process, void *buf, size_t count); + /** * Write to the process's stdin. The process must have been created with * `capture_in` set to true. diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 08499e24cc8..523e52f3156 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -152,7 +152,7 @@ int git_process_new( fd = -1; \ } -static int try_read(size_t *out, int fd, void *buf, size_t len) +static int try_read_status(size_t *out, int fd, void *buf, size_t len) { size_t read_len = 0; int ret = -1; @@ -179,7 +179,7 @@ static int read_status(int fd) char buffer[status_len], fn[128]; int error, fn_error, os_error, fn_len = 0; - if ((error = try_read(&read_len, fd, buffer, status_len)) < 0) + if ((error = try_read_status(&read_len, fd, buffer, status_len)) < 0) return error; /* Immediate EOF indicates the exec succeeded. */ @@ -198,7 +198,7 @@ static int read_status(int fd) if (fn_len > 0) { fn_len = min(fn_len, (int)(ARRAY_SIZE(fn) - 1)); - if ((error = try_read(&read_len, fd, fn, fn_len)) < 0) + if ((error = try_read_status(&read_len, fd, fn, fn_len)) < 0) return error; fn[fn_len] = '\0'; @@ -214,7 +214,7 @@ static int read_status(int fd) return fn_error; } -static bool try_write(int fd, const void *buf, size_t len) +static bool try_write_status(int fd, const void *buf, size_t len) { size_t write_len; int ret; @@ -246,11 +246,11 @@ static void write_status(int fd, const char *fn, int error, int os_error) memcpy(&buffer[sizeof(int) * 2], &fn_len, sizeof(int)); /* Do our best effort to write all the status. */ - if (!try_write(fd, buffer, status_len)) + if (!try_write_status(fd, buffer, status_len)) return; if (fn_len) - try_write(fd, fn, fn_len); + try_write_status(fd, fn, fn_len); } int git_process_start(git_process *process) @@ -370,17 +370,14 @@ int git_process_id(p_pid_t *out, git_process *process) return 0; } -ssize_t git_process_read(git_process *process, void *buf, size_t count) +static ssize_t process_read(int fd, void *buf, size_t count) { ssize_t ret; - GIT_ASSERT_ARG(process); - GIT_ASSERT(process->capture_out); - if (count > SSIZE_MAX) count = SSIZE_MAX; - if ((ret = read(process->child_out, buf, count)) < 0) { + if ((ret = read(fd, buf, count)) < 0) { git_error_set(GIT_ERROR_OS, "could not read from child process"); return -1; } @@ -388,6 +385,22 @@ ssize_t git_process_read(git_process *process, void *buf, size_t count) return ret; } +ssize_t git_process_read(git_process *process, void *buf, size_t count) +{ + GIT_ASSERT_ARG(process); + GIT_ASSERT(process->capture_out); + + return process_read(process->child_out, buf, count); +} + +ssize_t git_process_read_err(git_process *process, void *buf, size_t count) +{ + GIT_ASSERT_ARG(process); + GIT_ASSERT(process->capture_err); + + return process_read(process->child_err, buf, count); +} + #ifdef GIT_THREADS # define signal_state sigset_t From bc124bb4357538b1c5ee990fe0f90dca8aa8bf56 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 May 2023 17:34:09 +0100 Subject: [PATCH 270/816] transport: provide clearer / unique error messages Provide more user-friendly error messages in smart protocol negotiation failures. --- src/libgit2/transports/smart_protocol.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 9646abb705b..7c86a8fb96a 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -59,7 +59,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) return recvd; if (recvd == 0) { - git_error_set(GIT_ERROR_NET, "early EOF receiving refs"); + git_error_set(GIT_ERROR_NET, "could not read refs from remote repository"); return GIT_EEOF; } @@ -285,7 +285,7 @@ static int recv_pkt( if ((ret = git_smart__recv(t)) < 0) { return ret; } else if (ret == 0) { - git_error_set(GIT_ERROR_NET, "early EOF receiving packet"); + git_error_set(GIT_ERROR_NET, "could not read from remote repository"); return GIT_EEOF; } } while (error); @@ -940,7 +940,7 @@ static int parse_report(transport_smart *transport, git_push *push) } if (recvd == 0) { - git_error_set(GIT_ERROR_NET, "early EOF receiving report"); + git_error_set(GIT_ERROR_NET, "could not read report from remote repository"); error = GIT_EEOF; goto done; } From 23424f43e1deee99f4830501669bf32d05234dca Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 20 May 2023 15:58:49 +0100 Subject: [PATCH 271/816] ssh: don't capture stderr Don't capture stderr, optimize for the CLI case. --- src/libgit2/transports/ssh_exec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c index 2b2c8a08eb2..61b30ee52a4 100644 --- a/src/libgit2/transports/ssh_exec.c +++ b/src/libgit2/transports/ssh_exec.c @@ -45,8 +45,9 @@ static int ssh_exec_subtransport_stream_read( transport = (ssh_exec_subtransport *)stream->parent.subtransport; - if ((ret = git_process_read(transport->process, buffer, buf_size)) < 0) + if ((ret = git_process_read(transport->process, buffer, buf_size)) < 0) { return (int)ret; + } *bytes_read = (size_t)ret; return 0; @@ -129,7 +130,7 @@ static int start_ssh( process_opts.capture_in = 1; process_opts.capture_out = 1; - process_opts.capture_err = 1; + process_opts.capture_err = 0; switch (action) { case GIT_SERVICE_UPLOADPACK_LS: From d7060aff36fd5a4e37689ae79e6dd86c08b64cac Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 29 Jul 2023 14:31:29 +0100 Subject: [PATCH 272/816] process: provide cmdline-handling and execv style Provide both cmdline-style handling (passing it to the shell on POSIX, or directly to CreateProcess on win32) and execv style (passing it directly to execv on POSIX, and mangling it into a single command-line on win32). --- src/util/process.h | 31 +++++++++++++++++++++- src/util/unix/process.c | 13 ++++++++++ src/util/win32/process.c | 53 +++++++++++++++++++++++++++++++------- tests/util/process/win32.c | 2 ++ 4 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/util/process.h b/src/util/process.h index 816be67fd98..87cf7acbd0c 100644 --- a/src/util/process.h +++ b/src/util/process.h @@ -43,7 +43,8 @@ typedef struct { /** * Create a new process. The command to run should be specified as the - * element of the `arg` array. + * element of the `arg` array, execv-style. This should be the full path + * to the command to run, the PATH is not obeyed. * * This function will add the given environment variables (in `env`) * to the current environment. Operations on environment variables @@ -67,8 +68,36 @@ extern int git_process_new( size_t env_len, git_process_options *opts); +/** + * Create a new process. The command to run should be specified as the + * `cmdline` option - which is the full text of the command line as it + * would be specified or run by a user. The command to run will be + * looked up in the PATH. + * + * On Unix, this will be executed by the system's shell (`/bin/sh`) + * and may contain _Bourne-style_ shell quoting rules. On Windows, + * this will be passed to `CreateProcess`, and similarly, may + * contain _Windows-style_ shell quoting rules. + * + * This function will add the given environment variables (in `env`) + * to the current environment. Operations on environment variables + * are not thread safe, so you may not modify the environment during + * this call. You can avoid this by setting `exclude_env` in the + * options and providing the entire environment yourself. + */ +extern int git_process_new_from_cmdline( + git_process **out, + const char *cmdline, + const char **env, + size_t env_len, + git_process_options *opts); + #ifdef GIT_WIN32 +extern int git_process__appname( + git_str *out, + const char *cmdline); + /* Windows path parsing is tricky; this helper function is for testing. */ extern int git_process__cmdline( git_str *out, diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 523e52f3156..7f88ccff067 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -146,6 +146,19 @@ int git_process_new( return 0; } +extern int git_process_new_from_cmdline( + git_process **out, + const char *cmdline, + const char **env, + size_t env_len, + git_process_options *opts) +{ + const char *args[] = { "/bin/sh", "-c", cmdline }; + + return git_process_new(out, + args, ARRAY_SIZE(args), env, env_len, opts); +} + #define CLOSE_FD(fd) \ if (fd >= 0) { \ close(fd); \ diff --git a/src/util/win32/process.c b/src/util/win32/process.c index 932119ab95e..bb522459711 100644 --- a/src/util/win32/process.c +++ b/src/util/win32/process.c @@ -162,30 +162,29 @@ static int merge_env(wchar_t **out, const char **in, size_t in_len, bool exclude return ret < 0 ? -1 : 0; } -int git_process_new( +static int process_new( git_process **out, - const char **args, - size_t args_len, + const char *appname, + const char *cmdline, const char **env, size_t env_len, git_process_options *opts) { git_process *process; - git_str cmdline = GIT_STR_INIT; - int error; - - GIT_ASSERT_ARG(out && args && args_len > 0); + int error = 0; *out = NULL; process = git__calloc(1, sizeof(git_process)); GIT_ERROR_CHECK_ALLOC(process); - if ((error = git_process__cmdline(&cmdline, args, args_len)) < 0) + if (appname && + git_utf8_to_16_alloc(&process->appname, appname) < 0) { + error = -1; goto done; + } - if (git_utf8_to_16_alloc(&process->appname, args[0]) < 0 || - git_utf8_to_16_alloc(&process->cmdline, cmdline.ptr) < 0) { + if (git_utf8_to_16_alloc(&process->cmdline, cmdline) < 0) { error = -1; goto done; } @@ -211,6 +210,40 @@ int git_process_new( else *out = process; + return error; +} + +int git_process_new_from_cmdline( + git_process **out, + const char *cmdline, + const char **env, + size_t env_len, + git_process_options *opts) +{ + GIT_ASSERT_ARG(out && cmdline); + + return process_new(out, NULL, cmdline, env, env_len, opts); +} + +int git_process_new( + git_process **out, + const char **args, + size_t args_len, + const char **env, + size_t env_len, + git_process_options *opts) +{ + git_str cmdline = GIT_STR_INIT; + int error; + + GIT_ASSERT_ARG(out && args && args_len > 0); + + if ((error = git_process__cmdline(&cmdline, args, args_len)) < 0) + goto done; + + error = process_new(out, args[0], cmdline.ptr, env, env_len, opts); + +done: git_str_dispose(&cmdline); return error; } diff --git a/tests/util/process/win32.c b/tests/util/process/win32.c index 914504d6263..c04a56ec54b 100644 --- a/tests/util/process/win32.c +++ b/tests/util/process/win32.c @@ -10,8 +10,10 @@ static git_str result; cl_assert_equal_s(expected, result.ptr); \ git_str_dispose(&result); \ } while(0) + #endif + void test_process_win32__cmdline_is_whitespace_delimited(void) { #ifdef GIT_WIN32 From 019cf6c24f6d150a11b7b4f150b3b6843b47e3c0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 27 Jul 2023 09:48:34 +0100 Subject: [PATCH 273/816] ssh: honor core.sshcommand Callers can specify the ssh command to invoke using `core.sshcommand` or the `GIT_SSH` environment variable. This is useful for specifying alternate configuration, and is particularly useful for our testing environment. --- ci/test.sh | 4 ++ src/libgit2/transports/ssh.c | 2 + src/libgit2/transports/ssh_exec.c | 62 +++++++++++++++++++++++-------- tests/libgit2/online/clone.c | 16 ++++++++ tests/libgit2/online/push.c | 14 +++++++ 5 files changed, 82 insertions(+), 16 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index e5331362436..9a24398ca1d 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -414,6 +414,8 @@ if [ -z "$SKIP_SSH_TESTS" ]; then export GITTEST_REMOTE_SSH_PASSPHRASE="" export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}" + export GITTEST_SSH_CMD="ssh -i ${HOME}/.ssh/id_rsa -o UserKnownHostsFile=${HOME}/.ssh/known_hosts" + echo "" echo "Running ssh tests" echo "" @@ -430,6 +432,8 @@ if [ -z "$SKIP_SSH_TESTS" ]; then run_test ssh unset GITTEST_REMOTE_URL + unset GITTEST_SSH_CMD + unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_SSH_KEY unset GITTEST_REMOTE_SSH_PUBKEY diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c index 98e1be2d131..1155e18a1d7 100644 --- a/src/libgit2/transports/ssh.c +++ b/src/libgit2/transports/ssh.c @@ -64,6 +64,8 @@ int git_transport_ssh_with_paths( *out = transport; return 0; +#elif GIT_SSH_EXEC + abort(); #else GIT_UNUSED(out); GIT_UNUSED(owner); diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c index 61b30ee52a4..661cd49779a 100644 --- a/src/libgit2/transports/ssh_exec.c +++ b/src/libgit2/transports/ssh_exec.c @@ -11,10 +11,12 @@ #include "common.h" +#include "config.h" #include "net.h" #include "path.h" #include "futils.h" #include "process.h" +#include "transports/smart.h" typedef struct { git_smart_subtransport_stream parent; @@ -114,17 +116,54 @@ GIT_INLINE(int) ensure_transport_state( return 0; } +static int get_ssh_cmdline( + git_str *out, + ssh_exec_subtransport *transport, + git_net_url *url, + const char *command) +{ + git_remote *remote = ((transport_smart *)transport->owner)->owner; + git_repository *repo = remote->repo; + git_config *cfg; + git_str ssh_cmd = GIT_STR_INIT; + const char *default_ssh_cmd = "ssh"; + int error; + + if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) + return error; + + if ((error = git__getenv(&ssh_cmd, "GIT_SSH")) == 0) + ; + else if (error != GIT_ENOTFOUND) + goto done; + else if ((error = git_config__get_string_buf(&ssh_cmd, cfg, "core.sshcommand")) < 0 && error != GIT_ENOTFOUND) + goto done; + + error = git_str_printf(out, "%s -p %s \"%s%s%s\" \"%s\" \"%s\"", + ssh_cmd.size > 0 ? ssh_cmd.ptr : default_ssh_cmd, + url->port, + url->username ? url->username : "", + url->username ? "@" : "", + url->host, + command, + url->path); + +done: + git_str_dispose(&ssh_cmd); + git_config_free(cfg); + return error; +} + static int start_ssh( ssh_exec_subtransport *transport, git_smart_service_t action, const char *sshpath) { - const char *args[6]; const char *env[] = { "GIT_DIR=" }; git_process_options process_opts = GIT_PROCESS_OPTIONS_INIT; git_net_url url = GIT_NET_URL_INIT; - git_str userhost = GIT_STR_INIT; + git_str ssh_cmdline = GIT_STR_INIT; const char *command; int error; @@ -153,20 +192,11 @@ static int start_ssh( if (error < 0) goto done; - if (url.username) { - git_str_puts(&userhost, url.username); - git_str_putc(&userhost, '@'); - } - git_str_puts(&userhost, url.host); - - args[0] = "/usr/bin/ssh"; - args[1] = "-p"; - args[2] = url.port; - args[3] = userhost.ptr; - args[4] = command; - args[5] = url.path; + if ((error = get_ssh_cmdline(&ssh_cmdline, transport, &url, command)) < 0) + goto done; - if ((error = git_process_new(&transport->process, args, ARRAY_SIZE(args), env, ARRAY_SIZE(env), &process_opts)) < 0 || + if ((error = git_process_new_from_cmdline(&transport->process, + ssh_cmdline.ptr, env, ARRAY_SIZE(env), &process_opts)) < 0 || (error = git_process_start(transport->process)) < 0) { git_process_free(transport->process); transport->process = NULL; @@ -174,7 +204,7 @@ static int start_ssh( } done: - git_str_dispose(&userhost); + git_str_dispose(&ssh_cmdline); git_net_url_dispose(&url); return error; } diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 1dc76d507a4..7a8f5ead780 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -47,6 +47,9 @@ static char *_orig_http_proxy = NULL; static char *_orig_https_proxy = NULL; static char *_orig_no_proxy = NULL; +static char *_ssh_cmd = NULL; +static char *_orig_ssh_cmd = NULL; + static int ssl_cert(git_cert *cert, int valid, const char *host, void *payload) { GIT_UNUSED(cert); @@ -102,6 +105,14 @@ void test_online_clone__initialize(void) _orig_https_proxy = cl_getenv("HTTPS_PROXY"); _orig_no_proxy = cl_getenv("NO_PROXY"); + _orig_ssh_cmd = cl_getenv("GIT_SSH"); + _ssh_cmd = cl_getenv("GITTEST_SSH_CMD"); + + if (_ssh_cmd) + cl_setenv("GIT_SSH", _ssh_cmd); + else + cl_setenv("GIT_SSH", NULL); + if (_remote_expectcontinue) git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1); } @@ -149,6 +160,11 @@ void test_online_clone__cleanup(void) git__free(_orig_https_proxy); git__free(_orig_no_proxy); + cl_setenv("GIT_SSH", _orig_ssh_cmd); + git__free(_orig_ssh_cmd); + + git__free(_ssh_cmd); + git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL); git_libgit2_opts(GIT_OPT_SET_SERVER_TIMEOUT, 0); git_libgit2_opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, 0); diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index 204572cf57b..b18402bf1a0 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -20,6 +20,9 @@ static char *_remote_ssh_passphrase = NULL; static char *_remote_default = NULL; static char *_remote_expectcontinue = NULL; +static char *_orig_ssh_cmd = NULL; +static char *_ssh_cmd = NULL; + static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); static git_remote *_remote; @@ -369,6 +372,14 @@ void test_online_push__initialize(void) _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE"); _remote = NULL; + _orig_ssh_cmd = cl_getenv("GIT_SSH"); + _ssh_cmd = cl_getenv("GITTEST_SSH_CMD"); + + if (_ssh_cmd) + cl_setenv("GIT_SSH", _ssh_cmd); + else + cl_setenv("GIT_SSH", NULL); + /* Skip the test if we're missing the remote URL */ if (!_remote_url) cl_skip(); @@ -423,6 +434,9 @@ void test_online_push__cleanup(void) git__free(_remote_default); git__free(_remote_expectcontinue); + git__free(_orig_ssh_cmd); + git__free(_ssh_cmd); + /* Freed by cl_git_sandbox_cleanup */ _repo = NULL; From 3eb7ff2bf91d1d5f524b57685354a043dc46a2b7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 27 Jul 2023 20:52:52 +0100 Subject: [PATCH 274/816] ci: specify full path to certificate/key This helped when troubleshooting issues running the `ci/test.sh` script locally. --- ci/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/test.sh b/ci/test.sh index 9a24398ca1d..8c411b65fb8 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -199,6 +199,8 @@ if [ -z "$SKIP_SSH_TESTS" ]; then PubkeyAuthentication yes ChallengeResponseAuthentication no StrictModes no + HostCertificate ${SSHD_DIR}/id_rsa.pub + HostKey ${SSHD_DIR}/id_rsa # Required here as sshd will simply close connection otherwise UsePAM no EOF From f26d92a4e2f6adcd632707d6ef4c6e922627545b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 27 Jul 2023 21:49:32 +0100 Subject: [PATCH 275/816] ssh: exec with paths for OpenSSH Handle custom paths for OpenSSH. --- src/libgit2/transports/ssh.c | 47 ++++++++++++++++++------------- src/libgit2/transports/ssh_exec.c | 30 ++++++++++++++++++-- 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c index 1155e18a1d7..3f3a127f256 100644 --- a/src/libgit2/transports/ssh.c +++ b/src/libgit2/transports/ssh.c @@ -24,7 +24,31 @@ int git_smart_subtransport_ssh( GIT_UNUSED(owner); GIT_UNUSED(param); - git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support"); + git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport; library was built without SSH support"); + return -1; +#endif +} + +static int transport_set_paths(git_transport *t, git_strarray *paths) +{ + transport_smart *smart = (transport_smart *)t; + +#ifdef GIT_SSH_LIBSSH2 + return git_smart_subtransport_ssh_libssh2_set_paths( + (git_smart_subtransport *)smart->wrapped, + paths->strings[0], + paths->strings[1]); +#elif GIT_SSH_EXEC + return git_smart_subtransport_ssh_exec_set_paths( + (git_smart_subtransport *)smart->wrapped, + paths->strings[0], + paths->strings[1]); +#else + GIT_UNUSED(t); + GIT_UNUSED(smart); + GIT_UNUSED(paths); + + GIT_ASSERT(!"cannot create SSH library; library was built without SSH support"); return -1; #endif } @@ -34,16 +58,14 @@ int git_transport_ssh_with_paths( git_remote *owner, void *payload) { -#ifdef GIT_SSH_LIBSSH2 git_strarray *paths = (git_strarray *) payload; git_transport *transport; - transport_smart *smart; int error; git_smart_subtransport_definition ssh_definition = { git_smart_subtransport_ssh, 0, /* no RPC */ - NULL, + NULL }; if (paths->count != 2) { @@ -54,25 +76,10 @@ int git_transport_ssh_with_paths( if ((error = git_transport_smart(&transport, owner, &ssh_definition)) < 0) return error; - smart = (transport_smart *) transport; - - if ((error = git_smart_subtransport_ssh_libssh2_set_paths( - (git_smart_subtransport *)smart->wrapped, - paths->strings[0], - paths->strings[1])) < 0) + if ((error = transport_set_paths(transport, paths)) < 0) return error; *out = transport; return 0; -#elif GIT_SSH_EXEC - abort(); -#else - GIT_UNUSED(out); - GIT_UNUSED(owner); - GIT_UNUSED(payload); - - git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support"); - return -1; -#endif } diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c index 661cd49779a..786e7ee8bdb 100644 --- a/src/libgit2/transports/ssh_exec.c +++ b/src/libgit2/transports/ssh_exec.c @@ -28,6 +28,9 @@ typedef struct { ssh_exec_subtransport_stream *current_stream; + char *cmd_uploadpack; + char *cmd_receivepack; + git_smart_service_t action; git_process *process; } ssh_exec_subtransport; @@ -173,10 +176,12 @@ static int start_ssh( switch (action) { case GIT_SERVICE_UPLOADPACK_LS: - command = "git-upload-pack"; + command = transport->cmd_uploadpack ? + transport->cmd_uploadpack : "git-upload-pack"; break; case GIT_SERVICE_RECEIVEPACK_LS: - command = "git-receive-pack"; + command = transport->cmd_receivepack ? + transport->cmd_receivepack : "git-receive-pack"; break; default: git_error_set(GIT_ERROR_NET, "invalid action"); @@ -277,6 +282,8 @@ static void ssh_exec_subtransport_free(git_smart_subtransport *t) { ssh_exec_subtransport *transport = (ssh_exec_subtransport *)t; + git__free(transport->cmd_uploadpack); + git__free(transport->cmd_receivepack); git__free(transport); } @@ -301,4 +308,23 @@ int git_smart_subtransport_ssh_exec( return 0; } +int git_smart_subtransport_ssh_exec_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack) +{ + ssh_exec_subtransport *t = (ssh_exec_subtransport *)subtransport; + + git__free(t->cmd_uploadpack); + git__free(t->cmd_receivepack); + + t->cmd_uploadpack = git__strdup(cmd_uploadpack); + GIT_ERROR_CHECK_ALLOC(t->cmd_uploadpack); + + t->cmd_receivepack = git__strdup(cmd_receivepack); + GIT_ERROR_CHECK_ALLOC(t->cmd_receivepack); + + return 0; +} + #endif From ac399148d24e7cb6a6fc81a5b8c76454ac165b64 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 4 Aug 2023 09:19:02 +0100 Subject: [PATCH 276/816] net: don't free wrapped transport on failure --- src/libgit2/transports/smart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index fe3fe970ae1..67dc33e78fa 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -523,7 +523,6 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) definition->callback(&t->wrapped, &t->parent, definition->param) < 0) { git_vector_free(&t->refs); git_vector_free(&t->heads); - t->wrapped->free(t->wrapped); git__free(t); return -1; } From 9a9f220119d9647a352867b24b0556195cb26548 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 19 Aug 2023 15:09:59 +0100 Subject: [PATCH 277/816] ssh: refactor to avoid using error state The error handling in the ssh certificate callback is straightforward. There's no error messages from an external library that need to be saved, we populate the error message ourselves. Since there's nothing custom here, it does not need to use the error saving mechanism. --- src/libgit2/transports/ssh_libssh2.c | 31 ++++++++++++---------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index 76c08c2e1a5..e32587683de 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -665,7 +665,7 @@ static int check_certificate( git_cert_hostkey cert = {{ 0 }}; const char *key; size_t cert_len; - int cert_type, cert_valid = 0, error = 0; + int cert_type, cert_valid = 0, error = GIT_ECERTIFICATE; if ((key = libssh2_session_hostkey(session, &cert_len, &cert_type)) == NULL) { ssh_error(session, "failed to retrieve hostkey"); @@ -735,29 +735,24 @@ static int check_certificate( return -1; } - git_error_clear(); - error = 0; - if (!cert_valid) { - git_error_set(GIT_ERROR_SSH, "invalid or unknown remote ssh hostkey"); - error = GIT_ECERTIFICATE; - } - if (check_cb != NULL) { git_cert_hostkey *cert_ptr = &cert; - git_error_state previous_error = {0}; - git_error_state_capture(&previous_error, error); - error = check_cb((git_cert *) cert_ptr, cert_valid, host, check_cb_payload); - if (error == GIT_PASSTHROUGH) { - error = git_error_state_restore(&previous_error); - } else if (error < 0 && !git_error_last()) { - git_error_set(GIT_ERROR_NET, "unknown remote host key"); - } + error = check_cb((git_cert *)cert_ptr, cert_valid, host, + check_cb_payload); - git_error_state_free(&previous_error); + if (error == 0) + cert_valid = 1; + else if (error != GIT_PASSTHROUGH) + cert_valid = 0; } - return error; + if (!cert_valid) { + git_error_set(GIT_ERROR_SSH, "invalid or unknown remote ssh hostkey"); + return (error == GIT_PASSTHROUGH) ? GIT_ECERTIFICATE : error; + } + + return 0; } #define SSH_DEFAULT_PORT "22" From 3618a2aa45893a88fbb2d1e0eb97d530c7dc4f4d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 17 Aug 2023 10:49:52 +0100 Subject: [PATCH 278/816] errors: never return a NULL error Callers want to be able to simply call `git_error_last()->message`, not have to worry about whether `git_error_last()` returns NULL or not. --- include/git2/errors.h | 13 +++++++---- src/libgit2/errors.c | 10 ++++++++- tests/libgit2/config/include.c | 4 ++-- tests/libgit2/grafts/shallow.c | 2 +- tests/libgit2/repo/shallow.c | 2 +- tests/util/assert.c | 3 ++- tests/util/errors.c | 41 +++++++++++++++++++++++++--------- 7 files changed, 55 insertions(+), 20 deletions(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index 7180852f95c..f9f14c72cda 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -118,10 +118,15 @@ typedef enum { * Return the last `git_error` object that was generated for the * current thread. * - * The default behaviour of this function is to return NULL if no previous error has occurred. - * However, libgit2's error strings are not cleared aggressively, so a prior - * (unrelated) error may be returned. This can be avoided by only calling - * this function if the prior call to a libgit2 API returned an error. + * This function will never return NULL. + * + * Callers should not rely on this to determine whether an error has + * occurred. For error checking, callers should examine the return + * codes of libgit2 functions. + * + * This call can only reliably report error messages when an error + * has occurred. (It may contain stale information if it is called + * after a different function that succeeds.) * * @return A git_error object. */ diff --git a/src/libgit2/errors.c b/src/libgit2/errors.c index 2e58948d2e4..1c4ff7de8a4 100644 --- a/src/libgit2/errors.c +++ b/src/libgit2/errors.c @@ -28,7 +28,12 @@ static git_error uninitialized_error = { static git_error tlsdata_error = { "thread-local data initialization failure", - GIT_ERROR + GIT_ERROR_THREAD +}; + +static git_error no_error = { + "no error", + GIT_ERROR_NONE }; static void set_error_from_buffer(int error_class) @@ -184,6 +189,9 @@ const git_error *git_error_last(void) if ((threadstate = git_threadstate_get()) == NULL) return &tlsdata_error; + if (!threadstate->last_error) + return &no_error; + return threadstate->last_error; } diff --git a/tests/libgit2/config/include.c b/tests/libgit2/config/include.c index 1b55fdc86fd..ba8bcad4387 100644 --- a/tests/libgit2/config/include.c +++ b/tests/libgit2/config/include.c @@ -111,7 +111,7 @@ void test_config_include__missing(void) git_error_clear(); cl_git_pass(git_config_open_ondisk(&cfg, "including")); - cl_assert(git_error_last() == NULL); + cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); cl_assert_equal_s("baz", buf.ptr); @@ -126,7 +126,7 @@ void test_config_include__missing_homedir(void) git_error_clear(); cl_git_pass(git_config_open_ondisk(&cfg, "including")); - cl_assert(git_error_last() == NULL); + cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); cl_assert_equal_s("baz", buf.ptr); diff --git a/tests/libgit2/grafts/shallow.c b/tests/libgit2/grafts/shallow.c index 5911a26aabc..289d1b19105 100644 --- a/tests/libgit2/grafts/shallow.c +++ b/tests/libgit2/grafts/shallow.c @@ -40,7 +40,7 @@ void test_grafts_shallow__clears_errors(void) { g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); - cl_assert_equal_p(NULL, git_error_last()); + cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass); } void test_grafts_shallow__shallow_oids(void) diff --git a/tests/libgit2/repo/shallow.c b/tests/libgit2/repo/shallow.c index adb7a9e44b5..a3e3036c533 100644 --- a/tests/libgit2/repo/shallow.c +++ b/tests/libgit2/repo/shallow.c @@ -35,5 +35,5 @@ void test_repo_shallow__clears_errors(void) { g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); - cl_assert_equal_p(NULL, git_error_last()); + cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass); } diff --git a/tests/util/assert.c b/tests/util/assert.c index 3babc475ae3..4644f3533e9 100644 --- a/tests/util/assert.c +++ b/tests/util/assert.c @@ -92,7 +92,8 @@ void test_assert__argument_with_void_return_type(void) git_error_clear(); cl_assert_equal_p(foo, fn_returns_string(foo)); - cl_assert_equal_p(NULL, git_error_last()); + cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass); + cl_assert_equal_s("no error", git_error_last()->message); } void test_assert__internal(void) diff --git a/tests/util/errors.c b/tests/util/errors.c index 78654a753ae..f3597fce28b 100644 --- a/tests/util/errors.c +++ b/tests/util/errors.c @@ -5,7 +5,10 @@ void test_errors__public_api(void) char *str_in_error; git_error_clear(); - cl_assert(git_error_last() == NULL); + + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); git_error_set_oom(); @@ -23,7 +26,9 @@ void test_errors__public_api(void) cl_assert(str_in_error != NULL); git_error_clear(); - cl_assert(git_error_last() == NULL); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); } #include "common.h" @@ -35,7 +40,9 @@ void test_errors__new_school(void) char *str_in_error; git_error_clear(); - cl_assert(git_error_last() == NULL); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); git_error_set_oom(); /* internal fn */ @@ -53,7 +60,9 @@ void test_errors__new_school(void) cl_assert(str_in_error != NULL); git_error_clear(); - cl_assert(git_error_last() == NULL); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); do { struct stat st; @@ -91,7 +100,9 @@ void test_errors__restore(void) git_error_state err_state = {0}; git_error_clear(); - cl_assert(git_error_last() == NULL); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); cl_assert_equal_i(0, git_error_state_capture(&err_state, 0)); @@ -100,7 +111,9 @@ void test_errors__restore(void) git_error_set(42, "Foo: %s", "bar"); cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1)); - cl_assert(git_error_last() == NULL); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); git_error_set(99, "Bar: %s", "foo"); @@ -128,7 +141,9 @@ void test_errors__free_state(void) git_error_state_restore(&err_state); - cl_assert(git_error_last() == NULL); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); } void test_errors__restore_oom(void) @@ -144,7 +159,9 @@ void test_errors__restore_oom(void) cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1)); - cl_assert(git_error_last() == NULL); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); cl_assert_equal_i(GIT_ERROR_NOMEMORY, err_state.error_msg.klass); cl_assert_equal_s("Out of memory", err_state.error_msg.message); @@ -204,11 +221,15 @@ void test_errors__integer_overflow_sets_oom(void) git_error_clear(); cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX-1, 1)); - cl_assert_equal_p(NULL, git_error_last()); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); git_error_clear(); cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, 42, 69)); - cl_assert_equal_p(NULL, git_error_last()); + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_NONE); + cl_assert(strcmp(git_error_last()->message, "no error") == 0); git_error_clear(); cl_assert(GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX, SIZE_MAX)); From f78ae89bf1800444257160ad6ca48a0cd95384ba Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 17 Aug 2023 10:57:44 +0100 Subject: [PATCH 279/816] errors: move systems things into the sys includes Most callers only need to _get_ error messages. Only callers implemented more complicated functions (like a custom ODB for example) need to set them. (Callback users should likely ferry their own error information in their callback payload.) --- include/git2/errors.h | 52 ++---------------------------- include/git2/sys/errors.h | 66 +++++++++++++++++++++++++++++++++++++++ src/libgit2/errors.h | 1 + src/util/git2_util.h | 1 + 4 files changed, 71 insertions(+), 49 deletions(-) create mode 100644 include/git2/sys/errors.h diff --git a/include/git2/errors.h b/include/git2/errors.h index f9f14c72cda..face0898a12 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -128,59 +128,13 @@ typedef enum { * has occurred. (It may contain stale information if it is called * after a different function that succeeds.) * + * The memory for this object is managed by libgit2. It should not + * be freed. + * * @return A git_error object. */ GIT_EXTERN(const git_error *) git_error_last(void); -/** - * Clear the last library error that occurred for this thread. - */ -GIT_EXTERN(void) git_error_clear(void); - -/** - * Set the error message string for this thread, using `printf`-style - * formatting. - * - * This function is public so that custom ODB backends and the like can - * relay an error message through libgit2. Most regular users of libgit2 - * will never need to call this function -- actually, calling it in most - * circumstances (for example, calling from within a callback function) - * will just end up having the value overwritten by libgit2 internals. - * - * This error message is stored in thread-local storage and only applies - * to the particular thread that this libgit2 call is made from. - * - * @param error_class One of the `git_error_t` enum above describing the - * general subsystem that is responsible for the error. - * @param fmt The `printf`-style format string; subsequent arguments must - * be the arguments for the format string. - */ -GIT_EXTERN(void) git_error_set(int error_class, const char *fmt, ...) - GIT_FORMAT_PRINTF(2, 3); - -/** - * Set the error message string for this thread. This function is like - * `git_error_set` but takes a static string instead of a `printf`-style - * format. - * - * @param error_class One of the `git_error_t` enum above describing the - * general subsystem that is responsible for the error. - * @param string The error message to keep - * @return 0 on success or -1 on failure - */ -GIT_EXTERN(int) git_error_set_str(int error_class, const char *string); - -/** - * Set the error message to a special value for memory allocation failure. - * - * The normal `git_error_set_str()` function attempts to `strdup()` the - * string that is passed in. This is not a good idea when the error in - * question is a memory allocation failure. That circumstance has a - * special setter function that sets the error string to a known and - * statically allocated internal value. - */ -GIT_EXTERN(void) git_error_set_oom(void); - /** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/errors.h b/include/git2/sys/errors.h new file mode 100644 index 00000000000..3ae121524d5 --- /dev/null +++ b/include/git2/sys/errors.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_sys_git_errors_h__ +#define INCLUDE_sys_git_errors_h__ + +#include "git2/common.h" + +GIT_BEGIN_DECL + +/** + * Clear the last library error that occurred for this thread. + */ +GIT_EXTERN(void) git_error_clear(void); + +/** + * Set the error message string for this thread, using `printf`-style + * formatting. + * + * This function is public so that custom ODB backends and the like can + * relay an error message through libgit2. Most regular users of libgit2 + * will never need to call this function -- actually, calling it in most + * circumstances (for example, calling from within a callback function) + * will just end up having the value overwritten by libgit2 internals. + * + * This error message is stored in thread-local storage and only applies + * to the particular thread that this libgit2 call is made from. + * + * @param error_class One of the `git_error_t` enum above describing the + * general subsystem that is responsible for the error. + * @param fmt The `printf`-style format string; subsequent arguments must + * be the arguments for the format string. + */ +GIT_EXTERN(void) git_error_set(int error_class, const char *fmt, ...) + GIT_FORMAT_PRINTF(2, 3); + +/** + * Set the error message string for this thread. This function is like + * `git_error_set` but takes a static string instead of a `printf`-style + * format. + * + * @param error_class One of the `git_error_t` enum above describing the + * general subsystem that is responsible for the error. + * @param string The error message to keep + * @return 0 on success or -1 on failure + */ +GIT_EXTERN(int) git_error_set_str(int error_class, const char *string); + +/** + * Set the error message to a special value for memory allocation failure. + * + * The normal `git_error_set_str()` function attempts to `strdup()` the + * string that is passed in. This is not a good idea when the error in + * question is a memory allocation failure. That circumstance has a + * special setter function that sets the error string to a known and + * statically allocated internal value. + */ +GIT_EXTERN(void) git_error_set_oom(void); + +GIT_END_DECL + +#endif diff --git a/src/libgit2/errors.h b/src/libgit2/errors.h index 772c7bad18b..bb207a0f5e6 100644 --- a/src/libgit2/errors.h +++ b/src/libgit2/errors.h @@ -9,6 +9,7 @@ #define INCLUDE_errors_h__ #include "common.h" +#include "git2/sys/errors.h" /* * `vprintf`-style formatting for the error message for this thread. diff --git a/src/util/git2_util.h b/src/util/git2_util.h index c62dc24199d..5ec9429344a 100644 --- a/src/util/git2_util.h +++ b/src/util/git2_util.h @@ -12,6 +12,7 @@ #endif #include "git2/common.h" +#include "git2/sys/errors.h" #include "cc-compat.h" typedef struct git_str git_str; From f451cb18df97c5f9400cf31e6e271f4df74bfcd9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Aug 2023 10:32:34 +0100 Subject: [PATCH 280/816] errors: simplify the saved-state handling Instead of having a separate type for saving state, we can re-use the `git_error` structure. In practice, saving the error code along with the `git_error` information has not proven necessary or useful, so it can be removed to simplify down to re-using a single structure. --- src/libgit2/clone.c | 6 +- src/libgit2/errors.c | 94 +++++++++++++++++------------ src/libgit2/errors.h | 32 +++++----- src/libgit2/filter.c | 6 +- src/libgit2/index.c | 12 ++-- src/libgit2/transports/httpclient.c | 32 +++++++--- tests/util/errors.c | 57 +++++------------ 7 files changed, 121 insertions(+), 118 deletions(-) diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index fca0ca0cc7c..ab48191cc6a 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -542,15 +542,15 @@ static int git__clone( } if (error != 0) { - git_error_state last_error = {0}; - git_error_state_capture(&last_error, error); + git_error *last_error; + git_error_save(&last_error); git_repository_free(repo); repo = NULL; (void)git_futils_rmdir_r(local_path, NULL, rmdir_flags); - git_error_state_restore(&last_error); + git_error_restore(last_error); } *out = repo; diff --git a/src/libgit2/errors.c b/src/libgit2/errors.c index 1c4ff7de8a4..232980e0f40 100644 --- a/src/libgit2/errors.c +++ b/src/libgit2/errors.c @@ -36,6 +36,10 @@ static git_error no_error = { GIT_ERROR_NONE }; +#define IS_STATIC_ERROR(err) \ + ((err) == &oom_error || (err) == &uninitialized_error || \ + (err) == &tlsdata_error || (err) == &no_error) + static void set_error_from_buffer(int error_class) { git_threadstate *threadstate = git_threadstate_get(); @@ -66,12 +70,11 @@ static void set_error(int error_class, char *string) git_str_clear(buf); - if (string) { + if (string) git_str_puts(buf, string); - git__free(string); - } - set_error_from_buffer(error_class); + if (!git_str_oom(buf)) + set_error_from_buffer(error_class); } void git_error_set_oom(void) @@ -178,6 +181,16 @@ void git_error_clear(void) #endif } +bool git_error_exists(void) +{ + git_threadstate *threadstate; + + if ((threadstate = git_threadstate_get()) == NULL) + return true; + + return threadstate->last_error != NULL; +} + const git_error *git_error_last(void) { git_threadstate *threadstate; @@ -195,67 +208,68 @@ const git_error *git_error_last(void) return threadstate->last_error; } -int git_error_state_capture(git_error_state *state, int error_code) +int git_error_save(git_error **out) { git_threadstate *threadstate = git_threadstate_get(); - git_error *error; - git_str *error_buf; + git_error *error, *dup; - if (!threadstate) + if (!threadstate) { + *out = &tlsdata_error; return -1; + } error = threadstate->last_error; - error_buf = &threadstate->error_buf; - - memset(state, 0, sizeof(git_error_state)); - if (!error_code) + if (!error || error == &no_error) { + *out = &no_error; return 0; + } else if (IS_STATIC_ERROR(error)) { + *out = error; + return 0; + } - state->error_code = error_code; - state->oom = (error == &oom_error); + if ((dup = git__malloc(sizeof(git_error))) == NULL) { + *out = &oom_error; + return -1; + } - if (error) { - state->error_msg.klass = error->klass; + dup->klass = error->klass; + dup->message = git__strdup(error->message); - if (state->oom) - state->error_msg.message = oom_error.message; - else - state->error_msg.message = git_str_detach(error_buf); + if (!dup->message) { + *out = &oom_error; + return -1; } - git_error_clear(); - return error_code; + *out = dup; + return 0; } -int git_error_state_restore(git_error_state *state) +int git_error_restore(git_error *error) { - int ret = 0; + git_threadstate *threadstate = git_threadstate_get(); - git_error_clear(); + GIT_ASSERT_ARG(error); - if (state && state->error_msg.message) { - if (state->oom) - git_error_set_oom(); - else - set_error(state->error_msg.klass, state->error_msg.message); + if (IS_STATIC_ERROR(error) && threadstate) + threadstate->last_error = error; + else + set_error(error->klass, error->message); - ret = state->error_code; - memset(state, 0, sizeof(git_error_state)); - } - - return ret; + git_error_free(error); + return 0; } -void git_error_state_free(git_error_state *state) +void git_error_free(git_error *error) { - if (!state) + if (!error) return; - if (!state->oom) - git__free(state->error_msg.message); + if (IS_STATIC_ERROR(error)) + return; - memset(state, 0, sizeof(git_error_state)); + git__free(error->message); + git__free(error); } int git_error_system_last(void) diff --git a/src/libgit2/errors.h b/src/libgit2/errors.h index bb207a0f5e6..f929219560d 100644 --- a/src/libgit2/errors.h +++ b/src/libgit2/errors.h @@ -16,6 +16,11 @@ */ void git_error_vset(int error_class, const char *fmt, va_list ap); +/** + * Determines whether an error exists. + */ +bool git_error_exists(void); + /** * Set error message for user callback if needed. * @@ -28,9 +33,8 @@ GIT_INLINE(int) git_error_set_after_callback_function( int error_code, const char *action) { if (error_code) { - const git_error *e = git_error_last(); - if (!e || !e->message) - git_error_set(e ? e->klass : GIT_ERROR_CALLBACK, + if (!git_error_exists()) + git_error_set(GIT_ERROR_CALLBACK, "%s callback returned %d", action, error_code); } return error_code; @@ -54,28 +58,24 @@ int git_error_system_last(void); */ void git_error_system_set(int code); -/** - * Structure to preserve libgit2 error state - */ -typedef struct { - int error_code; - unsigned int oom : 1; - git_error error_msg; -} git_error_state; - /** * Capture current error state to restore later, returning error code. * If `error_code` is zero, this does not clear the current error state. * You must either restore this error state, or free it. + * + * This function returns 0 on success, or -1 on failure. If the function + * fails, the `out` structure is set to the failure error message and + * the normal system error message is not updated. */ -extern int git_error_state_capture(git_error_state *state, int error_code); +extern int git_error_save(git_error **out); /** - * Restore error state to a previous value, returning saved error code. + * Restore thread error state to the given value. The given value is + * freed and `git_error_free` need not be called on it. */ -extern int git_error_state_restore(git_error_state *state); +extern int git_error_restore(git_error *error); /** Free an error state. */ -extern void git_error_state_free(git_error_state *state); +extern void git_error_free(git_error *error); #endif diff --git a/src/libgit2/filter.c b/src/libgit2/filter.c index 80a3cae67bc..fdfc409a287 100644 --- a/src/libgit2/filter.c +++ b/src/libgit2/filter.c @@ -908,7 +908,7 @@ static int buffered_stream_close(git_writestream *s) { struct buffered_stream *buffered_stream = (struct buffered_stream *)s; git_str *writebuf; - git_error_state error_state = {0}; + git_error *last_error; int error; GIT_ASSERT_ARG(buffered_stream); @@ -946,9 +946,9 @@ static int buffered_stream_close(git_writestream *s) } else { /* close stream before erroring out taking care * to preserve the original error */ - git_error_state_capture(&error_state, error); + git_error_save(&last_error); buffered_stream->target->close(buffered_stream->target); - git_error_state_restore(&error_state); + git_error_restore(last_error); return error; } diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 9d919093be0..90580731830 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -1609,15 +1609,17 @@ int git_index_add_bypath(git_index *index, const char *path) if (ret == GIT_EDIRECTORY) { git_submodule *sm; - git_error_state err; + git_error *last_error; - git_error_state_capture(&err, ret); + git_error_save(&last_error); ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path); - if (ret == GIT_ENOTFOUND) - return git_error_state_restore(&err); + if (ret == GIT_ENOTFOUND) { + git_error_restore(last_error); + return GIT_EDIRECTORY; + } - git_error_state_free(&err); + git_error_free(last_error); /* * EEXISTS means that there is a repository at that path, but it's not known diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index a20b594930d..278d7c8e0ab 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -768,25 +768,37 @@ static int check_certificate( void *cert_cb_payload) { git_cert *cert; - git_error_state last_error = {0}; + git_error *last_error; int error; if ((error = git_stream_certificate(&cert, stream)) < 0) return error; - git_error_state_capture(&last_error, GIT_ECERTIFICATE); + /* + * Allow callers to set an error - but save ours and clear + * it, so that we can detect if they set one and restore it + * if we need to. + */ + git_error_save(&last_error); + git_error_clear(); error = cert_cb(cert, is_valid, url->host, cert_cb_payload); - if (error == GIT_PASSTHROUGH && !is_valid) - return git_error_state_restore(&last_error); - else if (error == GIT_PASSTHROUGH) - error = 0; - else if (error && !git_error_last()) - git_error_set(GIT_ERROR_HTTP, - "user rejected certificate for %s", url->host); + if (error == GIT_PASSTHROUGH) { + error = is_valid ? 0 : -1; + + if (error) { + git_error_restore(last_error); + last_error = NULL; + } + } else if (error) { + if (!git_error_exists()) + git_error_set(GIT_ERROR_HTTP, + "user rejected certificate for %s", + url->host); + } - git_error_state_free(&last_error); + git_error_free(last_error); return error; } diff --git a/tests/util/errors.c b/tests/util/errors.c index f3597fce28b..f9b85a65fde 100644 --- a/tests/util/errors.c +++ b/tests/util/errors.c @@ -97,58 +97,32 @@ void test_errors__new_school(void) void test_errors__restore(void) { - git_error_state err_state = {0}; + git_error *last_error; git_error_clear(); cl_assert(git_error_last() != NULL); cl_assert(git_error_last()->klass == GIT_ERROR_NONE); - cl_assert(strcmp(git_error_last()->message, "no error") == 0); - - cl_assert_equal_i(0, git_error_state_capture(&err_state, 0)); - - memset(&err_state, 0x0, sizeof(git_error_state)); + cl_assert(strcmp("no error", git_error_last()->message) == 0); git_error_set(42, "Foo: %s", "bar"); - cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1)); + cl_assert(git_error_save(&last_error) == 0); + git_error_clear(); cl_assert(git_error_last() != NULL); cl_assert(git_error_last()->klass == GIT_ERROR_NONE); - cl_assert(strcmp(git_error_last()->message, "no error") == 0); - - git_error_set(99, "Bar: %s", "foo"); - - git_error_state_restore(&err_state); - - cl_assert_equal_i(42, git_error_last()->klass); - cl_assert_equal_s("Foo: bar", git_error_last()->message); -} - -void test_errors__free_state(void) -{ - git_error_state err_state = {0}; - - git_error_clear(); - - git_error_set(42, "Foo: %s", "bar"); - cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1)); + cl_assert(strcmp("no error", git_error_last()->message) == 0); git_error_set(99, "Bar: %s", "foo"); - git_error_state_free(&err_state); - - cl_assert_equal_i(99, git_error_last()->klass); - cl_assert_equal_s("Bar: foo", git_error_last()->message); - - git_error_state_restore(&err_state); + git_error_restore(last_error); - cl_assert(git_error_last() != NULL); - cl_assert(git_error_last()->klass == GIT_ERROR_NONE); - cl_assert(strcmp(git_error_last()->message, "no error") == 0); + cl_assert(git_error_last()->klass == 42); + cl_assert(strcmp("Foo: bar", git_error_last()->message) == 0); } void test_errors__restore_oom(void) { - git_error_state err_state = {0}; + git_error *last_error; const git_error *oom_error = NULL; git_error_clear(); @@ -156,17 +130,18 @@ void test_errors__restore_oom(void) git_error_set_oom(); /* internal fn */ oom_error = git_error_last(); cl_assert(oom_error); + cl_assert(oom_error->klass == GIT_ERROR_NOMEMORY); - cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1)); + cl_assert(git_error_save(&last_error) == 0); + cl_assert(last_error->klass == GIT_ERROR_NOMEMORY); + cl_assert(strcmp("Out of memory", last_error->message) == 0); + git_error_clear(); cl_assert(git_error_last() != NULL); cl_assert(git_error_last()->klass == GIT_ERROR_NONE); - cl_assert(strcmp(git_error_last()->message, "no error") == 0); - cl_assert_equal_i(GIT_ERROR_NOMEMORY, err_state.error_msg.klass); - cl_assert_equal_s("Out of memory", err_state.error_msg.message); - - git_error_state_restore(&err_state); + cl_assert(strcmp("no error", git_error_last()->message) == 0); + git_error_restore(last_error); cl_assert(git_error_last()->klass == GIT_ERROR_NOMEMORY); cl_assert_(git_error_last() == oom_error, "static oom error not restored"); From 7572d539f9acb9f46505c885c3bea5ff9c26ba8b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Aug 2023 12:33:00 +0100 Subject: [PATCH 281/816] errors: keep thread-local state internal --- src/libgit2/errors.c | 143 ++++++++++++++++++++++++++++++-------- src/libgit2/errors.h | 3 + src/libgit2/libgit2.c | 1 + src/libgit2/threadstate.c | 9 --- src/libgit2/threadstate.h | 3 - 5 files changed, 117 insertions(+), 42 deletions(-) diff --git a/src/libgit2/errors.c b/src/libgit2/errors.c index 232980e0f40..cfaa367d925 100644 --- a/src/libgit2/errors.c +++ b/src/libgit2/errors.c @@ -7,14 +7,15 @@ #include "common.h" -#include "threadstate.h" #include "posix.h" #include "str.h" #include "libgit2.h" +#include "runtime.h" -/******************************************** - * New error handling - ********************************************/ +/* + * Some static error data that is used when we're out of memory, TLS + * has not been setup, or TLS has failed. + */ static git_error oom_error = { "Out of memory", @@ -40,33 +41,115 @@ static git_error no_error = { ((err) == &oom_error || (err) == &uninitialized_error || \ (err) == &tlsdata_error || (err) == &no_error) +/* Per-thread error state (TLS) */ + +static git_tlsdata_key tls_key; + +struct error_threadstate { + /* The error message buffer. */ + git_str message; + + /* Error information, set by `git_error_set` and friends. */ + git_error error; + + /* + * The last error to occur; points to the error member of this + * struct _or_ a static error. + */ + git_error *last; +}; + +static void threadstate_dispose(struct error_threadstate *threadstate) +{ + if (!threadstate) + return; + + git_str_dispose(&threadstate->message); +} + +static struct error_threadstate *threadstate_get(void) +{ + struct error_threadstate *threadstate; + + if ((threadstate = git_tlsdata_get(tls_key)) != NULL) + return threadstate; + + /* + * Avoid git__malloc here, since if it fails, it sets an error + * message, which requires thread state, which would allocate + * here, which would fail, which would set an error message... + */ + + if ((threadstate = git__allocator.gmalloc( + sizeof(struct error_threadstate), + __FILE__, __LINE__)) == NULL) + return NULL; + + memset(threadstate, 0, sizeof(struct error_threadstate)); + + if (git_str_init(&threadstate->message, 0) < 0) { + git__allocator.gfree(threadstate); + return NULL; + } + + git_tlsdata_set(tls_key, threadstate); + return threadstate; +} + +static void GIT_SYSTEM_CALL threadstate_free(void *threadstate) +{ + threadstate_dispose(threadstate); + git__free(threadstate); +} + +static void git_error_global_shutdown(void) +{ + struct error_threadstate *threadstate; + + threadstate = git_tlsdata_get(tls_key); + git_tlsdata_set(tls_key, NULL); + + threadstate_dispose(threadstate); + git__free(threadstate); + + git_tlsdata_dispose(tls_key); +} + +int git_error_global_init(void) +{ + if (git_tlsdata_init(&tls_key, &threadstate_free) != 0) + return -1; + + return git_runtime_shutdown_register(git_error_global_shutdown); +} + static void set_error_from_buffer(int error_class) { - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); git_error *error; git_str *buf; if (!threadstate) return; - error = &threadstate->error_t; - buf = &threadstate->error_buf; + error = &threadstate->error; + buf = &threadstate->message; error->message = buf->ptr; error->klass = error_class; - threadstate->last_error = error; + threadstate->last = error; } static void set_error(int error_class, char *string) { - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); git_str *buf; if (!threadstate) return; - buf = &threadstate->error_buf; + buf = &threadstate->message; git_str_clear(buf); @@ -79,12 +162,12 @@ static void set_error(int error_class, char *string) void git_error_set_oom(void) { - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); if (!threadstate) return; - threadstate->last_error = &oom_error; + threadstate->last = &oom_error; } void git_error_set(int error_class, const char *fmt, ...) @@ -102,14 +185,14 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0; #endif - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); int error_code = (error_class == GIT_ERROR_OS) ? errno : 0; git_str *buf; if (!threadstate) return; - buf = &threadstate->error_buf; + buf = &threadstate->message; git_str_clear(buf); @@ -143,7 +226,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) int git_error_set_str(int error_class, const char *string) { - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); git_str *buf; GIT_ASSERT_ARG(string); @@ -151,7 +234,7 @@ int git_error_set_str(int error_class, const char *string) if (!threadstate) return -1; - buf = &threadstate->error_buf; + buf = &threadstate->message; git_str_clear(buf); git_str_puts(buf, string); @@ -165,14 +248,14 @@ int git_error_set_str(int error_class, const char *string) void git_error_clear(void) { - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); if (!threadstate) return; - if (threadstate->last_error != NULL) { + if (threadstate->last != NULL) { set_error(0, NULL); - threadstate->last_error = NULL; + threadstate->last = NULL; } errno = 0; @@ -183,34 +266,34 @@ void git_error_clear(void) bool git_error_exists(void) { - git_threadstate *threadstate; + struct error_threadstate *threadstate; - if ((threadstate = git_threadstate_get()) == NULL) + if ((threadstate = threadstate_get()) == NULL) return true; - return threadstate->last_error != NULL; + return threadstate->last != NULL; } const git_error *git_error_last(void) { - git_threadstate *threadstate; + struct error_threadstate *threadstate; /* If the library is not initialized, return a static error. */ if (!git_libgit2_init_count()) return &uninitialized_error; - if ((threadstate = git_threadstate_get()) == NULL) + if ((threadstate = threadstate_get()) == NULL) return &tlsdata_error; - if (!threadstate->last_error) + if (!threadstate->last) return &no_error; - return threadstate->last_error; + return threadstate->last; } int git_error_save(git_error **out) { - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); git_error *error, *dup; if (!threadstate) { @@ -218,7 +301,7 @@ int git_error_save(git_error **out) return -1; } - error = threadstate->last_error; + error = threadstate->last; if (!error || error == &no_error) { *out = &no_error; @@ -247,12 +330,12 @@ int git_error_save(git_error **out) int git_error_restore(git_error *error) { - git_threadstate *threadstate = git_threadstate_get(); + struct error_threadstate *threadstate = threadstate_get(); GIT_ASSERT_ARG(error); if (IS_STATIC_ERROR(error) && threadstate) - threadstate->last_error = error; + threadstate->last = error; else set_error(error->klass, error->message); diff --git a/src/libgit2/errors.h b/src/libgit2/errors.h index f929219560d..755fd4db460 100644 --- a/src/libgit2/errors.h +++ b/src/libgit2/errors.h @@ -11,6 +11,9 @@ #include "common.h" #include "git2/sys/errors.h" +/* Initialize the error thread-state. */ +int git_error_global_init(void); + /* * `vprintf`-style formatting for the error message for this thread. */ diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index ec4a699a2ee..715fbec1d79 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -73,6 +73,7 @@ int git_libgit2_init(void) git_win32_leakcheck_global_init, #endif git_allocator_global_init, + git_error_global_init, git_threadstate_global_init, git_threads_global_init, git_rand_global_init, diff --git a/src/libgit2/threadstate.c b/src/libgit2/threadstate.c index ed9bb9b96ff..e521450921d 100644 --- a/src/libgit2/threadstate.c +++ b/src/libgit2/threadstate.c @@ -35,10 +35,6 @@ static void threadstate_dispose(git_threadstate *threadstate) { if (!threadstate) return; - - if (threadstate->error_t.message != git_str__initstr) - git__free(threadstate->error_t.message); - threadstate->error_t.message = NULL; } static void GIT_SYSTEM_CALL threadstate_free(void *threadstate) @@ -87,11 +83,6 @@ git_threadstate *git_threadstate_get(void) memset(threadstate, 0, sizeof(git_threadstate)); - if (git_str_init(&threadstate->error_buf, 0) < 0) { - git__allocator.gfree(threadstate); - return NULL; - } - git_tlsdata_set(tls_key, threadstate); return threadstate; } diff --git a/src/libgit2/threadstate.h b/src/libgit2/threadstate.h index 6ef04192ca9..7a3bbd9a1aa 100644 --- a/src/libgit2/threadstate.h +++ b/src/libgit2/threadstate.h @@ -10,9 +10,6 @@ #include "common.h" typedef struct { - git_error *last_error; - git_error error_t; - git_str error_buf; char oid_fmt[GIT_OID_MAX_HEXSIZE+1]; } git_threadstate; From 36b52506fff2b4c06d1885c648ea22debf7c813c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Aug 2023 12:36:44 +0100 Subject: [PATCH 282/816] errors: move into util --- src/{libgit2 => util}/errors.c | 8 ++++---- src/{libgit2 => util}/errors.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/{libgit2 => util}/errors.c (98%) rename src/{libgit2 => util}/errors.h (98%) diff --git a/src/libgit2/errors.c b/src/util/errors.c similarity index 98% rename from src/libgit2/errors.c rename to src/util/errors.c index cfaa367d925..68e7a415625 100644 --- a/src/libgit2/errors.c +++ b/src/util/errors.c @@ -5,11 +5,11 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "common.h" +#include "git2_util.h" +#include "errors.h" #include "posix.h" #include "str.h" -#include "libgit2.h" #include "runtime.h" /* @@ -23,7 +23,7 @@ static git_error oom_error = { }; static git_error uninitialized_error = { - "libgit2 has not been initialized; you must call git_libgit2_init", + "library has not been initialized", GIT_ERROR_INVALID }; @@ -279,7 +279,7 @@ const git_error *git_error_last(void) struct error_threadstate *threadstate; /* If the library is not initialized, return a static error. */ - if (!git_libgit2_init_count()) + if (!git_runtime_init_count()) return &uninitialized_error; if ((threadstate = threadstate_get()) == NULL) diff --git a/src/libgit2/errors.h b/src/util/errors.h similarity index 98% rename from src/libgit2/errors.h rename to src/util/errors.h index 755fd4db460..8d5877550b1 100644 --- a/src/libgit2/errors.h +++ b/src/util/errors.h @@ -8,7 +8,7 @@ #ifndef INCLUDE_errors_h__ #define INCLUDE_errors_h__ -#include "common.h" +#include "git2_util.h" #include "git2/sys/errors.h" /* Initialize the error thread-state. */ From 1265986b69866f84b01fb7694ac6832c9b249977 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Aug 2023 14:54:47 +0100 Subject: [PATCH 283/816] oid: move thread local storage into oid.c Now that thread-local error data is handled in error, move the thread local data out of the `threadstate` object, since it has now become useless indirection. --- src/libgit2/libgit2.c | 1 + src/libgit2/oid.c | 37 ++++++++++++++++++++++++++++++++----- src/libgit2/oid.h | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 715fbec1d79..2bbbccbae03 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -76,6 +76,7 @@ int git_libgit2_init(void) git_error_global_init, git_threadstate_global_init, git_threads_global_init, + git_oid_global_init, git_rand_global_init, git_hash_global_init, git_sysdir_global_init, diff --git a/src/libgit2/oid.c b/src/libgit2/oid.c index 631a566ebaa..2bb7a6f6bc4 100644 --- a/src/libgit2/oid.c +++ b/src/libgit2/oid.c @@ -9,7 +9,7 @@ #include "git2/oid.h" #include "repository.h" -#include "threadstate.h" +#include "runtime.h" #include #include @@ -153,15 +153,42 @@ int git_oid_pathfmt(char *str, const git_oid *oid) return 0; } +static git_tlsdata_key thread_str_key; + +static void GIT_SYSTEM_CALL thread_str_free(void *s) +{ + char *str = (char *)s; + git__free(str); +} + +static void thread_str_global_shutdown(void) +{ + char *str = git_tlsdata_get(thread_str_key); + git_tlsdata_set(thread_str_key, NULL); + + git__free(str); + git_tlsdata_dispose(thread_str_key); +} + +int git_oid_global_init(void) +{ + if (git_tlsdata_init(&thread_str_key, thread_str_free) != 0) + return -1; + + return git_runtime_shutdown_register(thread_str_global_shutdown); +} + char *git_oid_tostr_s(const git_oid *oid) { - git_threadstate *threadstate = git_threadstate_get(); char *str; - if (!threadstate) - return NULL; + if ((str = git_tlsdata_get(thread_str_key)) == NULL) { + if ((str = git__malloc(GIT_OID_MAX_HEXSIZE + 1)) == NULL) + return NULL; + + git_tlsdata_set(thread_str_key, str); + } - str = threadstate->oid_fmt; git_oid_nfmt(str, git_oid_hexsize(git_oid_type(oid)) + 1, oid); return str; } diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h index 7b6b09d8bb6..f25a899a681 100644 --- a/src/libgit2/oid.h +++ b/src/libgit2/oid.h @@ -270,4 +270,6 @@ int git_oid__fromstrn( int git_oid__fromraw(git_oid *out, const unsigned char *raw, git_oid_t type); +int git_oid_global_init(void); + #endif From 5a63b43d970637158aa02a11bf23b23949bfe32b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Aug 2023 14:56:26 +0100 Subject: [PATCH 284/816] threadstate: remove the thread state object We now have no "big single object" that contains thread state. --- src/libgit2/libgit2.c | 2 - src/libgit2/threadstate.c | 88 --------------------------------------- src/libgit2/threadstate.h | 19 --------- 3 files changed, 109 deletions(-) delete mode 100644 src/libgit2/threadstate.c delete mode 100644 src/libgit2/threadstate.h diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 2bbbccbae03..777dcbbb558 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -26,7 +26,6 @@ #include "runtime.h" #include "sysdir.h" #include "thread.h" -#include "threadstate.h" #include "git2/global.h" #include "streams/registry.h" #include "streams/mbedtls.h" @@ -74,7 +73,6 @@ int git_libgit2_init(void) #endif git_allocator_global_init, git_error_global_init, - git_threadstate_global_init, git_threads_global_init, git_oid_global_init, git_rand_global_init, diff --git a/src/libgit2/threadstate.c b/src/libgit2/threadstate.c deleted file mode 100644 index e521450921d..00000000000 --- a/src/libgit2/threadstate.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "threadstate.h" -#include "runtime.h" - -/** - * Handle the thread-local state - * - * `git_threadstate_global_init` will be called as part - * of `git_libgit2_init` (which itself must be called - * before calling any other function in the library). - * - * This function allocates a TLS index to store the per- - * thread state. - * - * Any internal method that requires thread-local state - * will then call `git_threadstate_get()` which returns a - * pointer to the thread-local state structure; this - * structure is lazily allocated on each thread. - * - * This mechanism will register a shutdown handler - * (`git_threadstate_global_shutdown`) which will free the - * TLS index. This shutdown handler will be called by - * `git_libgit2_shutdown`. - */ - -static git_tlsdata_key tls_key; - -static void threadstate_dispose(git_threadstate *threadstate) -{ - if (!threadstate) - return; -} - -static void GIT_SYSTEM_CALL threadstate_free(void *threadstate) -{ - threadstate_dispose(threadstate); - git__free(threadstate); -} - -static void git_threadstate_global_shutdown(void) -{ - git_threadstate *threadstate; - - threadstate = git_tlsdata_get(tls_key); - git_tlsdata_set(tls_key, NULL); - - threadstate_dispose(threadstate); - git__free(threadstate); - - git_tlsdata_dispose(tls_key); -} - -int git_threadstate_global_init(void) -{ - if (git_tlsdata_init(&tls_key, &threadstate_free) != 0) - return -1; - - return git_runtime_shutdown_register(git_threadstate_global_shutdown); -} - -git_threadstate *git_threadstate_get(void) -{ - git_threadstate *threadstate; - - if ((threadstate = git_tlsdata_get(tls_key)) != NULL) - return threadstate; - - /* - * Avoid git__malloc here, since if it fails, it sets an error - * message, which requires thread state, which would allocate - * here, which would fail, which would set an error message... - */ - - if ((threadstate = git__allocator.gmalloc(sizeof(git_threadstate), - __FILE__, __LINE__)) == NULL) - return NULL; - - memset(threadstate, 0, sizeof(git_threadstate)); - - git_tlsdata_set(tls_key, threadstate); - return threadstate; -} diff --git a/src/libgit2/threadstate.h b/src/libgit2/threadstate.h deleted file mode 100644 index 7a3bbd9a1aa..00000000000 --- a/src/libgit2/threadstate.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_threadstate_h__ -#define INCLUDE_threadstate_h__ - -#include "common.h" - -typedef struct { - char oid_fmt[GIT_OID_MAX_HEXSIZE+1]; -} git_threadstate; - -extern int git_threadstate_global_init(void); -extern git_threadstate *git_threadstate_get(void); - -#endif From 40556c798aa23e13e4e6f859c3e43b7e118a7ab0 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Sat, 9 Sep 2023 20:06:03 -0700 Subject: [PATCH 285/816] add dl to LIBGIT2_SYSTEM_LIBS --- cmake/SelectHTTPSBackend.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index 0b3d63a790c..94a0953f891 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -54,7 +54,7 @@ if(USE_HTTPS) set(GIT_OPENSSL 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR}) - list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) list(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS}) list(APPEND LIBGIT2_PC_REQUIRES "openssl") elseif(USE_HTTPS STREQUAL "mbedTLS") From 8dd5d60e807fc49f136921c7537688de77d6190e Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Sat, 9 Sep 2023 20:50:42 -0700 Subject: [PATCH 286/816] guard --- cmake/SelectHTTPSBackend.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index 94a0953f891..fbc2adc147f 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -54,7 +54,10 @@ if(USE_HTTPS) set(GIT_OPENSSL 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR}) - list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES}) + if(LINK_WITH_STATIC_LIBRARIES STREQUAL ON) + list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_DL_LIBS}) + endif() list(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS}) list(APPEND LIBGIT2_PC_REQUIRES "openssl") elseif(USE_HTTPS STREQUAL "mbedTLS") From 863ff79ff01988b634f7ae4caa5890d5ad83fc68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 19 Sep 2023 21:49:49 +0300 Subject: [PATCH 287/816] net: copy the option-injection detection from git This function returns true if the string starts with a `-` as that could be used to inject options into commands we execute. --- src/util/net.c | 5 +++++ src/util/net.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/util/net.c b/src/util/net.c index afd52ce0830..9c5ff1df44a 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -1152,3 +1152,8 @@ void git_net_url_dispose(git_net_url *url) git__free(url->username); url->username = NULL; git__free(url->password); url->password = NULL; } + +int git_net_looks_like_command_line_option(const char *str) +{ + return str && str[0] == '-'; +} diff --git a/src/util/net.h b/src/util/net.h index 8024956ad0c..1b82bd1dce3 100644 --- a/src/util/net.h +++ b/src/util/net.h @@ -107,4 +107,13 @@ extern bool git_net_url_matches_pattern_list( /** Disposes the contents of the structure. */ extern void git_net_url_dispose(git_net_url *url); + +/** + * Returns true if the string starts with a dash + * + * These could be used to try to trick an executed subcommand like ssh to do + * something other than what we intend. + */ +int git_net_looks_like_command_line_option(const char *str); + #endif From cf7477a82be9e6e59bb509d236d8a1ae2fc8d21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 19 Sep 2023 19:13:46 +0300 Subject: [PATCH 288/816] ssh_exec: detect a potentially malicious ssh url string If you pass along something like `-oProxyCommand=...` as the hostname, we would pass that along to ssh unbeknownst to us and potentially also the user, if they were asking a tool to recursively clone submodules. This is the same fix as mainline git although they don't separate the username and host for ssh so ours looks like it's checking more. --- src/libgit2/transports/ssh_exec.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c index 786e7ee8bdb..1aa7a65d9fc 100644 --- a/src/libgit2/transports/ssh_exec.c +++ b/src/libgit2/transports/ssh_exec.c @@ -132,6 +132,26 @@ static int get_ssh_cmdline( const char *default_ssh_cmd = "ssh"; int error; + /* Safety check: like git, we forbid paths that look like an option as + * that could lead to injection to ssh that can make us do unexpected + * things */ + if (git_net_looks_like_command_line_option(url->username)) { + git_error_set(GIT_ERROR_NET, "strange username '%s' blocked", url->username); + return -1; + } + if (git_net_looks_like_command_line_option(url->host)) { + git_error_set(GIT_ERROR_NET, "strange host '%s' blocked", url->host); + return -1; + } + + /* Safety check: like git, we forbid paths that look like an option as + * that could lead to injection on the remote side */ + if (git_net_looks_like_command_line_option(url->path)) { + git_error_set(GIT_ERROR_NET, "strange path '%s' blocked", url->path); + return -1; + } + + if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) return error; From 517bd0d30c02914e733e7d59742ce791801ece75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 20 Sep 2023 00:39:41 +0300 Subject: [PATCH 289/816] ssh: reject suspicious path Like in the previous commit and in git, we reject a path that looks like an option to avoid injection into the command we ask the remote to execute. --- src/libgit2/transports/ssh_libssh2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index e32587683de..e74205bff00 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -788,6 +788,15 @@ static int _git_ssh_setup_conn( if (error < 0) goto done; + /* Safety check: like git, we forbid paths that look like an option as + * that could lead to injection on the remote side */ + if (git_net_looks_like_command_line_option(s->url.path)) { + git_error_set(GIT_ERROR_NET, "strange path '%s' blocked", s->url.path); + error = -1; + goto done; + } + + if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 || (error = git_stream_connect(s->io)) < 0) goto done; From 687da95ec8d778c475dc17a9b292d5c25647421e Mon Sep 17 00:00:00 2001 From: Antonin Delpeuch Date: Sat, 23 Sep 2023 12:00:19 +0200 Subject: [PATCH 290/816] blame example: Fix support for line range in CLI The -L option announced by the CLI was ignored so far. --- examples/blame.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/blame.c b/examples/blame.c index 77087a5771a..0996e7a1fdb 100644 --- a/examples/blame.c +++ b/examples/blame.c @@ -47,6 +47,10 @@ int lg2_blame(git_repository *repo, int argc, char *argv[]) if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES; if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES; if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT; + if (o.start_line && o.end_line) { + blameopts.min_line = o.start_line; + blameopts.max_line = o.end_line; + } /** * The commit range comes in "committish" form. Use the rev-parse API to From ad3799e8120de26b418a28b1d04c33523809e0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 20 Sep 2023 17:13:28 +0300 Subject: [PATCH 291/816] tests: add tests for injection rejection in ssh exec --- tests/libgit2/transport/ssh_exec.c | 79 ++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/libgit2/transport/ssh_exec.c diff --git a/tests/libgit2/transport/ssh_exec.c b/tests/libgit2/transport/ssh_exec.c new file mode 100644 index 00000000000..886c10ad7c3 --- /dev/null +++ b/tests/libgit2/transport/ssh_exec.c @@ -0,0 +1,79 @@ +#include "clar_libgit2.h" +#include "git2/sys/remote.h" +#include "git2/sys/transport.h" + + +void test_transport_ssh_exec__reject_injection_username(void) +{ +#ifndef GIT_SSH_EXEC + cl_skip(); +#else + git_remote *remote; + git_repository *repo; + git_transport *transport; + const char *url = "-oProxyCommand=git@somehost:somepath"; + git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; + + + cl_git_pass(git_repository_init(&repo, "./transport-username", 0)); + cl_git_pass(git_remote_create(&remote, repo, "test", + cl_fixture("testrepo.git"))); + cl_git_pass(git_transport_new(&transport, remote, url)); + cl_git_fail_with(-1, transport->connect(transport, url, + GIT_SERVICE_UPLOADPACK_LS, &opts)); + + transport->free(transport); + git_remote_free(remote); + git_repository_free(repo); +#endif +} + +void test_transport_ssh_exec__reject_injection_hostname(void) +{ +#ifndef GIT_SSH_EXEC + cl_skip(); +#else + git_remote *remote; + git_repository *repo; + git_transport *transport; + const char *url = "-oProxyCommand=somehost:somepath-hostname"; + git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; + + + cl_git_pass(git_repository_init(&repo, "./transport-hostname", 0)); + cl_git_pass(git_remote_create(&remote, repo, "test", + cl_fixture("testrepo.git"))); + cl_git_pass(git_transport_new(&transport, remote, url)); + cl_git_fail_with(-1, transport->connect(transport, url, + GIT_SERVICE_UPLOADPACK_LS, &opts)); + + transport->free(transport); + git_remote_free(remote); + git_repository_free(repo); +#endif +} + +void test_transport_ssh_exec__reject_injection_path(void) +{ +#ifndef GIT_SSH_EXEC + cl_skip(); +#else + git_remote *remote; + git_repository *repo; + git_transport *transport; + const char *url = "git@somehost:-somepath"; + git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; + + + cl_git_pass(git_repository_init(&repo, "./transport-path", 0)); + cl_git_pass(git_remote_create(&remote, repo, "test", + cl_fixture("testrepo.git"))); + cl_git_pass(git_transport_new(&transport, remote, url)); + cl_git_fail_with(-1, transport->connect(transport, url, + GIT_SERVICE_UPLOADPACK_LS, &opts)); + + transport->free(transport); + git_remote_free(remote); + git_repository_free(repo); +#endif +} From aa5994b0174b8042d3d5a3887c162b6be2cab74f Mon Sep 17 00:00:00 2001 From: Yori Date: Fri, 6 Oct 2023 17:26:55 +1100 Subject: [PATCH 292/816] diff: fix removal of unmodified deltas When finding similar deltas, count the targets that are tagged to be deleted. Apply deletions even in the absense of rewrites or updates. --- src/libgit2/diff_tform.c | 14 ++++++++----- tests/libgit2/diff/rename.c | 41 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/libgit2/diff_tform.c b/src/libgit2/diff_tform.c index 4a156c7a341..7b31905c0f6 100644 --- a/src/libgit2/diff_tform.c +++ b/src/libgit2/diff_tform.c @@ -810,7 +810,7 @@ int git_diff_find_similar( git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; size_t num_deltas, num_srcs = 0, num_tgts = 0; size_t tried_srcs = 0, tried_tgts = 0; - size_t num_rewrites = 0, num_updates = 0, num_bumped = 0; + size_t num_rewrites = 0, num_updates = 0, num_bumped = 0, num_to_delete = 0; size_t sigcache_size; void **sigcache = NULL; /* cache of similarity metric file signatures */ diff_find_match *tgt2src = NULL; @@ -852,11 +852,14 @@ int git_diff_find_similar( if ((tgt->flags & GIT_DIFF_FLAG__TO_SPLIT) != 0) num_rewrites++; + + if ((tgt->flags & GIT_DIFF_FLAG__TO_DELETE) != 0) + num_to_delete++; } - /* if there are no candidate srcs or tgts, we're done */ + /* If there are no candidate srcs or tgts, no need to find matches */ if (!num_srcs || !num_tgts) - goto cleanup; + goto split_and_delete; src2tgt = git__calloc(num_deltas, sizeof(diff_find_match)); GIT_ERROR_CHECK_ALLOC(src2tgt); @@ -1093,13 +1096,14 @@ int git_diff_find_similar( } } +split_and_delete: /* * Actually split and delete entries as needed */ - if (num_rewrites > 0 || num_updates > 0) + if (num_rewrites > 0 || num_updates > 0 || num_to_delete > 0) error = apply_splits_and_deletes( - diff, diff->deltas.length - num_rewrites, + diff, diff->deltas.length - num_rewrites - num_to_delete, FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES) && !FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY)); diff --git a/tests/libgit2/diff/rename.c b/tests/libgit2/diff/rename.c index 9d44394624d..2fbcb2f7087 100644 --- a/tests/libgit2/diff/rename.c +++ b/tests/libgit2/diff/rename.c @@ -1441,6 +1441,47 @@ void test_diff_rename__can_delete_unmodified_deltas(void) git_str_dispose(&c1); } +void test_diff_rename__can_delete_unmodified_deltas_without_changes(void) +{ + git_str c1 = GIT_STR_INIT; + git_index *index; + git_tree *tree; + git_diff *diff; + git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; + git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; + diff_expects exp; + + cl_git_pass( + git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_read_tree(index, tree)); + + diffopts.flags = GIT_DIFF_INCLUDE_UNMODIFIED; + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); + + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNMODIFIED]); + + opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_REMOVE_UNMODIFIED; + cl_git_pass(git_diff_find_similar(diff, &opts)); + + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(0, exp.files); + + git_diff_free(diff); + git_tree_free(tree); + git_index_free(index); + + git_str_dispose(&c1); +} + void test_diff_rename__matches_config_behavior(void) { const char *sha0 = INITIAL_COMMIT; From e69ca3212ce4482863d89a341a27c57bf0256f2f Mon Sep 17 00:00:00 2001 From: Yori Date: Sat, 7 Oct 2023 13:28:37 +1100 Subject: [PATCH 293/816] diff: fix removal of unmodified non-blob deltas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When excluding non-blob deltas as potential rename sources, honour the “remove unmodified” option (if the delta is unmodified). --- src/libgit2/diff_tform.c | 9 ++++++++- tests/libgit2/diff/rename.c | 21 +++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/libgit2/diff_tform.c b/src/libgit2/diff_tform.c index 7b31905c0f6..a90ab07c9b9 100644 --- a/src/libgit2/diff_tform.c +++ b/src/libgit2/diff_tform.c @@ -718,8 +718,15 @@ static bool is_rename_source( git_diff_delta *delta = GIT_VECTOR_GET(&diff->deltas, delta_idx); /* skip things that aren't blobs */ - if (!GIT_MODE_ISBLOB(delta->old_file.mode)) + if (!GIT_MODE_ISBLOB(delta->old_file.mode)) { + + /* but still honor "remove unmodified" flag */ + if (delta->status == GIT_DELTA_UNMODIFIED && + FLAG_SET(opts, GIT_DIFF_FIND_REMOVE_UNMODIFIED)) + delta->flags |= GIT_DIFF_FLAG__TO_DELETE; + return false; + } switch (delta->status) { case GIT_DELTA_ADDED: diff --git a/tests/libgit2/diff/rename.c b/tests/libgit2/diff/rename.c index 2fbcb2f7087..61a2f839cb3 100644 --- a/tests/libgit2/diff/rename.c +++ b/tests/libgit2/diff/rename.c @@ -1441,9 +1441,9 @@ void test_diff_rename__can_delete_unmodified_deltas(void) git_str_dispose(&c1); } -void test_diff_rename__can_delete_unmodified_deltas_without_changes(void) +void test_diff_rename__can_delete_unmodified_deltas_including_submodule(void) { - git_str c1 = GIT_STR_INIT; + git_repository *repo; /* "submodules" */ git_index *index; git_tree *tree; git_diff *diff; @@ -1451,21 +1451,26 @@ void test_diff_rename__can_delete_unmodified_deltas_without_changes(void) git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; + cl_git_sandbox_cleanup(); /* Don't use "renames" for this test */ + repo = cl_git_sandbox_init("submodules"); + + cl_repo_set_bool(repo, "core.autocrlf", false); + cl_git_pass( - git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); + git_revparse_single((git_object **)&tree, repo, "HEAD^{tree}")); - cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_read_tree(index, tree)); diffopts.flags = GIT_DIFF_INCLUDE_UNMODIFIED; - cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); + cl_git_pass(git_diff_tree_to_index(&diff, repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); - cl_assert_equal_i(4, exp.files); - cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(5, exp.files); + cl_assert_equal_i(5, exp.file_status[GIT_DELTA_UNMODIFIED]); opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_REMOVE_UNMODIFIED; cl_git_pass(git_diff_find_similar(diff, &opts)); @@ -1479,7 +1484,7 @@ void test_diff_rename__can_delete_unmodified_deltas_without_changes(void) git_tree_free(tree); git_index_free(index); - git_str_dispose(&c1); + cl_git_sandbox_cleanup(); } void test_diff_rename__matches_config_behavior(void) From 95e517bee5ad4ddb1c2344cbfe6c7ad15ca78cd3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 15 Oct 2023 13:53:21 +0100 Subject: [PATCH 294/816] remote: optionally report unchanged tips --- include/git2/remote.h | 30 +++++++++++++----- src/libgit2/clone.c | 2 +- src/libgit2/remote.c | 59 +++++++++++++++++++++--------------- tests/libgit2/online/fetch.c | 45 ++++++++++++++++++++++++++- 4 files changed, 103 insertions(+), 33 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index e9065b250c1..87577123c8d 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -76,6 +76,17 @@ typedef enum { GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC = (1 << 1) } git_remote_create_flags; +/** + * How to handle reference updates. + */ +typedef enum { + /* Write the fetch results to FETCH_HEAD. */ + GIT_REMOTE_UPDATE_FETCHHEAD = (1 << 0), + + /* Report unchanged tips in the update_tips callback. */ + GIT_REMOTE_UPDATE_REPORT_UNCHANGED = (1 << 1) +} git_remote_update_flags; + /** * Remote creation options structure * @@ -733,10 +744,10 @@ typedef struct { git_fetch_prune_t prune; /** - * Whether to write the results to FETCH_HEAD. Defaults to - * on. Leave this default in order to behave like git. + * How to handle reference updates; a combination of + * `git_remote_update_flags`. */ - int update_fetchhead; + unsigned int update_flags; /** * Determines how to behave regarding tags on the remote, such @@ -775,8 +786,13 @@ typedef struct { } git_fetch_options; #define GIT_FETCH_OPTIONS_VERSION 1 -#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ - GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT } +#define GIT_FETCH_OPTIONS_INIT { \ + GIT_FETCH_OPTIONS_VERSION, \ + GIT_REMOTE_CALLBACKS_INIT, \ + GIT_FETCH_PRUNE_UNSPECIFIED, \ + GIT_REMOTE_UPDATE_FETCHHEAD, \ + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, \ + GIT_PROXY_OPTIONS_INIT } /** * Initialize git_fetch_options structure @@ -1001,7 +1017,7 @@ GIT_EXTERN(int) git_remote_upload( * the name of the remote (or its url, for in-memory remotes). This * parameter is ignored when pushing. * @param callbacks pointer to the callback structure to use or NULL - * @param update_fetchhead whether to write to FETCH_HEAD. Pass 1 to behave like git. + * @param update_flags the git_remote_update_flags for these tips. * @param download_tags what the behaviour for downloading tags is for this fetch. This is * ignored for push. This must be the same value passed to `git_remote_download()`. * @return 0 or an error code @@ -1009,7 +1025,7 @@ GIT_EXTERN(int) git_remote_upload( GIT_EXTERN(int) git_remote_update_tips( git_remote *remote, const git_remote_callbacks *callbacks, - int update_fetchhead, + unsigned int update_flags, git_remote_autotag_option_t download_tags, const char *reflog_message); diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index ab48191cc6a..27bae1ac499 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -419,7 +419,7 @@ static int clone_into( return error; memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); - fetch_opts.update_fetchhead = 0; + fetch_opts.update_flags = ~GIT_REMOTE_UPDATE_FETCHHEAD; if (!opts->depth) fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index fee2a7f3968..97d32200c66 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1348,13 +1348,14 @@ int git_remote_fetch( const git_fetch_options *opts, const char *reflog_message) { - int error, update_fetchhead = 1; git_remote_autotag_option_t tagopt = remote->download_tags; bool prune = false; git_str reflog_msg_buf = GIT_STR_INIT; git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; unsigned int capabilities; git_oid_t oid_type; + unsigned int update_flags = GIT_REMOTE_UPDATE_FETCHHEAD; + int error; GIT_ASSERT_ARG(remote); @@ -1371,7 +1372,7 @@ int git_remote_fetch( return error; if (opts) { - update_fetchhead = opts->update_fetchhead; + update_flags = opts->update_flags; tagopt = opts->download_tags; } @@ -1398,8 +1399,14 @@ int git_remote_fetch( } /* Create "remote/foo" branches for all remote branches */ - error = git_remote_update_tips(remote, &connect_opts.callbacks, update_fetchhead, tagopt, git_str_cstr(&reflog_msg_buf)); + error = git_remote_update_tips(remote, + &connect_opts.callbacks, + update_flags, + tagopt, + git_str_cstr(&reflog_msg_buf)); + git_str_dispose(&reflog_msg_buf); + if (error < 0) goto done; @@ -1774,6 +1781,7 @@ static int update_one_tip( git_refspec *spec, git_remote_head *head, git_refspec *tagspec, + unsigned int update_flags, git_remote_autotag_option_t tagopt, const char *log_message, const git_remote_callbacks *callbacks) @@ -1781,7 +1789,7 @@ static int update_one_tip( git_odb *odb; git_str refname = GIT_STR_INIT; git_reference *ref = NULL; - bool autotag = false; + bool autotag = false, updated = false; git_oid old; int valid; int error; @@ -1855,21 +1863,21 @@ static int update_one_tip( goto done; } - if (!git_oid__cmp(&old, &head->oid)) - goto done; + if ((updated = !git_oid_equal(&old, &head->oid))) { + /* In autotag mode, don't overwrite any locally-existing tags */ + error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag, + log_message); - /* In autotag mode, don't overwrite any locally-existing tags */ - error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag, - log_message); - - if (error < 0) { - if (error == GIT_EEXISTS) - error = 0; + if (error < 0) { + if (error == GIT_EEXISTS) + error = 0; - goto done; + goto done; + } } if (callbacks && callbacks->update_tips != NULL && + (updated || (update_flags & GIT_REMOTE_UPDATE_REPORT_UNCHANGED)) && (error = callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload)) < 0) git_error_set_after_callback_function(error, "git_remote_fetch"); @@ -1882,7 +1890,7 @@ static int update_one_tip( static int update_tips_for_spec( git_remote *remote, const git_remote_callbacks *callbacks, - int update_fetchhead, + unsigned int update_flags, git_remote_autotag_option_t tagopt, git_refspec *spec, git_vector *refs, @@ -1905,7 +1913,10 @@ static int update_tips_for_spec( /* Update tips based on the remote heads */ git_vector_foreach(refs, i, head) { - if (update_one_tip(&update_heads, remote, spec, head, &tagspec, tagopt, log_message, callbacks) < 0) + if (update_one_tip(&update_heads, + remote, spec, head, &tagspec, + update_flags, tagopt, log_message, + callbacks) < 0) goto on_error; } @@ -1927,7 +1938,7 @@ static int update_tips_for_spec( goto on_error; } - if (update_fetchhead && + if ((update_flags & GIT_REMOTE_UPDATE_FETCHHEAD) && (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0) goto on_error; @@ -2058,11 +2069,11 @@ static int truncate_fetch_head(const char *gitdir) } int git_remote_update_tips( - git_remote *remote, - const git_remote_callbacks *callbacks, - int update_fetchhead, - git_remote_autotag_option_t download_tags, - const char *reflog_message) + git_remote *remote, + const git_remote_callbacks *callbacks, + unsigned int update_flags, + git_remote_autotag_option_t download_tags, + const char *reflog_message) { git_refspec *spec, tagspec; git_vector refs = GIT_VECTOR_INIT; @@ -2091,7 +2102,7 @@ int git_remote_update_tips( goto out; if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { - if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0) + if ((error = update_tips_for_spec(remote, callbacks, update_flags, tagopt, &tagspec, &refs, reflog_message)) < 0) goto out; } @@ -2099,7 +2110,7 @@ int git_remote_update_tips( if (spec->push) continue; - if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0) + if ((error = update_tips_for_spec(remote, callbacks, update_flags, tagopt, spec, &refs, reflog_message)) < 0) goto out; } diff --git a/tests/libgit2/online/fetch.c b/tests/libgit2/online/fetch.c index a557bbf7506..d640eac1b6c 100644 --- a/tests/libgit2/online/fetch.c +++ b/tests/libgit2/online/fetch.c @@ -128,6 +128,8 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date git_clone_options opts = GIT_CLONE_OPTIONS_INIT; opts.bare = true; + counter = 0; + cl_git_pass(git_clone(&_repository, "https://github.com/libgit2/TestGitRepository.git", "./fetch/lg2", &opts)); git_repository_free(_repository); @@ -141,11 +143,52 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date options.callbacks.transfer_progress = &transferProgressCallback; options.callbacks.payload = &invoked; + options.callbacks.update_tips = update_tips; cl_git_pass(git_remote_download(remote, NULL, &options)); cl_assert_equal_i(false, invoked); - cl_git_pass(git_remote_update_tips(remote, &options.callbacks, 1, options.download_tags, NULL)); + cl_git_pass(git_remote_update_tips(remote, &options.callbacks, GIT_REMOTE_UPDATE_FETCHHEAD, options.download_tags, NULL)); + cl_assert_equal_i(0, counter); + + git_remote_disconnect(remote); + + git_remote_free(remote); + git_repository_free(_repository); +} + +void test_online_fetch__report_unchanged_tips(void) +{ + git_repository *_repository; + bool invoked = false; + git_remote *remote; + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + opts.bare = true; + + counter = 0; + + cl_git_pass(git_clone(&_repository, "https://github.com/libgit2/TestGitRepository.git", + "./fetch/lg2", &opts)); + git_repository_free(_repository); + + cl_git_pass(git_repository_open(&_repository, "./fetch/lg2")); + + cl_git_pass(git_remote_lookup(&remote, _repository, "origin")); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + + cl_assert_equal_i(false, invoked); + + options.callbacks.transfer_progress = &transferProgressCallback; + options.callbacks.payload = &invoked; + options.callbacks.update_tips = update_tips; + cl_git_pass(git_remote_download(remote, NULL, &options)); + + cl_assert_equal_i(false, invoked); + + cl_git_pass(git_remote_update_tips(remote, &options.callbacks, GIT_REMOTE_UPDATE_REPORT_UNCHANGED, options.download_tags, NULL)); + cl_assert(counter > 0); + git_remote_disconnect(remote); git_remote_free(remote); From 7a060cc5bc9ca79e1d1e3e456d92b1985456d5b9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 15 Oct 2023 21:53:43 +0100 Subject: [PATCH 295/816] ssh: option injection code review --- src/libgit2/transports/ssh_exec.c | 26 +++++++++++--------------- src/libgit2/transports/ssh_libssh2.c | 5 +++-- src/util/net.c | 5 ----- src/util/net.h | 9 --------- src/util/process.h | 11 +++++++++++ 5 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c index 1aa7a65d9fc..a09c1db9441 100644 --- a/src/libgit2/transports/ssh_exec.c +++ b/src/libgit2/transports/ssh_exec.c @@ -132,26 +132,22 @@ static int get_ssh_cmdline( const char *default_ssh_cmd = "ssh"; int error; - /* Safety check: like git, we forbid paths that look like an option as - * that could lead to injection to ssh that can make us do unexpected - * things */ - if (git_net_looks_like_command_line_option(url->username)) { - git_error_set(GIT_ERROR_NET, "strange username '%s' blocked", url->username); + /* + * Safety check: like git, we forbid paths that look like an + * option as that could lead to injection to ssh that can make + * us do unexpected things + */ + if (git_process__is_cmdline_option(url->username)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: username '%s' is ambiguous with command-line option", url->username); return -1; - } - if (git_net_looks_like_command_line_option(url->host)) { - git_error_set(GIT_ERROR_NET, "strange host '%s' blocked", url->host); + } else if (git_process__is_cmdline_option(url->host)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: host '%s' is ambiguous with command-line option", url->host); return -1; - } - - /* Safety check: like git, we forbid paths that look like an option as - * that could lead to injection on the remote side */ - if (git_net_looks_like_command_line_option(url->path)) { - git_error_set(GIT_ERROR_NET, "strange path '%s' blocked", url->path); + } else if (git_process__is_cmdline_option(url->path)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: path '%s' is ambiguous with command-line option", url->path); return -1; } - if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) return error; diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index e74205bff00..d2be2ba3387 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -14,6 +14,7 @@ #include "runtime.h" #include "net.h" #include "smart.h" +#include "process.h" #include "streams/socket.h" #include "sysdir.h" @@ -790,8 +791,8 @@ static int _git_ssh_setup_conn( /* Safety check: like git, we forbid paths that look like an option as * that could lead to injection on the remote side */ - if (git_net_looks_like_command_line_option(s->url.path)) { - git_error_set(GIT_ERROR_NET, "strange path '%s' blocked", s->url.path); + if (git_process__is_cmdline_option(s->url.path)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: path '%s' is ambiguous with command-line option", s->url.path); error = -1; goto done; } diff --git a/src/util/net.c b/src/util/net.c index 9c5ff1df44a..afd52ce0830 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -1152,8 +1152,3 @@ void git_net_url_dispose(git_net_url *url) git__free(url->username); url->username = NULL; git__free(url->password); url->password = NULL; } - -int git_net_looks_like_command_line_option(const char *str) -{ - return str && str[0] == '-'; -} diff --git a/src/util/net.h b/src/util/net.h index 1b82bd1dce3..8024956ad0c 100644 --- a/src/util/net.h +++ b/src/util/net.h @@ -107,13 +107,4 @@ extern bool git_net_url_matches_pattern_list( /** Disposes the contents of the structure. */ extern void git_net_url_dispose(git_net_url *url); - -/** - * Returns true if the string starts with a dash - * - * These could be used to try to trick an executed subcommand like ssh to do - * something other than what we intend. - */ -int git_net_looks_like_command_line_option(const char *str); - #endif diff --git a/src/util/process.h b/src/util/process.h index 87cf7acbd0c..9310652c325 100644 --- a/src/util/process.h +++ b/src/util/process.h @@ -106,6 +106,17 @@ extern int git_process__cmdline( #endif +/* + * Whether the given string looks like a command line option (starts + * with a dash). This is useful for examining strings that will become + * cmdline arguments to ensure that they are not erroneously treated + * as an option. For example, arguments to `ssh`. + */ +GIT_INLINE(bool) git_process__is_cmdline_option(const char *str) +{ + return (str && str[0] == '-'); +} + /** * Start the process. * From ffc12e66731ee002b35d498744fd2d767a95766a Mon Sep 17 00:00:00 2001 From: 7Ji Date: Tue, 31 Oct 2023 16:31:39 +0800 Subject: [PATCH 296/816] remote: fix memory leak in git_remote_download() connect_opts is created with its custom_headers and proxy_opts->url possibly allocated on heap, just like in git_remote_fetch(). But unlike in _fetch(), it is not disposed at the end of the function, thus causing memory leak. --- src/libgit2/remote.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 97d32200c66..fc37cf2a5ae 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1339,7 +1339,11 @@ int git_remote_download( if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0) return error; - return git_remote__download(remote, refspecs, opts); + error = git_remote__download(remote, refspecs, opts); + + git_remote_connect_options_dispose(&connect_opts); + + return error; } int git_remote_fetch( From cf320cc125e589a4de109de9098d54098f03b31b Mon Sep 17 00:00:00 2001 From: Yuriy Chernyshov Date: Wed, 15 Nov 2023 16:03:07 +0300 Subject: [PATCH 297/816] Do not trim dots from usernames --- src/libgit2/signature.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libgit2/signature.c b/src/libgit2/signature.c index 5d6ab572cbf..12d2b5f8d50 100644 --- a/src/libgit2/signature.c +++ b/src/libgit2/signature.c @@ -43,7 +43,6 @@ static bool contains_angle_brackets(const char *input) static bool is_crud(unsigned char c) { return c <= 32 || - c == '.' || c == ',' || c == ':' || c == ';' || From 51f0b0211bf8bb919ce5d3e600b7a7e281baba1f Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Fri, 17 Nov 2023 18:25:09 +0100 Subject: [PATCH 298/816] util: make git_futils_readbuffer_updated header match source --- src/util/futils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/futils.h b/src/util/futils.h index 3f207afb2f2..53bcc551890 100644 --- a/src/util/futils.h +++ b/src/util/futils.h @@ -25,7 +25,7 @@ extern int git_futils_readbuffer(git_str *obj, const char *path); extern int git_futils_readbuffer_updated( git_str *obj, const char *path, - unsigned char checksum[GIT_HASH_SHA1_SIZE], + unsigned char checksum[GIT_HASH_SHA256_SIZE], int *updated); extern int git_futils_readbuffer_fd_full(git_str *obj, git_file fd); extern int git_futils_readbuffer_fd(git_str *obj, git_file fd, size_t len); From b1b2f063c305c00253fa6204cf4c3c24f5e087be Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 20 Nov 2023 12:39:44 +0000 Subject: [PATCH 299/816] Update tests/resources/push.sh --- tests/resources/push.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/push.sh b/tests/resources/push.sh index 54ef3ddf27c..648c2ad26f5 100644 --- a/tests/resources/push.sh +++ b/tests/resources/push.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash #creates push_src repo for libgit2 push tests. set -eu From a8cca4d5373f94cb5838715e0d3381a0f1dd79fb Mon Sep 17 00:00:00 2001 From: Yuriy Chernyshov Date: Tue, 21 Nov 2023 15:25:45 +0300 Subject: [PATCH 300/816] Update tests --- tests/libgit2/commit/signature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libgit2/commit/signature.c b/tests/libgit2/commit/signature.c index a91551415d6..32058f6c344 100644 --- a/tests/libgit2/commit/signature.c +++ b/tests/libgit2/commit/signature.c @@ -39,7 +39,7 @@ void test_commit_signature__leading_and_trailing_spaces_are_trimmed(void) void test_commit_signature__leading_and_trailing_crud_is_trimmed(void) { assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", "\"nulltoken\"", "\"emeric.fermas@gmail.com\""); - assert_name_and_email("nulltoken w", "emeric.fermas@gmail.com", "nulltoken w.", "emeric.fermas@gmail.com"); + assert_name_and_email("nulltoken w", "emeric.fermas@gmail.com", "nulltoken w;", "emeric.fermas@gmail.com"); assert_name_and_email("nulltoken \xe2\x98\xba", "emeric.fermas@gmail.com", "nulltoken \xe2\x98\xba", "emeric.fermas@gmail.com"); } From 1f54d5bb5aae79b4f0ebd7767bac671903e54ed5 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Fri, 17 Nov 2023 19:19:12 +0100 Subject: [PATCH 301/816] util: suppress some uninitialized variable warnings --- src/util/net.c | 2 +- src/util/regexp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/net.c b/src/util/net.c index afd52ce0830..24782d2af09 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -657,7 +657,7 @@ static bool has_at(const char *str) int git_net_url_parse_scp(git_net_url *url, const char *given) { const char *default_port = default_port_for_scheme("ssh"); - const char *c, *user, *host, *port, *path = NULL; + const char *c, *user, *host, *port = NULL, *path = NULL; size_t user_len = 0, host_len = 0, port_len = 0; unsigned short bracket = 0; diff --git a/src/util/regexp.c b/src/util/regexp.c index 08700882bc3..eb45822474d 100644 --- a/src/util/regexp.c +++ b/src/util/regexp.c @@ -125,7 +125,7 @@ int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, if ((data = pcre2_match_data_create(nmatches, NULL)) == NULL) { git_error_set_oom(); - goto out; + return -1; } if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string), From db013b5333e8f0808ea7cdf91ab7398b1e835181 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Mon, 20 Nov 2023 10:18:22 +0100 Subject: [PATCH 302/816] util: replace index (deprecated) with strchr --- src/util/unix/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 7f88ccff067..0c2029acb95 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -37,7 +37,7 @@ struct git_process { GIT_INLINE(bool) is_delete_env(const char *env) { - char *c = index(env, '='); + char *c = strchr(env, '='); if (c == NULL) return false; From 3889ea5eb173b2bd9366e9547da62b3b932c5683 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Mon, 20 Nov 2023 10:42:12 +0100 Subject: [PATCH 303/816] util: include git2/deprecated.h in errors.c In C99 functions need to be declared before they are defined. We could just add the declarations before them, but including the header allows the compiler to warn if they differ. --- src/util/errors.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/errors.c b/src/util/errors.c index 68e7a415625..feed6a835f5 100644 --- a/src/util/errors.c +++ b/src/util/errors.c @@ -376,6 +376,9 @@ void git_error_system_set(int code) /* Deprecated error values and functions */ #ifndef GIT_DEPRECATE_HARD + +#include "git2/deprecated.h" + const git_error *giterr_last(void) { return git_error_last(); From bde119e71a3364d3abd8201fc91da15baff99224 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Sun, 26 Nov 2023 01:02:47 +0100 Subject: [PATCH 304/816] util: sudo_uid_lookup should always return error if out isn't set --- src/util/fs_path.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/util/fs_path.c b/src/util/fs_path.c index e03fcf7c760..ab64778c23e 100644 --- a/src/util/fs_path.c +++ b/src/util/fs_path.c @@ -1938,12 +1938,13 @@ static int sudo_uid_lookup(uid_t *out) { git_str uid_str = GIT_STR_INIT; int64_t uid; - int error; + int error = -1; - if ((error = git__getenv(&uid_str, "SUDO_UID")) == 0 && - (error = git__strntol64(&uid, uid_str.ptr, uid_str.size, NULL, 10)) == 0 && - uid == (int64_t)((uid_t)uid)) { + if (git__getenv(&uid_str, "SUDO_UID") == 0 && + git__strntol64(&uid, uid_str.ptr, uid_str.size, NULL, 10) == 0 && + uid == (int64_t)((uid_t)uid)) { *out = (uid_t)uid; + error = 0; } git_str_dispose(&uid_str); From 4ed1bd1578f7b4d30138cc11dab212d0cfb3c1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 6 Dec 2023 11:50:29 +0100 Subject: [PATCH 305/816] fetch: enable deepening/shortening shallow clones A shallow repository can currently only be completely unshallowed, which is caused by mark_local() only marking locally-existing objects as wanted if the fetch depth is set to INT_MAX (GIT_FETCH_DEPTH_UNSHALLOW). This prevents deepening the history of a shallow clone to an arbitrary number of commits, which may be preferable over full unshallowing for large repositories. Enable deepening and shortening shallow clones by marking locally-existing objects as wanted whenever the fetch depth is set to any non-default value (either GIT_FETCH_DEPTH_UNSHALLOW or an arbitrary positive integer). --- src/libgit2/fetch.c | 8 +-- tests/libgit2/online/shallow.c | 99 ++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index d74abb4a847..8e2660f2172 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -60,9 +60,11 @@ static int mark_local(git_remote *remote) git_vector_foreach(&remote->refs, i, head) { /* If we have the object, mark it so we don't ask for it. - However if we are unshallowing, we need to ask for it - even though the head exists locally. */ - if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid)) + However if we are unshallowing or changing history + depth, we need to ask for it even though the head + exists locally. */ + if (remote->nego.depth == GIT_FETCH_DEPTH_FULL && + git_odb_exists(odb, &head->oid)) head->local = 1; else remote->need_pack = 1; diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c index 5c0e6565b03..ee4aaf37ed4 100644 --- a/tests/libgit2/online/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -164,3 +164,102 @@ void test_online_shallow__unshallow(void) git_revwalk_free(walk); git_repository_free(repo); } + +void test_online_shallow__deepen_six(void) +{ + git_str path = GIT_STR_INIT; + git_repository *repo; + git_revwalk *walk; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + git_remote *origin = NULL; + git_oid oid; + git_oid *roots; + size_t roots_len; + size_t num_commits = 0; + int error = 0; + + clone_opts.fetch_opts.depth = 5; + clone_opts.remote_cb = remote_single_branch; + + git_str_joinpath(&path, clar_sandbox_path(), "deepen_6"); + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + fetch_opts.depth = 6; + cl_git_pass(git_remote_lookup(&origin, repo, "origin")); + cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(4, roots_len); + cl_assert_equal_s("58be4659bb571194ed4562d04b359d26216f526e", git_oid_tostr_s(&roots[0])); + cl_assert_equal_s("d31f5a60d406e831d056b8ac2538d515100c2df2", git_oid_tostr_s(&roots[1])); + cl_assert_equal_s("6462e7d8024396b14d7651e2ec11e2bbf07a05c4", git_oid_tostr_s(&roots[2])); + cl_assert_equal_s("2c349335b7f797072cf729c4f3bb0914ecb6dec9", git_oid_tostr_s(&roots[3])); + + git_revwalk_new(&walk, repo); + git_revwalk_push_head(walk); + + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + + cl_assert_equal_i(num_commits, 17); + cl_assert_equal_i(error, GIT_ITEROVER); + + git__free(roots); + git_remote_free(origin); + git_str_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +} + +void test_online_shallow__shorten_four(void) +{ + git_str path = GIT_STR_INIT; + git_repository *repo; + git_revwalk *walk; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + git_remote *origin = NULL; + git_oid oid; + git_oid *roots; + size_t roots_len; + size_t num_commits = 0; + int error = 0; + + clone_opts.fetch_opts.depth = 5; + clone_opts.remote_cb = remote_single_branch; + + git_str_joinpath(&path, clar_sandbox_path(), "shorten_4"); + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + fetch_opts.depth = 4; + cl_git_pass(git_remote_lookup(&origin, repo, "origin")); + cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(3, roots_len); + cl_assert_equal_s("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864", git_oid_tostr_s(&roots[0])); + cl_assert_equal_s("59706a11bde2b9899a278838ef20a97e8f8795d2", git_oid_tostr_s(&roots[1])); + cl_assert_equal_s("bab66b48f836ed950c99134ef666436fb07a09a0", git_oid_tostr_s(&roots[2])); + + git_revwalk_new(&walk, repo); + git_revwalk_push_head(walk); + + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + + cl_assert_equal_i(num_commits, 10); + cl_assert_equal_i(error, GIT_ITEROVER); + + git__free(roots); + git_remote_free(origin); + git_str_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +} From e8ed8dae62e6073c143675e078e612dbcb0d0aa0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 8 Dec 2023 10:52:05 +0000 Subject: [PATCH 306/816] ci: install fewer brew dependencies on macOS GitHub Actions has borked their homebrew setup by first `brew installing` things into `/usr/local` _and then_ putting their own things in their place (eg `python`). This breaks Homebrew, since it thinks it has `python` installed, but it's actually something else. Try to avoid using things that are in this bad state. https://github.com/orgs/community/discussions/78266 --- ci/setup-osx-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/setup-osx-build.sh b/ci/setup-osx-build.sh index 0b95e7629e4..426aa1c7414 100755 --- a/ci/setup-osx-build.sh +++ b/ci/setup-osx-build.sh @@ -3,6 +3,6 @@ set -ex brew update -brew install pkgconfig zlib curl openssl libssh2 ninja +brew install pkgconfig libssh2 ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib From e002004686109945cbf6089e18bc65d1a85bce12 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 8 Dec 2023 16:22:44 +0000 Subject: [PATCH 307/816] ci: use Ninja on macOS --- .github/workflows/main.yml | 2 ++ ci/setup-osx-build.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index eba3b055a6d..5e456a81698 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,6 +67,7 @@ jobs: env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON + CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true @@ -181,6 +182,7 @@ jobs: env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true diff --git a/ci/setup-osx-build.sh b/ci/setup-osx-build.sh index 426aa1c7414..511d886cb17 100755 --- a/ci/setup-osx-build.sh +++ b/ci/setup-osx-build.sh @@ -3,6 +3,6 @@ set -ex brew update -brew install pkgconfig libssh2 +brew install pkgconfig libssh2 ninja ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib From a6164cb4f1720d2204f477fa781414146e4db5d6 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 9 Dec 2023 16:32:55 +0100 Subject: [PATCH 308/816] Avoid macro redefinition of ENABLE_INTSAFE_SIGNED_FUNCTIONS Signed-off-by: Sven Strickroth --- src/util/integer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/integer.h b/src/util/integer.h index 63277177bf3..a9e416cc342 100644 --- a/src/util/integer.h +++ b/src/util/integer.h @@ -89,7 +89,9 @@ GIT_INLINE(int) git__is_int(int64_t p) /* Use Microsoft's safe integer handling functions where available */ #elif defined(_MSC_VER) -# define ENABLE_INTSAFE_SIGNED_FUNCTIONS +# if !defined(ENABLE_INTSAFE_SIGNED_FUNCTIONS) +# define ENABLE_INTSAFE_SIGNED_FUNCTIONS +# endif # include # define git__add_sizet_overflow(out, one, two) \ From cc965243d67c8fe524bbf47315e481b9a55328a1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 13 Dec 2023 16:38:32 +0000 Subject: [PATCH 309/816] process: test /usr/bin/false on BSDs Our process tests were previously testing that false is `/bin/false` everywhere except macOS, where it exists as `/usr/bin/false`. . Extend this to all BSDs. --- tests/util/process/start.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/util/process/start.c b/tests/util/process/start.c index d130c7efbbb..19ae5e312a4 100644 --- a/tests/util/process/start.c +++ b/tests/util/process/start.c @@ -38,9 +38,10 @@ void test_process_start__cleanup(void) void test_process_start__returncode(void) { -#ifdef GIT_WIN32 +#if defined(GIT_WIN32) const char *args_array[] = { "C:\\Windows\\System32\\cmd.exe", "/c", "exit", "1" }; -#elif __APPLE__ +#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__MidnightBSD__) || defined(__DragonFly__) const char *args_array[] = { "/usr/bin/false" }; #else const char *args_array[] = { "/bin/false" }; From 779263be0d8601d866ed62619e96ddfa77c9b78f Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sun, 10 Dec 2023 10:17:44 +0100 Subject: [PATCH 310/816] Do not normalize safe.directory paths Vanilla Git does not do it either (cf. https://github.com/gitster/git/blob/master/setup.c#L1150) and calling git_fs_path_prettify_dir can cause performance issues (cf. issue #6649). Signed-off-by: Sven Strickroth --- src/libgit2/repository.c | 18 +++++++++++------- tests/libgit2/repo/open.c | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 05ece6efc41..26741bbbc67 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -537,8 +537,7 @@ static int read_gitfile(git_str *path_out, const char *file_path) } typedef struct { - const char *repo_path; - git_str tmp; + git_str repo_path; bool *is_safe; } validate_ownership_data; @@ -582,9 +581,7 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) strncmp(test_path, "//wsl.localhost/", strlen("//wsl.localhost/")) != 0) test_path++; #endif - - if (git_fs_path_prettify_dir(&data->tmp, test_path, NULL) == 0 && - strcmp(data->tmp.ptr, data->repo_path) == 0) + if (strcmp(test_path, data->repo_path.ptr) == 0) *data->is_safe = true; } @@ -597,7 +594,7 @@ static int validate_ownership_config( bool use_env) { validate_ownership_data ownership_data = { - path, GIT_STR_INIT, is_safe + GIT_STR_INIT, is_safe }; git_config *config; int error; @@ -605,6 +602,13 @@ static int validate_ownership_config( if (load_global_config(&config, use_env) != 0) return 0; + git_str_sets(&ownership_data.repo_path, path); + if (git_str_oom(&ownership_data.repo_path)) + return -1; + if (git_str_len(&ownership_data.repo_path) > 1 && + ownership_data.repo_path.ptr[git_str_len(&ownership_data.repo_path) - 1] == '/') + git_str_shorten(&ownership_data.repo_path, 1); + error = git_config_get_multivar_foreach(config, "safe.directory", NULL, validate_ownership_cb, @@ -614,7 +618,7 @@ static int validate_ownership_config( error = 0; git_config_free(config); - git_str_dispose(&ownership_data.tmp); + git_str_dispose(&ownership_data.repo_path); return error; } diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index 3d1a0620b12..547e300a170 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -555,6 +555,25 @@ void test_repo_open__can_allowlist_dirs_with_problematic_ownership(void) git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); + // Test with incorrect exception (slash at the end) + git_str_printf(&config_data, + "[foo]\n" \ + "\tbar = Foobar\n" \ + "\tbaz = Baz!\n" \ + "[safe]\n" \ + "\tdirectory = /non/existent/path\n" \ + "\tdirectory = /\n" \ + "\tdirectory = c:\\\\temp\n" \ + "\tdirectory = %s/%s/\n" \ + "\tdirectory = /tmp\n" \ + "[bar]\n" \ + "\tfoo = barfoo\n", + clar_sandbox_path(), "empty_standard_repo"); + cl_git_rewritefile(config_filename.ptr, config_data.ptr); + cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); + + // Test with correct exception + git_str_clear(&config_data); git_str_printf(&config_data, "[foo]\n" \ "\tbar = Foobar\n" \ From 73f034c7b99d3682d34408de567c9aeead185c34 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sun, 10 Dec 2023 10:25:24 +0100 Subject: [PATCH 311/816] Improve error message Signed-off-by: Sven Strickroth --- src/libgit2/repository.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 26741bbbc67..f9d639b6144 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -685,9 +685,26 @@ static int validate_ownership(git_repository *repo) goto done; if (!is_safe) { - git_error_set(GIT_ERROR_CONFIG, - "repository path '%s' is not owned by current user", - path); + git_str nice_path = GIT_STR_INIT; +#ifdef GIT_WIN32 + /* see comment above in validate_ownership_cb */ + if (!strncasecmp(path, "//", strlen("//"))) + git_str_puts(&nice_path, "%(prefix)/"); +#endif + git_str_puts(&nice_path, path); + if (!git_str_oom(&nice_path)) { + if (git_str_len(&nice_path) > 1 && nice_path.ptr[git_str_len(&nice_path) - 1] == '/') + git_str_shorten(&nice_path, 1); + git_error_set( + GIT_ERROR_CONFIG, + "repository path '%s' is not owned by current user.\n\nTo add an exception use the path '%s'.", + path, nice_path.ptr); + } else + git_error_set( + GIT_ERROR_CONFIG, + "repository path '%s' is not owned by current user.", + path); + git_str_dispose(&nice_path); error = GIT_EOWNER; } From 731af14be3a16839ead66751ea0d6c97226799d8 Mon Sep 17 00:00:00 2001 From: Kevin Saul Date: Thu, 14 Dec 2023 15:36:05 +1300 Subject: [PATCH 312/816] repo: add oid type support to git_repository_new --- include/git2/sys/repository.h | 5 ++++ src/libgit2/repository.c | 15 +++++++++++- src/libgit2/repository.h | 3 +++ tests/libgit2/network/remote/local.c | 4 +++ tests/libgit2/odb/backend/nobackend.c | 4 +++ tests/libgit2/repo/new.c | 35 +++++++++++++++++++++++++++ 6 files changed, 65 insertions(+), 1 deletion(-) diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h index 892be669266..080a404c413 100644 --- a/include/git2/sys/repository.h +++ b/include/git2/sys/repository.h @@ -9,6 +9,7 @@ #include "git2/common.h" #include "git2/types.h" +#include "git2/oid.h" /** * @file git2/sys/repository.h @@ -32,7 +33,11 @@ GIT_BEGIN_DECL * @param out The blank repository * @return 0 on success, or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_repository_new(git_repository **out, git_oid_t oid_type); +#else GIT_EXTERN(int) git_repository_new(git_repository **out); +#endif /** * Reset all the internal state in a repository. diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 05ece6efc41..c73ef1303da 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -328,7 +328,7 @@ static git_repository *repository_alloc(void) return NULL; } -int git_repository_new(git_repository **out) +int git_repository__new(git_repository **out, git_oid_t oid_type) { git_repository *repo; @@ -337,10 +337,23 @@ int git_repository_new(git_repository **out) repo->is_bare = 1; repo->is_worktree = 0; + repo->oid_type = oid_type; return 0; } +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_repository_new(git_repository **out, git_oid_t oid_type) +{ + return git_repository__new(out, oid_type); +} +#else +int git_repository_new(git_repository** out) +{ + return git_repository__new(out, GIT_OID_SHA1); +} +#endif + static int load_config_data(git_repository *repo, const git_config *config) { int is_bare; diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index 6d2b64c0368..be4bc8860d6 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -280,4 +280,7 @@ int git_repository__set_objectformat( git_repository *repo, git_oid_t oid_type); +/* SHA256-aware internal functions */ +int git_repository__new(git_repository **out, git_oid_t oid_type); + #endif diff --git a/tests/libgit2/network/remote/local.c b/tests/libgit2/network/remote/local.c index 2007f3776a1..d70d0ebf7a6 100644 --- a/tests/libgit2/network/remote/local.c +++ b/tests/libgit2/network/remote/local.c @@ -473,7 +473,11 @@ void test_network_remote_local__anonymous_remote_inmemory_repo(void) git_str_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git"))); +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_repository_new(&inmemory, GIT_OID_SHA1)); +#else cl_git_pass(git_repository_new(&inmemory)); +#endif cl_git_pass(git_remote_create_anonymous(&remote, inmemory, git_str_cstr(&file_path_buf))); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); cl_assert(git_remote_connected(remote)); diff --git a/tests/libgit2/odb/backend/nobackend.c b/tests/libgit2/odb/backend/nobackend.c index 7d9394c6f33..a81e5857715 100644 --- a/tests/libgit2/odb/backend/nobackend.c +++ b/tests/libgit2/odb/backend/nobackend.c @@ -11,7 +11,11 @@ void test_odb_backend_nobackend__initialize(void) git_odb *odb; git_refdb *refdb; +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_repository_new(&_repo, GIT_OID_SHA1)); +#else cl_git_pass(git_repository_new(&_repo)); +#endif cl_git_pass(git_config_new(&config)); cl_git_pass(git_odb__new(&odb, NULL)); cl_git_pass(git_refdb_new(&refdb, _repo)); diff --git a/tests/libgit2/repo/new.c b/tests/libgit2/repo/new.c index d77e903f670..aaa917a4aba 100644 --- a/tests/libgit2/repo/new.c +++ b/tests/libgit2/repo/new.c @@ -5,7 +5,11 @@ void test_repo_new__has_nothing(void) { git_repository *repo; +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_repository_new(&repo, GIT_OID_SHA1)); +#else cl_git_pass(git_repository_new(&repo)); +#endif cl_assert_equal_b(true, git_repository_is_bare(repo)); cl_assert_equal_p(NULL, git_repository_path(repo)); cl_assert_equal_p(NULL, git_repository_workdir(repo)); @@ -16,7 +20,11 @@ void test_repo_new__is_bare_until_workdir_set(void) { git_repository *repo; +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_repository_new(&repo, GIT_OID_SHA1)); +#else cl_git_pass(git_repository_new(&repo)); +#endif cl_assert_equal_b(true, git_repository_is_bare(repo)); cl_git_pass(git_repository_set_workdir(repo, clar_sandbox_path(), 0)); @@ -25,3 +33,30 @@ void test_repo_new__is_bare_until_workdir_set(void) git_repository_free(repo); } +void test_repo_new__sha1(void) +{ + git_repository *repo; + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_repository_new(&repo, GIT_OID_SHA1)); +#else + cl_git_pass(git_repository_new(&repo)); +#endif + cl_assert_equal_i(GIT_OID_SHA1, git_repository_oid_type(repo)); + + git_repository_free(repo); +} + +void test_repo_new__sha256(void) +{ +#ifndef GIT_EXPERIMENTAL_SHA256 + cl_skip(); +#else + git_repository *repo; + + cl_git_pass(git_repository_new(&repo, GIT_OID_SHA256)); + cl_assert_equal_i(GIT_OID_SHA256, git_repository_oid_type(repo)); + + git_repository_free(repo); +#endif +} From f247a3f59fc1d50a1bfd8f94051cfee1571103fb Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Thu, 14 Dec 2023 09:38:18 +0100 Subject: [PATCH 313/816] git2: Fix crash when called w/o parameters Signed-off-by: Sven Strickroth --- src/cli/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cli/main.c b/src/cli/main.c index 6854b82289a..190b6756d95 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -100,6 +100,11 @@ int main(int argc, char **argv) goto done; } + if (!command) { + ret = cmd_help(argc, argv); + goto done; + } + if ((cmd = cli_cmd_spec_byname(command)) == NULL) { ret = cli_error("'%s' is not a %s command. See '%s help'.", command, PROGRAM_NAME, PROGRAM_NAME); From 8b7495fc8250e187a091bd5f00c8d5323799edb4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 10:51:34 +0000 Subject: [PATCH 314/816] push: set generic error in push_negotiation cb When a user returns `-1` in a `push_negotiation` callback, we set the error to whatever's hanging out in the buffer, probably something about a missing configuration entry. Clear the error buffer before invoking the callback, so that if a user does not set an error message in their callback that we can detect. If there is no error but `-1` is returned, set a generic error message. --- src/libgit2/push.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/libgit2/push.c b/src/libgit2/push.c index 8b47abc2463..d3ec4a1d818 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -444,10 +444,21 @@ static int do_push(git_push *push) if ((error = calculate_work(push)) < 0) goto on_error; - if (callbacks && callbacks->push_negotiation && - (error = callbacks->push_negotiation((const git_push_update **) push->updates.contents, - push->updates.length, callbacks->payload)) < 0) - goto on_error; + if (callbacks && callbacks->push_negotiation) { + git_error_clear(); + + error = callbacks->push_negotiation( + (const git_push_update **) push->updates.contents, + push->updates.length, callbacks->payload); + + if (error < 0) { + git_error_set_after_callback_function(error, + "push_negotiation"); + goto on_error; + } + + error = 0; + } if ((error = queue_objects(push)) < 0 || (error = transport->push(transport, push)) < 0) From 31fd5e36570bd338cea229952f043943c6b5ba72 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 12:16:12 +0000 Subject: [PATCH 315/816] release: add a compatibility label Add a compatibility label to the release.yml to describe things that are for improved cross-platform compatibility. --- .github/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/release.yml b/.github/release.yml index 7a0032113db..099e3803fa6 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -21,6 +21,9 @@ changelog: - title: Documentation improvements labels: - documentation + - title: Platform compatibility fixes + labels: + - compatibility - title: Git compatibility fixes labels: - git compatibility From 4681b3aee447ba85c63043355699042253599d88 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 13:40:20 +0000 Subject: [PATCH 316/816] ntlmclient: update to latest version Ensure that we declare variables at the top of the block for broad compatibility with old compilers. --- deps/ntlmclient/crypt_commoncrypto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deps/ntlmclient/crypt_commoncrypto.c b/deps/ntlmclient/crypt_commoncrypto.c index 4ff57edd29a..3c20469f58d 100644 --- a/deps/ntlmclient/crypt_commoncrypto.c +++ b/deps/ntlmclient/crypt_commoncrypto.c @@ -59,11 +59,12 @@ bool ntlm_des_encrypt( ntlm_des_block *plaintext, ntlm_des_block *key) { + CCCryptorStatus result; size_t written; NTLM_UNUSED(ntlm); - CCCryptorStatus result = CCCrypt(kCCEncrypt, + result = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, sizeof(ntlm_des_block), NULL, plaintext, sizeof(ntlm_des_block), From b882e9e7a6e142ce4cf26ea15905f0ff06c11eb8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 13:40:57 +0000 Subject: [PATCH 317/816] stream: use an unsigned int for a bitmask --- include/git2/sys/stream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/sys/stream.h b/include/git2/sys/stream.h index 3d28d09b321..3277088c99c 100644 --- a/include/git2/sys/stream.h +++ b/include/git2/sys/stream.h @@ -29,8 +29,8 @@ GIT_BEGIN_DECL typedef struct git_stream { int version; - int encrypted : 1, - proxy_support : 1; + unsigned int encrypted : 1, + proxy_support : 1; /** * Timeout for read and write operations; can be set to `0` to From de9a76b92c5805033ce3b477a8a65957465c8625 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 13:41:17 +0000 Subject: [PATCH 318/816] config: properly handle multiline quotes Pass a pointer to the quote counts so that we can increment it. --- src/libgit2/config_parse.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libgit2/config_parse.c b/src/libgit2/config_parse.c index 06931368e7b..1431bed36db 100644 --- a/src/libgit2/config_parse.c +++ b/src/libgit2/config_parse.c @@ -279,8 +279,7 @@ static int skip_bom(git_parse_ctx *parser) */ /* '\"' -> '"' etc */ -static int unescape_line( - char **out, bool *is_multi, const char *ptr, int quote_count) +static int unescape_line(char **out, bool *is_multi, const char *ptr, int *quote_count) { char *str, *fixed, *esc; size_t ptr_len = strlen(ptr), alloc_len; @@ -296,7 +295,8 @@ static int unescape_line( while (*ptr != '\0') { if (*ptr == '"') { - quote_count++; + if (quote_count) + (*quote_count)++; } else if (*ptr != '\\') { *fixed++ = *ptr; } else { @@ -358,7 +358,7 @@ static int parse_multiline_variable(git_config_parser *reader, git_str *value, i goto next; if ((error = unescape_line(&proc_line, &multiline, - line, in_quotes)) < 0) + line, &in_quotes)) < 0) goto out; /* Add this line to the multiline var */ @@ -445,7 +445,7 @@ static int parse_variable(git_config_parser *reader, char **var_name, char **var while (git__isspace(value_start[0])) value_start++; - if ((error = unescape_line(&value, &multiline, value_start, 0)) < 0) + if ((error = unescape_line(&value, &multiline, value_start, NULL)) < 0) goto out; if (multiline) { From 9ed52434b718d3f06637e1b953dda98d93711c34 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 13:41:49 +0000 Subject: [PATCH 319/816] refdb: use an unsigned int for a bitfield --- src/libgit2/refdb_fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index e34a71455cb..6952548046c 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -62,8 +62,8 @@ typedef struct refdb_fs_backend { git_oid_t oid_type; - int fsync : 1, - sorted : 1; + unsigned int fsync : 1, + sorted : 1; int peeling_mode; git_iterator_flag_t iterator_flags; uint32_t direach_flags; From 18aa18bee17fcc45f87b556b5bde2aebb3a3a40a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 13:42:01 +0000 Subject: [PATCH 320/816] smart: use an unsigned int for a bitfield --- src/libgit2/transports/smart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 52c7553a1d7..f49827eb698 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -203,7 +203,7 @@ int git_smart__update_heads(transport_smart *t, git_vector *symrefs); /* smart_pkt.c */ typedef struct { git_oid_t oid_type; - int seen_capabilities: 1; + unsigned int seen_capabilities: 1; } git_pkt_parse_data; int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen, git_pkt_parse_data *data); From 60c68e7e03aa7c5b827ceb8cd9e0d506a87e743f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 14:06:51 +0000 Subject: [PATCH 321/816] cli: use the latest version of adopt --- src/cli/opt.c | 2 +- src/cli/opt.h | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cli/opt.c b/src/cli/opt.c index 25c97746f1d..2b08dc219a3 100644 --- a/src/cli/opt.c +++ b/src/cli/opt.c @@ -10,7 +10,7 @@ * This file was produced by using the `rename.pl` script included with * adopt. The command-line specified was: * - * ./rename.pl cli_opt --filename=opt --include=cli.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage + * ./rename.pl cli_opt --filename=opt --include=common.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage */ #include diff --git a/src/cli/opt.h b/src/cli/opt.h index 7133307b4f7..226f74db8bc 100644 --- a/src/cli/opt.h +++ b/src/cli/opt.h @@ -10,7 +10,7 @@ * This file was produced by using the `rename.pl` script included with * adopt. The command-line specified was: * - * ./rename.pl cli_opt --filename=opt --include=cli.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage + * ./rename.pl cli_opt --filename=opt --include=common.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage */ #ifndef CLI_opt_h__ @@ -275,8 +275,8 @@ typedef struct cli_opt_parser { size_t arg_idx; size_t in_args; size_t in_short; - int needs_sort : 1, - in_literal : 1; + unsigned int needs_sort : 1, + in_literal : 1; } cli_opt_parser; /** @@ -300,6 +300,16 @@ cli_opt_status_t cli_opt_parse( size_t args_len, unsigned int flags); +/** + * Quickly executes the given callback for each argument. + * + * @param specs A NULL-terminated array of `cli_opt_spec`s that can be parsed + * @param args The arguments that will be parsed + * @param args_len The length of arguments to be parsed + * @param flags The `cli_opt_flag_t flags for parsing + * @param callback The callback to invoke for each specified option + * @param callback_data Data to be provided to the callback + */ int cli_opt_foreach( const cli_opt_spec specs[], char **args, From 2098c490c8b8bfb88adab30575ff82fa157e52a3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 14:07:03 +0000 Subject: [PATCH 322/816] net: use an unsigned int for a bitfield --- src/util/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/net.c b/src/util/net.c index 24782d2af09..4474564511b 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -22,7 +22,7 @@ #define GIT_NET_URL_PARSER_INIT { 0 } typedef struct { - int hierarchical : 1; + unsigned int hierarchical : 1; const char *scheme; const char *user; From 6fb234b5fbd1e999685bf545013d64c42550d110 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 14:17:24 +0000 Subject: [PATCH 323/816] process: use unsigned int for bitfields --- src/util/process.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/process.h b/src/util/process.h index 9310652c325..3ada6696d22 100644 --- a/src/util/process.h +++ b/src/util/process.h @@ -11,10 +11,10 @@ typedef struct git_process git_process; typedef struct { - int capture_in : 1, - capture_out : 1, - capture_err : 1, - exclude_env : 1; + unsigned int capture_in : 1, + capture_out : 1, + capture_err : 1, + exclude_env : 1; char *cwd; } git_process_options; From 839b249525b46f2894b8cd574d02b06ef9933f8e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 14:26:09 +0000 Subject: [PATCH 324/816] tests: update to latest clar --- tests/clar/clar.c | 2 ++ tests/clar/clar/fixtures.h | 2 +- tests/clar/clar/fs.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/clar/clar.c b/tests/clar/clar.c index c9c3fde3827..3fc2c768158 100644 --- a/tests/clar/clar.c +++ b/tests/clar/clar.c @@ -94,8 +94,10 @@ static void fs_rm(const char *_source); static void fs_copy(const char *_source, const char *dest); +#ifdef CLAR_FIXTURE_PATH static const char * fixture_path(const char *base, const char *fixture_name); +#endif struct clar_error { const char *file; diff --git a/tests/clar/clar/fixtures.h b/tests/clar/clar/fixtures.h index 77033d36507..6ec6423484d 100644 --- a/tests/clar/clar/fixtures.h +++ b/tests/clar/clar/fixtures.h @@ -1,3 +1,4 @@ +#ifdef CLAR_FIXTURE_PATH static const char * fixture_path(const char *base, const char *fixture_name) { @@ -20,7 +21,6 @@ fixture_path(const char *base, const char *fixture_name) return _path; } -#ifdef CLAR_FIXTURE_PATH const char *cl_fixture(const char *fixture_name) { return fixture_path(CLAR_FIXTURE_PATH, fixture_name); diff --git a/tests/clar/clar/fs.h b/tests/clar/clar/fs.h index 44ede457258..a6eda5e5dc2 100644 --- a/tests/clar/clar/fs.h +++ b/tests/clar/clar/fs.h @@ -295,7 +295,9 @@ fs_copy(const char *_source, const char *_dest) void cl_fs_cleanup(void) { +#ifdef CLAR_FIXTURE_PATH fs_rm(fixture_path(_clar_path, "*")); +#endif } #else From d728cb610bfa36c81a38a50fd32ae66d29b6c271 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Sat, 1 Jan 2022 14:50:15 +0100 Subject: [PATCH 325/816] ci: add url-like path to online clone tests --- tests/libgit2/online/clone.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 7a8f5ead780..207dd839172 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -7,6 +7,7 @@ #include "refs.h" #define LIVE_REPO_URL "http://github.com/libgit2/TestGitRepository" +#define LIVE_REPO_AS_DIR "http:/github.com/libgit2/TestGitRepository" #define LIVE_EMPTYREPO_URL "http://github.com/libgit2/TestEmptyRepository" #define BB_REPO_URL "https://libgit2-test@bitbucket.org/libgit2-test/testgitrepository.git" #define BB_REPO_URL_WITH_PASS "https://libgit2-test:YT77Ppm2nq8w4TYjGS8U@bitbucket.org/libgit2-test/testgitrepository.git" @@ -115,6 +116,16 @@ void test_online_clone__initialize(void) if (_remote_expectcontinue) git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1); + +#if !defined(GIT_WIN32) + /* + * On system that allows ':' in filenames "http://path" can be misinterpreted + * as the local path "http:/path". + * Create a local non-repository path that looks like LIVE_REPO_URL to make + * sure we can handle cloning despite this directory being around. + */ + git_futils_mkdir_r(LIVE_REPO_AS_DIR, 0777); +#endif } void test_online_clone__cleanup(void) @@ -127,6 +138,10 @@ void test_online_clone__cleanup(void) cl_fixture_cleanup("./initial"); cl_fixture_cleanup("./subsequent"); +#if !defined(GIT_WIN32) + cl_fixture_cleanup("http:"); +#endif + git__free(_remote_url); git__free(_remote_user); git__free(_remote_pass); From 26b08d4c6d524d21ba95b0d08650c7b4c2aeb576 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Thu, 12 Aug 2021 13:46:03 +0200 Subject: [PATCH 326/816] clone: don't test remote url against filesystem --- src/libgit2/clone.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index 27bae1ac499..3df28f80aed 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -22,6 +22,7 @@ #include "fs_path.h" #include "repository.h" #include "odb.h" +#include "net.h" static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link); @@ -336,8 +337,9 @@ static int create_and_configure_origin( git_remote_create_cb remote_create = options->remote_cb; void *payload = options->remote_cb_payload; - /* If the path exists and is a dir, the url should be the absolute path */ - if (git_fs_path_root(url) < 0 && git_fs_path_exists(url) && git_fs_path_isdir(url)) { + /* If the path is local and exists it should be the absolute path. */ + if (!git_net_str_is_url(url) && git_fs_path_root(url) < 0 && + git_fs_path_exists(url)) { if (p_realpath(url, buf) == NULL) return -1; @@ -458,26 +460,25 @@ static int clone_into( int git_clone__should_clone_local(const char *url_or_path, git_clone_local_t local) { git_str fromurl = GIT_STR_INIT; - const char *path = url_or_path; - bool is_url, is_local; + bool is_local; if (local == GIT_CLONE_NO_LOCAL) return 0; - if ((is_url = git_fs_path_is_local_file_url(url_or_path)) != 0) { - if (git_fs_path_fromurl(&fromurl, url_or_path) < 0) { - is_local = -1; - goto done; - } + if (git_net_str_is_url(url_or_path)) { + /* If GIT_CLONE_LOCAL_AUTO is specified, any url should be treated as remote */ + if (local == GIT_CLONE_LOCAL_AUTO || + !git_fs_path_is_local_file_url(url_or_path)) + return 0; - path = fromurl.ptr; + if (git_fs_path_fromurl(&fromurl, url_or_path) == 0) + is_local = git_fs_path_isdir(git_str_cstr(&fromurl)); + else + is_local = -1; + git_str_dispose(&fromurl); + } else { + is_local = git_fs_path_isdir(url_or_path); } - - is_local = (!is_url || local != GIT_CLONE_LOCAL_AUTO) && - git_fs_path_isdir(path); - -done: - git_str_dispose(&fromurl); return is_local; } From 85c4edfae35f52e116c19d54a69c5bf683ae3e14 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 20:50:51 +0000 Subject: [PATCH 327/816] signature: test new leading/trailing dot parsing We now allow leading and trailing dots in username and email addresses. Test that we do so. --- tests/libgit2/commit/signature.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/libgit2/commit/signature.c b/tests/libgit2/commit/signature.c index 32058f6c344..fddd5076eb7 100644 --- a/tests/libgit2/commit/signature.c +++ b/tests/libgit2/commit/signature.c @@ -36,6 +36,13 @@ void test_commit_signature__leading_and_trailing_spaces_are_trimmed(void) assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", " \t nulltoken \n", " \n emeric.fermas@gmail.com \n"); } +void test_commit_signature__leading_and_trailing_dots_are_supported(void) +{ + assert_name_and_email(".nulltoken", ".emeric.fermas@gmail.com", ".nulltoken", ".emeric.fermas@gmail.com"); + assert_name_and_email("nulltoken.", "emeric.fermas@gmail.com.", "nulltoken.", "emeric.fermas@gmail.com."); + assert_name_and_email(".nulltoken.", ".emeric.fermas@gmail.com.", ".nulltoken.", ".emeric.fermas@gmail.com."); +} + void test_commit_signature__leading_and_trailing_crud_is_trimmed(void) { assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", "\"nulltoken\"", "\"emeric.fermas@gmail.com\""); From cba3469cdba08cef67d71ab53a8cc2abb3132598 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 24 Jun 2023 20:47:09 +0100 Subject: [PATCH 328/816] cli: add `index-pack` command --- src/cli/cmd.h | 1 + src/cli/cmd_index_pack.c | 114 +++++++++++++++++++++++++++++++++++++++ src/cli/main.c | 1 + src/cli/progress.c | 53 +++++++++++++++++- src/cli/progress.h | 12 +++++ 5 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 src/cli/cmd_index_pack.c diff --git a/src/cli/cmd.h b/src/cli/cmd.h index 12977cbc7bb..bd881223db9 100644 --- a/src/cli/cmd.h +++ b/src/cli/cmd.h @@ -30,5 +30,6 @@ extern int cmd_clone(int argc, char **argv); extern int cmd_config(int argc, char **argv); extern int cmd_hash_object(int argc, char **argv); extern int cmd_help(int argc, char **argv); +extern int cmd_index_pack(int argc, char **argv); #endif /* CLI_cmd_h__ */ diff --git a/src/cli/cmd_index_pack.c b/src/cli/cmd_index_pack.c new file mode 100644 index 00000000000..17698033ae7 --- /dev/null +++ b/src/cli/cmd_index_pack.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include "common.h" +#include "cmd.h" +#include "progress.h" + +#define COMMAND_NAME "index-pack" + +#define BUFFER_SIZE (1024 * 1024) + +static int show_help, verbose, read_stdin; +static char *filename; +static cli_progress progress = CLI_PROGRESS_INIT; + +static const cli_opt_spec opts[] = { + { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, + "display help about the " COMMAND_NAME " command" }, + + { CLI_OPT_TYPE_SWITCH, "verbose", 'v', &verbose, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "display progress output" }, + + { CLI_OPT_TYPE_LITERAL }, + + { CLI_OPT_TYPE_SWITCH, "stdin", 0, &read_stdin, 1, + CLI_OPT_USAGE_REQUIRED, NULL, "read from stdin" }, + { CLI_OPT_TYPE_ARG, "pack-file", 0, &filename, 0, + CLI_OPT_USAGE_CHOICE, "pack-file", "packfile path" }, + + { 0 }, +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Indexes a packfile and writes the index to disk.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +int cmd_index_pack(int argc, char **argv) +{ + cli_opt invalid_opt; + git_indexer *idx = NULL; + git_indexer_options idx_opts = GIT_INDEXER_OPTIONS_INIT; + git_indexer_progress stats = {0}; + char buf[BUFFER_SIZE]; + ssize_t read_len; + int fd, ret; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (verbose) { + idx_opts.progress_cb = cli_progress_indexer; + idx_opts.progress_cb_payload = &progress; + } + + if (read_stdin) { + fd = fileno(stdin); + } else if ((fd = p_open(filename, O_RDONLY)) < 0) { + ret = cli_error_git(); + goto done; + } + +#ifdef GIT_EXPERIMENTAL_SHA256 + ret = git_indexer_new(&idx, ".", GIT_OID_SHA1, &idx_opts); +#else + ret = git_indexer_new(&idx, ".", 0, NULL, &idx_opts); +#endif + + if (ret < 0) { + ret = cli_error_git(); + goto done; + } + + while ((read_len = p_read(fd, buf, sizeof(buf))) > 0) { + if (git_indexer_append(idx, buf, (size_t)read_len, &stats) < 0) { + ret = cli_error_git(); + goto done; + } + } + + if (!read_stdin) + p_close(fd); + + if (git_indexer_commit(idx, &stats) < 0) { + ret = cli_error_git(); + goto done; + } + + cli_progress_finish(&progress); + +done: + cli_progress_dispose(&progress); + git_indexer_free(idx); + return ret; +} diff --git a/src/cli/main.c b/src/cli/main.c index 190b6756d95..c7a6fcfce26 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -37,6 +37,7 @@ const cli_cmd_spec cli_cmds[] = { { "config", cmd_config, "View or set configuration values " }, { "hash-object", cmd_hash_object, "Hash a raw object and product its object ID" }, { "help", cmd_help, "Display help information" }, + { "index-pack", cmd_index_pack, "Create an index for a packfile" }, { NULL } }; diff --git a/src/cli/progress.c b/src/cli/progress.c index ddfbafb73a4..d975b0954ac 100644 --- a/src/cli/progress.c +++ b/src/cli/progress.c @@ -242,7 +242,21 @@ static int fetch_receiving( done ? ", done." : ""); } -static int fetch_resolving( +static int indexer_indexing( + cli_progress *progress, + const git_indexer_progress *stats) +{ + bool done = (stats->received_objects == stats->total_objects); + + return progress_printf(progress, false, + "Indexing objects: %3d%% (%d/%d)%s\r", + percent(stats->received_objects, stats->total_objects), + stats->received_objects, + stats->total_objects, + done ? ", done." : ""); +} + +static int indexer_resolving( cli_progress *progress, const git_indexer_progress *stats) { @@ -283,7 +297,42 @@ int cli_progress_fetch_transfer(const git_indexer_progress *stats, void *payload /* fall through */ case CLI_PROGRESS_RESOLVING: - error = fetch_resolving(progress, stats); + error = indexer_resolving(progress, stats); + break; + + default: + /* should not be reached */ + GIT_ASSERT(!"unexpected progress state"); + } + + return error; +} + +int cli_progress_indexer( + const git_indexer_progress *stats, + void *payload) +{ + cli_progress *progress = (cli_progress *)payload; + int error = 0; + + switch (progress->action) { + case CLI_PROGRESS_NONE: + progress->action = CLI_PROGRESS_INDEXING; + /* fall through */ + + case CLI_PROGRESS_INDEXING: + if ((error = indexer_indexing(progress, stats)) < 0) + break; + + if (stats->indexed_deltas == stats->total_deltas) + break; + + progress_complete(progress); + progress->action = CLI_PROGRESS_RESOLVING; + /* fall through */ + + case CLI_PROGRESS_RESOLVING: + error = indexer_resolving(progress, stats); break; default: diff --git a/src/cli/progress.h b/src/cli/progress.h index 886fef89d03..f08d68f19e4 100644 --- a/src/cli/progress.h +++ b/src/cli/progress.h @@ -22,6 +22,7 @@ typedef enum { CLI_PROGRESS_NONE, CLI_PROGRESS_RECEIVING, + CLI_PROGRESS_INDEXING, CLI_PROGRESS_RESOLVING, CLI_PROGRESS_CHECKING_OUT } cli_progress_t; @@ -74,6 +75,17 @@ extern int cli_progress_fetch_transfer( const git_indexer_progress *stats, void *payload); +/** + * Prints indexer progress to the console. Suitable for a + * `progress_cb` callback for `git_indexer_options`. + * + * @param stats The indexer stats + * @param payload A pointer to the cli_progress + */ +extern int cli_progress_indexer( + const git_indexer_progress *stats, + void *payload); + /** * Prints checkout progress to the console. Suitable for a * `progress_cb` callback for `git_checkout_options`. From 9d767b9d5ea05821c0213ec49a593f31241f5ef3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Dec 2023 22:26:05 +0000 Subject: [PATCH 329/816] cmake: rename FindIconv to avoid collision with cmake cmake now includes `FindIconv`. Rename ours to avoid any confusion. --- cmake/{FindIconv.cmake => FindIntlIconv.cmake} | 0 src/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename cmake/{FindIconv.cmake => FindIntlIconv.cmake} (100%) diff --git a/cmake/FindIconv.cmake b/cmake/FindIntlIconv.cmake similarity index 100% rename from cmake/FindIconv.cmake rename to cmake/FindIntlIconv.cmake diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b412452c916..ed3f4a51427 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -184,7 +184,7 @@ add_feature_info(ntlmclient GIT_NTLM "NTLM authentication support for Unix") # iconv if(USE_ICONV) - find_package(Iconv) + find_package(IntlIconv) endif() if(ICONV_FOUND) set(GIT_USE_ICONV 1) From f5793057fa759b513f2cd48784be67511dfe7178 Mon Sep 17 00:00:00 2001 From: Kevin Saul Date: Fri, 15 Dec 2023 11:41:46 +1300 Subject: [PATCH 330/816] attr: ignore missing index --- src/libgit2/attr.c | 6 +++++- tests/libgit2/attr/repo.c | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libgit2/attr.c b/src/libgit2/attr.c index 1623b1d4570..1db90b59c7e 100644 --- a/src/libgit2/attr.c +++ b/src/libgit2/attr.c @@ -424,9 +424,13 @@ static int attr_setup( goto out; if ((error = git_repository_index__weakptr(&idx, repo)) < 0 || - (error = preload_attr_source(repo, attr_session, &index_source)) < 0) + (error = preload_attr_source(repo, attr_session, &index_source)) < 0) { + if (error != GIT_ENOTFOUND) goto out; + error = 0; + } + if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) && (error = preload_attr_source(repo, attr_session, &head_source)) < 0) goto out; diff --git a/tests/libgit2/attr/repo.c b/tests/libgit2/attr/repo.c index abd2381541d..747715b51fa 100644 --- a/tests/libgit2/attr/repo.c +++ b/tests/libgit2/attr/repo.c @@ -309,6 +309,31 @@ void test_attr_repo__bare_repo_with_index(void) cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3])); } +void test_attr_repo__inmemory_repo_without_index(void) +{ + const char *names[1] = { "fake" }; + const char *values[1]; + git_repository *inmemory; + git_index *index = NULL; + + /* setup bare in-memory repo without index */ +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_repository_new(&inmemory, GIT_OID_SHA1)); +#else + cl_git_pass(git_repository_new(&inmemory)); +#endif + cl_assert(git_repository_is_bare(inmemory)); + + /* verify repo isn't given an index upfront in future */ + git_repository_index(&index, inmemory); + cl_assert(!index); + + /* check attributes can be queried without error due to missing index */ + cl_git_pass(git_attr_get_many(values, inmemory, 0, "fake.txt", 1, names)); + + git_repository_free(inmemory); +} + void test_attr_repo__sysdir(void) { git_str sysdir = GIT_STR_INIT; From 6855502c94c567dbac1f6b952c555625acdb73ec Mon Sep 17 00:00:00 2001 From: Kevin Saul Date: Fri, 15 Dec 2023 17:46:13 +1300 Subject: [PATCH 331/816] repo: use empty grafts when directory not found for in-memory repo --- src/libgit2/repository.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index c73ef1303da..0b76e0464a6 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -865,8 +865,30 @@ static int load_grafts(git_repository *repo) git_str path = GIT_STR_INIT; int error; - if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || - (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || + /* refresh if they've both been opened previously */ + if (repo->grafts && repo->shallow_grafts) { + if ((error = git_grafts_refresh(repo->grafts)) < 0 || + (error = git_grafts_refresh(repo->shallow_grafts)) < 0) + return error; + } + + /* resolve info path, which may not be found for inmemory repository */ + if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0) { + if (error != GIT_ENOTFOUND) + return error; + + /* create empty/inmemory grafts for inmemory repository */ + if (!repo->grafts && (error = git_grafts_new(&repo->grafts, repo->oid_type)) < 0) + return error; + + if (!repo->shallow_grafts && (error = git_grafts_new(&repo->shallow_grafts, repo->oid_type)) < 0) + return error; + + return 0; + } + + /* load grafts from disk */ + if ((error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || (error = git_grafts_open_or_refresh(&repo->grafts, path.ptr, repo->oid_type)) < 0) goto error; From 8f3e2d26d3754921460ce583b6becb4dd1f3d92a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Dec 2023 13:57:43 +0000 Subject: [PATCH 332/816] ci: allow workflows to read and write packages Our CI workflows consume and will automatically generate their build containers. Ensure that they can do so. --- .github/workflows/benchmark.yml | 7 ++++--- .github/workflows/main.yml | 1 + .github/workflows/nightly.yml | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index cc231b462ec..7705d89e97a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -10,9 +10,10 @@ permissions: contents: read jobs: - # Run our nightly builds. We build a matrix with the various build - # targets and their details. Then we build either in a docker container - # (Linux) or on the actual hosts (macOS, Windows). + # Run our benchmarks. We build a matrix with the various build + # targets and their details. Unlike our CI builds, we run these + # directly on the VM instead of in containers since we do not + # need the breadth of platform diversity. build: # Only run scheduled workflows on the main repository; prevents people # from using build minutes on their forks. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3de084b8d41..f341a9cd274 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,6 +15,7 @@ env: permissions: contents: read + packages: write jobs: containers: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index ae55b36c071..b48cbf51260 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -12,6 +12,7 @@ env: permissions: contents: read + packages: write jobs: # Run our nightly builds. We build a matrix with the various build From 0b10c3fb433c3ade7bfd3c89b17f1cf959a16c0b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Dec 2023 14:39:29 +0000 Subject: [PATCH 333/816] ci: allow workflows to push changes Our workflows push documentation changes; ensure that they are allowed to do so. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f341a9cd274..bafffdc1fc8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ env: docker-config-path: source/ci/docker permissions: - contents: read + contents: write packages: write jobs: From e619b884d5f121d7e584f77e2187b720d4d23f01 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Thu, 14 Dec 2023 19:22:05 +0100 Subject: [PATCH 334/816] ctype: cast characters to unsigned when classifying characters ctype classification takes an integer in as returned from getc() if we just sign extend characters to integers 128-255 will be misclassified. (255 will become EOF) Newlib in particular doesn't like this since they uses the value as an index in a lookup table. --- src/libgit2/config.c | 2 +- src/libgit2/config_parse.c | 9 +++++---- src/libgit2/path.c | 2 +- src/libgit2/trailer.c | 10 +++++----- src/libgit2/transports/smart_pkt.c | 4 ++-- src/util/date.c | 18 +++++++++--------- src/util/str.c | 4 ++-- src/util/util.h | 2 +- tests/libgit2/repo/open.c | 2 +- 9 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 23a8f9ffad1..5c1c00f6cb7 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -1447,7 +1447,7 @@ static int normalize_section(char *start, char *end) for (scan = start; *scan; ++scan) { if (end && scan >= end) break; - if (isalnum(*scan)) + if (isalnum((unsigned char)*scan)) *scan = (char)git__tolower(*scan); else if (*scan != '-' || scan == start) return GIT_EINVALIDSPEC; diff --git a/src/libgit2/config_parse.c b/src/libgit2/config_parse.c index 1431bed36db..9ab78cc7f60 100644 --- a/src/libgit2/config_parse.c +++ b/src/libgit2/config_parse.c @@ -25,9 +25,9 @@ static void set_parse_error(git_config_parser *reader, int col, const char *erro } -GIT_INLINE(int) config_keychar(int c) +GIT_INLINE(int) config_keychar(char c) { - return isalnum(c) || c == '-'; + return isalnum((unsigned char)c) || c == '-'; } static int strip_comments(char *line, int in_quotes) @@ -158,9 +158,10 @@ static int parse_subsection_header(git_config_parser *reader, const char *line, static int parse_section_header(git_config_parser *reader, char **section_out) { char *name, *name_end; - int name_length, c, pos; + int name_length, pos; int result; char *line; + char c; size_t line_len; git_parse_advance_ws(&reader->ctx); @@ -382,7 +383,7 @@ static int parse_multiline_variable(git_config_parser *reader, git_str *value, i GIT_INLINE(bool) is_namechar(char c) { - return isalnum(c) || c == '-'; + return isalnum((unsigned char)c) || c == '-'; } static int parse_name( diff --git a/src/libgit2/path.c b/src/libgit2/path.c index a19340efe6f..50181fdbff0 100644 --- a/src/libgit2/path.c +++ b/src/libgit2/path.c @@ -202,7 +202,7 @@ GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char * { size_t count = 0; - while (len > 0 && tolower(*str) == tolower(*prefix)) { + while (len > 0 && tolower((unsigned char)*str) == tolower((unsigned char)*prefix)) { count++; str++; prefix++; diff --git a/src/libgit2/trailer.c b/src/libgit2/trailer.c index 4761c9922f2..9fb16418413 100644 --- a/src/libgit2/trailer.c +++ b/src/libgit2/trailer.c @@ -24,7 +24,7 @@ static const char *const git_generated_prefixes[] = { static int is_blank_line(const char *str) { const char *s = str; - while (*s && *s != '\n' && isspace(*s)) + while (*s && *s != '\n' && isspace((unsigned char)*s)) s++; return !*s || *s == '\n'; } @@ -93,7 +93,7 @@ static bool find_separator(size_t *out, const char *line, const char *separators return true; } - if (!whitespace_found && (isalnum(*c) || *c == '-')) + if (!whitespace_found && (isalnum((unsigned char)*c) || *c == '-')) continue; if (c != line && (*c == ' ' || *c == '\t')) { whitespace_found = 1; @@ -233,12 +233,12 @@ static size_t find_trailer_start(const char *buf, size_t len) } find_separator(&separator_pos, bol, TRAILER_SEPARATORS); - if (separator_pos >= 1 && !isspace(bol[0])) { + if (separator_pos >= 1 && !isspace((unsigned char)bol[0])) { trailer_lines++; possible_continuation_lines = 0; if (recognized_prefix) continue; - } else if (isspace(bol[0])) + } else if (isspace((unsigned char)bol[0])) possible_continuation_lines++; else { non_trailer_lines++; @@ -323,7 +323,7 @@ int git_message_trailers(git_message_trailer_array *trailer_arr, const char *mes goto ret; } - if (isalnum(*ptr) || *ptr == '-') { + if (isalnum((unsigned char)*ptr) || *ptr == '-') { /* legal key character */ NEXT(S_KEY); } diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 7805f332377..08cb7fbe5c2 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -535,10 +535,10 @@ static int parse_len(size_t *out, const char *line, size_t linelen) num[PKT_LEN_SIZE] = '\0'; for (i = 0; i < PKT_LEN_SIZE; ++i) { - if (!isxdigit(num[i])) { + if (!isxdigit((unsigned char)num[i])) { /* Make sure there are no special characters before passing to error message */ for (k = 0; k < PKT_LEN_SIZE; ++k) { - if(!isprint(num[k])) { + if(!isprint((unsigned char)num[k])) { num[k] = '.'; } } diff --git a/src/util/date.c b/src/util/date.c index 4d757e21a00..d54056842dd 100644 --- a/src/util/date.c +++ b/src/util/date.c @@ -129,9 +129,9 @@ static size_t match_string(const char *date, const char *str) for (i = 0; *date; date++, str++, i++) { if (*date == *str) continue; - if (toupper(*date) == toupper(*str)) + if (toupper((unsigned char)*date) == toupper((unsigned char)*str)) continue; - if (!isalnum(*date)) + if (!isalnum((unsigned char)*date)) break; return 0; } @@ -143,7 +143,7 @@ static int skip_alpha(const char *date) int i = 0; do { i++; - } while (isalpha(date[i])); + } while (isalpha((unsigned char)date[i])); return i; } @@ -251,7 +251,7 @@ static size_t match_multi_number(unsigned long num, char c, const char *date, ch num2 = strtol(end+1, &end, 10); num3 = -1; - if (*end == c && isdigit(end[1])) + if (*end == c && isdigit((unsigned char)end[1])) num3 = strtol(end+1, &end, 10); /* Time? Date? */ @@ -349,7 +349,7 @@ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_ case '.': case '/': case '-': - if (isdigit(end[1])) { + if (isdigit((unsigned char)end[1])) { size_t match = match_multi_number(num, *end, date, end, tm); if (match) return match; @@ -364,7 +364,7 @@ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_ n = 0; do { n++; - } while (isdigit(date[n])); + } while (isdigit((unsigned char)date[n])); /* Four-digit year or a timezone? */ if (n == 4) { @@ -518,7 +518,7 @@ static int parse_date_basic(const char *date, git_time_t *timestamp, int *offset match = match_alpha(date, &tm, offset); else if (isdigit(c)) match = match_digit(date, &tm, offset, &tm_gmt); - else if ((c == '-' || c == '+') && isdigit(date[1])) + else if ((c == '-' || c == '+') && isdigit((unsigned char)date[1])) match = match_tz(date, offset); if (!match) { @@ -682,7 +682,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm const char *end = date; int i; - while (isalpha(*++end)) + while (isalpha((unsigned char)*++end)) /* scan to non-alpha */; for (i = 0; i < 12; i++) { @@ -783,7 +783,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num) case '.': case '/': case '-': - if (isdigit(end[1])) { + if (isdigit((unsigned char)end[1])) { size_t match = match_multi_number(number, *end, date, end, tm); if (match) return date + match; diff --git a/src/util/str.c b/src/util/str.c index 0d405bfda50..625faba06db 100644 --- a/src/util/str.c +++ b/src/util/str.c @@ -485,8 +485,8 @@ int git_str_decode_percent( for (str_pos = 0; str_pos < str_len; buf->size++, str_pos++) { if (str[str_pos] == '%' && str_len > str_pos + 2 && - isxdigit(str[str_pos + 1]) && - isxdigit(str[str_pos + 2])) { + isxdigit((unsigned char)str[str_pos + 1]) && + isxdigit((unsigned char)str[str_pos + 2])) { buf->ptr[buf->size] = (HEX_DECODE(str[str_pos + 1]) << 4) + HEX_DECODE(str[str_pos + 2]); str_pos += 2; diff --git a/src/util/util.h b/src/util/util.h index 7f178b169fe..933644fd2b9 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -89,7 +89,7 @@ GIT_INLINE(int) git__tolower(int c) return (c >= 'A' && c <= 'Z') ? (c + 32) : c; } #else -# define git__tolower(a) tolower(a) +# define git__tolower(a) tolower((unsigned char)(a)) #endif extern size_t git__linenlen(const char *buffer, size_t buffer_len); diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index 3d1a0620b12..219612016b9 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -316,7 +316,7 @@ static void unposix_path(git_str *path) src = tgt = path->ptr; /* convert "/d/..." to "d:\..." */ - if (src[0] == '/' && isalpha(src[1]) && src[2] == '/') { + if (src[0] == '/' && isalpha((unsigned char)src[1]) && src[2] == '/') { *tgt++ = src[1]; *tgt++ = ':'; *tgt++ = '\\'; From 6847eed97a44170768fb89830ca894b454be0f17 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Sun, 17 Dec 2023 13:35:17 +0100 Subject: [PATCH 335/816] tests: remove test for strcasecmp strcasecmp is a posix function, testing it doesn't make sense. Functions that needs unsigned compare should use git__strcasecmp() --- tests/clar/clar.c | 3 --- tests/util/string.c | 6 ------ 2 files changed, 9 deletions(-) diff --git a/tests/clar/clar.c b/tests/clar/clar.c index 3fc2c768158..9695dc946e4 100644 --- a/tests/clar/clar.c +++ b/tests/clar/clar.c @@ -41,9 +41,6 @@ # ifndef strdup # define strdup(str) _strdup(str) # endif -# ifndef strcasecmp -# define strcasecmp(a,b) _stricmp(a,b) -# endif # ifndef __MINGW32__ # pragma comment(lib, "shell32") diff --git a/tests/util/string.c b/tests/util/string.c index de04dea6983..051f8c3298c 100644 --- a/tests/util/string.c +++ b/tests/util/string.c @@ -111,12 +111,6 @@ void test_string__strcasecmp(void) cl_assert(git__strcasecmp("foo", "FOO") == 0); cl_assert(git__strcasecmp("foo", "fOO") == 0); - cl_assert(strcasecmp("rt\303\202of", "rt dev\302\266h") > 0); - cl_assert(strcasecmp("e\342\202\254ghi=", "et") > 0); - cl_assert(strcasecmp("rt dev\302\266h", "rt\303\202of") < 0); - cl_assert(strcasecmp("et", "e\342\202\254ghi=") < 0); - cl_assert(strcasecmp("\303\215", "\303\255") < 0); - cl_assert(git__strcasecmp("rt\303\202of", "rt dev\302\266h") > 0); cl_assert(git__strcasecmp("e\342\202\254ghi=", "et") > 0); cl_assert(git__strcasecmp("rt dev\302\266h", "rt\303\202of") < 0); From 0023bf7263a6f484f2eb4c50286dca8584d443b9 Mon Sep 17 00:00:00 2001 From: Peter Pettersson Date: Sun, 17 Dec 2023 13:44:48 +0100 Subject: [PATCH 336/816] util: remove unused p_strcasecmp define It was unused and only defined in posix.h It did not exist in its Windows equivalent. --- src/util/unix/posix.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/util/unix/posix.h b/src/util/unix/posix.h index 778477e8e2f..60f27d3d333 100644 --- a/src/util/unix/posix.h +++ b/src/util/unix/posix.h @@ -54,8 +54,6 @@ GIT_INLINE(int) p_fsync(int fd) #define p_send(s,b,l,f) send(s,b,l,f) #define p_inet_pton(a, b, c) inet_pton(a, b, c) -#define p_strcasecmp(s1, s2) strcasecmp(s1, s2) -#define p_strncasecmp(s1, s2, c) strncasecmp(s1, s2, c) #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) #define p_snprintf snprintf #define p_chdir(p) chdir(p) From 9f52a4b2029596cf30cf899d64ee823e82b69aac Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 17 Dec 2023 14:21:47 +0000 Subject: [PATCH 337/816] README: replace gmaster with GitButler master is no more; GitButler is a new client using libgit2. Fixes #6689 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ed33df55f2..19fe7196976 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ functionality into your application. Language bindings like in your favorite language. `libgit2` is used to power Git GUI clients like -[GitKraken](https://gitkraken.com/) and [gmaster](https://gmaster.io/) +[GitKraken](https://gitkraken.com/) and [GitButler](https://gitbutler.com/) and on Git hosting providers like [GitHub](https://github.com/), [GitLab](https://gitlab.com/) and [Azure DevOps](https://azure.com/devops). From d963f63816fe3fcce76176abb1fbb0687d889c81 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 17 Dec 2023 20:34:08 +0000 Subject: [PATCH 338/816] process: don't try to close the status `process->status` is a status value; we were mistakenly trying to close it as a file descriptor, as if it were the `status` self-pipe that we open during process creation. Instead, don't try to close it, as it's not a file descriptor. --- src/util/unix/process.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 0c2029acb95..332f1fcdb3c 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -556,7 +556,6 @@ int git_process_close(git_process *process) CLOSE_FD(process->child_in); CLOSE_FD(process->child_out); CLOSE_FD(process->child_err); - CLOSE_FD(process->status); return 0; } From c529b2c753c0136a9246125d550d5ae15f9a0ecf Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 17 Dec 2023 20:37:23 +0000 Subject: [PATCH 339/816] ci: allow users to opt-in only to certain tests Previously, users could skip certain tests when running the CI script (`SKIP_ONLINE_TESTS=1`). Provide a mechanism for users to opt-in to only certain tests (`SKIP_TESTS=1 SKIP_ONLINE_TESTS=0`). --- ci/test.sh | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index 8c411b65fb8..56cb78ce7d5 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -3,7 +3,14 @@ set -e if [ -n "$SKIP_TESTS" ]; then - exit 0 + if [ -z "$SKIP_OFFLINE_TESTS" ]; then SKIP_OFFLINE_TESTS=1; fi + if [ -z "$SKIP_ONLINE_TESTS" ]; then SKIP_ONLINE_TESTS=1; fi + if [ -z "$SKIP_GITDAEMON_TESTS" ]; then SKIP_GITDAEMON_TESTS=1; fi + if [ -z "$SKIP_PROXY_TESTS" ]; then SKIP_PROXY_TESTS=1; fi + if [ -z "$SKIP_NTLM_TESTS" ]; then SKIP_NTLM_TESTS=1; fi + if [ -z "$SKIP_NEGOTIATE_TESTS" ]; then SKIP_NEGOTIATE_TESTS=1; fi + if [ -z "$SKIP_SSH_TESTS" ]; then SKIP_SSH_TESTS=1; fi + if [ -z "$SKIP_FUZZERS" ]; then SKIP_FUZZERS=1; fi fi # Windows doesn't run the NTLM tests properly (yet) @@ -24,6 +31,16 @@ export CLAR_HOMEDIR=${HOME} SUCCESS=1 CONTINUE_ON_FAILURE=0 +should_run() { + eval "skip=\${SKIP_${1}}" + [ -z "$skip" \ + -o "$skip" == "no" -o "$skip" == "NO" \ + -o "$skip" == "n" -o "$skip" == "N" \ + -o "$skip" == "false" -o "$skip" == "FALSE" \ + -o "$skip" == "f" -o "$skip" == "F" \ + -o "$skip" == "0" ] +} + cleanup() { echo "Cleaning up..." @@ -140,7 +157,7 @@ echo "########################################################################## echo "" -if [ -z "$SKIP_GITDAEMON_TESTS" ]; then +if should_run "GITDAEMON_TESTS"; then echo "Starting git daemon (standard)..." GIT_STANDARD_DIR=`mktemp -d ${TMPDIR}/git_standard.XXXXXXXX` git init --bare "${GIT_STANDARD_DIR}/test.git" >/dev/null @@ -160,7 +177,7 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then GIT_SHA256_PID=$! fi -if [ -z "$SKIP_PROXY_TESTS" ]; then +if should_run "PROXY_TESTS"; then curl --location --silent --show-error https://github.com/ethomson/poxyproxy/releases/download/v0.7.0/poxyproxy-0.7.0.jar >poxyproxy.jar echo "Starting HTTP proxy (Basic)..." @@ -172,7 +189,7 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then PROXY_NTLM_PID=$! fi -if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then +if should_run "NTLM_TESTS" || should_run "ONLINE_TESTS"; then curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.6.0/poxygit-0.6.0.jar >poxygit.jar echo "Starting HTTP server..." @@ -182,7 +199,7 @@ if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then HTTP_PID=$! fi -if [ -z "$SKIP_SSH_TESTS" ]; then +if should_run "SSH_TESTS"; then echo "Starting SSH server..." SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX` git init --bare "${SSHD_DIR}/test.git" >/dev/null @@ -232,7 +249,7 @@ fi # Run the tests that do not require network connectivity. -if [ -z "$SKIP_OFFLINE_TESTS" ]; then +if should_run "OFFLINE_TESTS"; then echo "" echo "##############################################################################" echo "## Running core tests" @@ -267,7 +284,7 @@ fi # allow them to retry up to 5 times export GITTEST_FLAKY_RETRY=5 -if [ -z "$SKIP_ONLINE_TESTS" ]; then +if should_run "ONLINE_TESTS"; then # Run the online tests. The "online" test suite only includes the # default online tests that do not require additional configuration. # The "proxy" and "ssh" test suites require further setup. @@ -296,7 +313,7 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then run_test online_customcert fi -if [ -z "$SKIP_GITDAEMON_TESTS" ]; then +if should_run "GITDAEMON_TESTS"; then echo "" echo "Running gitdaemon (standard) tests" echo "" @@ -324,7 +341,7 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then unset GITTEST_REMOTE_URL fi -if [ -z "$SKIP_PROXY_TESTS" ]; then +if should_run "PROXY_TESTS"; then echo "" echo "Running proxy tests (Basic authentication)" echo "" @@ -350,7 +367,7 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then unset GITTEST_REMOTE_PROXY_PASS fi -if [ -z "$SKIP_NTLM_TESTS" ]; then +if should_run "NTLM_TESTS"; then echo "" echo "Running NTLM tests (IIS emulation)" echo "" @@ -376,7 +393,7 @@ if [ -z "$SKIP_NTLM_TESTS" ]; then unset GITTEST_REMOTE_PASS fi -if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then +if should_run "NEGOTIATE_TESTS" && -n "$GITTEST_NEGOTIATE_PASSWORD" ; then echo "" echo "Running SPNEGO tests" echo "" @@ -409,7 +426,7 @@ if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then kdestroy -A fi -if [ -z "$SKIP_SSH_TESTS" ]; then +if should_run "SSH_TESTS"; then export GITTEST_REMOTE_USER=$USER export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_rsa" export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_rsa.pub" @@ -445,7 +462,7 @@ fi unset GITTEST_FLAKY_RETRY -if [ -z "$SKIP_FUZZERS" ]; then +if should_run "FUZZERS"; then echo "" echo "##############################################################################" echo "## Running fuzzers" From bc04087577828578d688d2cfeaaa1376397c7547 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 18 Dec 2023 12:08:05 +0000 Subject: [PATCH 340/816] index_pack: close fd on error If we're reading an on-disk packfile, ensure that we close the file descriptor on error. --- src/cli/cmd_index_pack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/cmd_index_pack.c b/src/cli/cmd_index_pack.c index 17698033ae7..09685c5d4db 100644 --- a/src/cli/cmd_index_pack.c +++ b/src/cli/cmd_index_pack.c @@ -97,9 +97,6 @@ int cmd_index_pack(int argc, char **argv) } } - if (!read_stdin) - p_close(fd); - if (git_indexer_commit(idx, &stats) < 0) { ret = cli_error_git(); goto done; @@ -108,6 +105,9 @@ int cmd_index_pack(int argc, char **argv) cli_progress_finish(&progress); done: + if (!read_stdin && fd >= 0) + p_close(fd); + cli_progress_dispose(&progress); git_indexer_free(idx); return ret; From ecc2ffdabb6d2d495fa3930c78b290549f7c5cd0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 18 Dec 2023 12:31:46 +0000 Subject: [PATCH 341/816] midx: avoid assignment in assert `GIT_ASSERT` may be a macro for `assert` (when `GIT_ASSERT_HARD` is defined), which may differ in debug builds. Pull the assignment out of the assertion. --- src/libgit2/midx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index d73a1da45d4..71bbb1d0eaf 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -703,9 +703,9 @@ static int midx_write( hash_cb_data.ctx = &ctx; oid_size = git_oid_size(w->oid_type); - - GIT_ASSERT((checksum_type = git_oid_algorithm(w->oid_type))); + checksum_type = git_oid_algorithm(w->oid_type); checksum_size = git_hash_size(checksum_type); + GIT_ASSERT(oid_size && checksum_type && checksum_size); if ((error = git_hash_ctx_init(&ctx, checksum_type)) < 0) return error; From 113b995f484a6be230c7118d2fd7663aec384227 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 18 Dec 2023 12:40:55 +0000 Subject: [PATCH 342/816] process: don't deref a NULL opts `opts` may be null; check before dereferencing. --- src/util/unix/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 332f1fcdb3c..15092cb217f 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -121,7 +121,7 @@ int git_process_new( GIT_ERROR_CHECK_ALLOC(process); if (git_strlist_copy_with_null(&process->args, args, args_len) < 0 || - merge_env(&process->env, env, env_len, opts->exclude_env) < 0) { + merge_env(&process->env, env, env_len, opts ? opts->exclude_env : false) < 0) { git_process_free(process); return -1; } From a46c426598c89b38aaeab38b6e15a27eaf27ca12 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 18 Dec 2023 12:56:24 +0000 Subject: [PATCH 343/816] gitattributes: .sh files are always Unixy Always checkout out shell scripts with Unix-style line endings. mingw doesn't mind, but cygwin struggles without CRLF. --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index 3d90b7d61f8..3788dc98358 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ * text=auto +ci/**/*.sh text eol=lf +script/**/*.sh text eol=lf tests/resources/** linguist-vendored From d0bb7eb7ea2537183169c1dfff3c3b068eb6b8cc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 15 Dec 2023 10:48:14 +0000 Subject: [PATCH 344/816] ci: take an optional shell parameter Allow the build matrix to specify its shell, in case we provide one in the setup (eg, Cygwin). --- .github/actions/run-build/action.yml | 9 +++++++-- .github/workflows/main.yml | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/actions/run-build/action.yml b/.github/actions/run-build/action.yml index 41145d3b4f0..bd0f59c9a88 100644 --- a/.github/actions/run-build/action.yml +++ b/.github/actions/run-build/action.yml @@ -5,14 +5,19 @@ description: Run a build step in a container or directly on the Actions runner inputs: command: description: Command to run - required: true type: string + required: true container: description: Optional container to run in type: string container-version: description: Version of the container to run type: string + shell: + description: Shell to use + type: string + required: true + default: 'bash' runs: using: 'composite' @@ -42,4 +47,4 @@ runs: else ${{ inputs.command }} fi - shell: bash + shell: ${{ inputs.shell != '' && inputs.shell || 'bash' }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bafffdc1fc8..4865cd1b6c0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -241,12 +241,14 @@ jobs: command: cd build && ../source/ci/build.sh container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} - name: Test uses: ./source/.github/actions/run-build with: command: cd build && ../source/ci/test.sh container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} - name: Upload test results uses: actions/upload-artifact@v3 if: success() || failure() From a79ef29e6ac934d262619c0dba21a0c13cc76dee Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 19 Dec 2023 11:23:12 +0000 Subject: [PATCH 345/816] ci: reorder some parameters for cleanliness --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4865cd1b6c0..2f1ff039418 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,40 +31,40 @@ jobs: platform: - name: "Linux (Xenial, GCC, OpenSSL, libssh2)" id: xenial-gcc-openssl + os: ubuntu-latest container: name: xenial env: CC: gcc CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - os: ubuntu-latest - name: Linux (Xenial, GCC, mbedTLS, OpenSSH) id: xenial-gcc-mbedtls + os: ubuntu-latest container: name: xenial env: CC: gcc CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec - os: ubuntu-latest - name: "Linux (Xenial, Clang, OpenSSL, OpenSSH)" id: xenial-clang-openssl + os: ubuntu-latest container: name: xenial env: CC: clang CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec - os: ubuntu-latest - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" id: xenial-clang-mbedtls + os: ubuntu-latest container: name: xenial env: CC: clang CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 CMAKE_GENERATOR: Ninja - os: ubuntu-latest - name: "macOS" id: macos os: macos-12 @@ -142,6 +142,7 @@ jobs: os: ubuntu-latest - name: "Sanitizer (UndefinedBehavior)" id: ubsanitizer + os: ubuntu-latest container: name: focal env: @@ -153,9 +154,9 @@ jobs: SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 - os: ubuntu-latest - name: "Sanitizer (Thread)" id: threadsanitizer + os: ubuntu-latest container: name: focal env: @@ -168,21 +169,21 @@ jobs: ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1 - os: ubuntu-latest # Experimental: SHA256 support - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" id: xenial-clang-openssl + os: ubuntu-latest container: name: xenial env: CC: clang CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON - os: ubuntu-latest - name: "macOS (SHA256)" id: macos os: macos-12 + setup-script: osx env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON @@ -190,7 +191,6 @@ jobs: PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - setup-script: osx - name: "Windows (SHA256, amd64, Visual Studio)" id: windows-amd64-vs os: windows-2019 From 9d8fa925f285c292c9d879a0fe255145d9f5bef5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 19 Dec 2023 11:24:17 +0000 Subject: [PATCH 346/816] ci: optional BUILD_WORKSPACE Setup scripts can change BUILD_WORKSPACE, for instance, if they use a different format for paths, they can replace with `cygpath` variants. --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2f1ff039418..2207345194c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -238,14 +238,14 @@ jobs: - name: Build uses: ./source/.github/actions/run-build with: - command: cd build && ../source/ci/build.sh + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/build.sh container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} shell: ${{ matrix.platform.shell }} - name: Test uses: ./source/.github/actions/run-build with: - command: cd build && ../source/ci/test.sh + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/test.sh container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} shell: ${{ matrix.platform.shell }} From 05a8d8d7becd35fc0d923e92b048a9a3ae9cc2cc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 19 Dec 2023 11:25:24 +0000 Subject: [PATCH 347/816] ci: show PATH in build script --- ci/build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/build.sh b/ci/build.sh index 80e7a61aecb..a9b66f6613f 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -61,6 +61,8 @@ if test -n "${CC}"; then "${CC}" --version 2>&1 | indent fi echo "Environment:" +echo "PATH=${BUILD_PATH}" | indent + if test -n "${CC}"; then echo "CC=${CC}" | indent fi From 90136cd4273da9d0fe7873105c877099ef449c33 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 19 Dec 2023 11:56:06 +0000 Subject: [PATCH 348/816] ci: align nightly with main Ensure that the main builds are all identical in nightly. Nightly should only add new, specialized builds. --- .github/workflows/main.yml | 11 +- .github/workflows/nightly.yml | 253 ++++++++++++++++++---------------- 2 files changed, 144 insertions(+), 120 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2207345194c..3aa214cd397 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,6 +29,7 @@ jobs: strategy: matrix: platform: + # All builds: core platforms - name: "Linux (Xenial, GCC, OpenSSL, libssh2)" id: xenial-gcc-openssl os: ubuntu-latest @@ -125,9 +126,9 @@ jobs: SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - # Sanitizers + # All builds: sanitizers - name: "Sanitizer (Memory)" - id: memorysanitizer + id: sanitizer-memory container: name: focal env: @@ -141,7 +142,7 @@ jobs: UBSAN_OPTIONS: print_stacktrace=1 os: ubuntu-latest - name: "Sanitizer (UndefinedBehavior)" - id: ubsanitizer + id: sanitizer-ub os: ubuntu-latest container: name: focal @@ -155,7 +156,7 @@ jobs: ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 - name: "Sanitizer (Thread)" - id: threadsanitizer + id: sanitizer-thread os: ubuntu-latest container: name: focal @@ -170,7 +171,7 @@ jobs: UBSAN_OPTIONS: print_stacktrace=1 TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1 - # Experimental: SHA256 support + # All builds: experimental SHA256 support - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" id: xenial-clang-openssl os: ubuntu-latest diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b48cbf51260..aca4506b26b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -26,55 +26,106 @@ jobs: strategy: matrix: platform: - - name: Linux (Xenial, GCC, OpenSSL) + # All builds: core platforms + - name: "Linux (Xenial, GCC, OpenSSL, libssh2)" + id: xenial-gcc-openssl + os: ubuntu-latest container: name: xenial env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + - name: Linux (Xenial, GCC, mbedTLS, OpenSSH) + id: xenial-gcc-mbedtls os: ubuntu-latest - - name: "Linux (Xenial, GCC, mbedTLS)" container: name: xenial env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec + - name: "Linux (Xenial, Clang, OpenSSL, OpenSSH)" + id: xenial-clang-openssl os: ubuntu-latest - - name: "Linux (Xenial, Clang, OpenSSL)" container: name: xenial env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec + - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" + id: xenial-clang-mbedtls os: ubuntu-latest - - name: "Linux (Xenial, Clang, mbedTLS)" container: name: xenial env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON - CMAKE_GENERATOR: Ninja - os: ubuntu-latest - - name: "Linux (no threads)" - container: - name: xenial - env: - CC: gcc - CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 CMAKE_GENERATOR: Ninja - os: ubuntu-latest - - name: "Linux (dynamically-loaded OpenSSL)" - container: - name: xenial + - name: "macOS" + id: macos + os: macos-12 env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON CMAKE_GENERATOR: Ninja - os: ubuntu-latest - - name: "Linux (MemorySanitizer)" + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + setup-script: osx + - name: "Windows (amd64, Visual Studio, Schannel)" + id: windows-amd64-vs + os: windows-2019 + setup-script: win32 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin + BUILD_TEMP: D:\Temp + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (x86, Visual Studio, WinHTTP)" + id: windows-x86-vs + os: windows-2019 + setup-script: win32 + env: + ARCH: x86 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin + BUILD_TEMP: D:\Temp + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (amd64, mingw, WinHTTP)" + id: windows-amd64-mingw + os: windows-2019 + setup-script: mingw + env: + ARCH: amd64 + CMAKE_GENERATOR: MinGW Makefiles + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON + BUILD_TEMP: D:\Temp + BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (x86, mingw, Schannel)" + id: windows-x86-mingw + os: windows-2019 + setup-script: mingw + env: + ARCH: x86 + CMAKE_GENERATOR: MinGW Makefiles + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel + BUILD_TEMP: D:\Temp + BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + + # All builds: sanitizers + - name: "Sanitizer (Memory)" + id: memorysanitizer container: name: focal env: @@ -87,59 +138,58 @@ jobs: ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 os: ubuntu-latest - - name: "Linux (UndefinedBehaviorSanitizer)" + - name: "Sanitizer (UndefinedBehavior)" + id: ubsanitizer + os: ubuntu-latest container: name: focal env: CC: clang-10 CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 + - name: "Sanitizer (Thread)" + id: threadsanitizer os: ubuntu-latest - - name: "Linux (ThreadSanitizer)" container: name: focal env: CC: clang-10 CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1 + + # Nightly builds: extended platforms + - name: "Linux (CentOS 7, OpenSSL)" + id: centos7-openssl os: ubuntu-latest - - name: "Linux (no mmap)" - container: - name: focal - env: - CC: clang-10 - CFLAGS: -DNO_MMAP - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local - CMAKE_GENERATOR: Ninja - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - os: ubuntu-latest - - name: "Linux (CentOS 7)" container: name: centos7 env: CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true - os: ubuntu-latest - name: "Linux (CentOS 7, dynamically-loaded OpenSSL)" + id: centos7-dynamicopenssl + os: ubuntu-latest container: name: centos7 env: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true + - name: "Linux (CentOS 8, OpenSSL)" + id: centos8-openssl os: ubuntu-latest - - name: "Linux (CentOS 8)" container: name: centos8 env: @@ -147,8 +197,9 @@ jobs: PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true - os: ubuntu-latest - name: "Linux (CentOS 8, dynamically-loaded OpenSSL)" + id: centos8-dynamicopenssl + os: ubuntu-latest container: name: centos8 env: @@ -156,79 +207,8 @@ jobs: PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true - os: ubuntu-latest - - name: "macOS" - os: macos-12 - env: - CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON - PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - setup-script: osx - - name: "Windows (amd64, Visual Studio, WinHTTP)" - os: windows-2019 - env: - ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=WinHTTP - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, Visual Studio, WinHTTP)" - os: windows-2019 - env: - ARCH: x86 - CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=WinHTTP -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (amd64, Visual Studio, Schannel)" - os: windows-2019 - env: - ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, Visual Studio, Schannel)" - os: windows-2019 - env: ARCH: x86 - CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_BUNDLED_ZLIB=ON - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (amd64, mingw, WinHTTP)" - os: windows-2019 - setup-script: mingw - env: - ARCH: amd64 - CMAKE_GENERATOR: MinGW Makefiles - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON - BUILD_TEMP: D:\Temp - BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, mingw, Schannel)" - os: windows-2019 - setup-script: mingw - env: - ARCH: x86 - CMAKE_GENERATOR: MinGW Makefiles - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel - BUILD_TEMP: D:\Temp - BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (no mmap)" - os: windows-2019 - env: - ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 - CFLAGS: -DNO_MMAP - CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true + - name: "Linux (Bionic, GCC, dynamically-loaded OpenSSL)" container: name: bionic @@ -286,7 +266,50 @@ jobs: SKIP_PROXY_TESTS: true os: ubuntu-latest - # Experimental: SHA256 support + # Nightly builds: ensure we fallback when missing core functionality + - name: "Linux (no threads)" + id: xenial-nothreads + os: ubuntu-latest + container: + name: xenial + env: + CC: gcc + CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + - name: "Linux (no mmap)" + id: focal-nommap + os: ubuntu-latest + container: + name: focal + env: + CC: clang-10 + CFLAGS: -DNO_MMAP + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local + CMAKE_GENERATOR: Ninja + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (no mmap)" + os: windows-2019 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CFLAGS: -DNO_MMAP + CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + + # Nightly builds: extended SSL support + - name: "Linux (dynamically-loaded OpenSSL)" + id: xenial-dynamicopenssl + os: ubuntu-latest + container: + name: xenial + env: + CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + + # All builds: experimental SHA256 support - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" id: xenial-clang-openssl container: From d83fccc97a8025563dc4d4c6268259a50529ac68 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 11:10:53 +0000 Subject: [PATCH 349/816] zlib: upgrade bundled zlib to v1.3 --- COPYING | 2 +- deps/zlib/CMakeLists.txt | 7 +- deps/zlib/COPYING | 27 -- deps/zlib/LICENSE | 22 ++ deps/zlib/adler32.c | 32 +- deps/zlib/crc32.c | 261 +++++--------- deps/zlib/deflate.c | 750 +++++++++++++++++---------------------- deps/zlib/deflate.h | 16 +- deps/zlib/gzguts.h | 23 +- deps/zlib/infback.c | 47 +-- deps/zlib/inffast.c | 5 +- deps/zlib/inffast.h | 2 +- deps/zlib/inflate.c | 136 ++----- deps/zlib/inftrees.c | 17 +- deps/zlib/inftrees.h | 8 +- deps/zlib/trees.c | 623 ++++++++++++++------------------ deps/zlib/zconf.h | 27 +- deps/zlib/zlib.h | 392 ++++++++++---------- deps/zlib/zutil.c | 62 +--- deps/zlib/zutil.h | 19 +- 20 files changed, 1053 insertions(+), 1425 deletions(-) delete mode 100644 deps/zlib/COPYING create mode 100644 deps/zlib/LICENSE diff --git a/COPYING b/COPYING index 25c8d8c6b78..ff5e76857e3 100644 --- a/COPYING +++ b/COPYING @@ -365,7 +365,7 @@ Public License instead of this License. The bundled ZLib code is licensed under the ZLib license: -Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + (C) 1995-2022 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/deps/zlib/CMakeLists.txt b/deps/zlib/CMakeLists.txt index 435877d869d..078ce69b32e 100644 --- a/deps/zlib/CMakeLists.txt +++ b/deps/zlib/CMakeLists.txt @@ -1,5 +1,10 @@ disable_warnings(implicit-fallthrough) -add_definitions(-DNO_VIZ -DSTDC -DNO_GZIP) +add_definitions(-DNO_VIZ -DSTDC -DNO_GZIP -DHAVE_SYS_TYPES_H -DHAVE_STDINT_H -DHAVE_STDDEF_H) + +if(MINGW OR MSYS) + add_definitions(-DZ_HAVE_UNISTD_H -D_LFS64_LARGEFILE -D_LARGEFILE64_SOURCE=1) +endif() + file(GLOB SRC_ZLIB "*.c" "*.h") list(SORT SRC_ZLIB) include_directories(".") diff --git a/deps/zlib/COPYING b/deps/zlib/COPYING deleted file mode 100644 index e2e86d76968..00000000000 --- a/deps/zlib/COPYING +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you - use this software in a product, an acknowledgment in the - product documentation would be appreciated but is not - required. - -2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source - distribution. - -Jean-loup Gailly Mark Adler - -The data format used by the zlib library is described by RFCs -(Request for Comments) 1950 to 1952 in the files rfc1950 (zlib -format), rfc1951 (deflate format) and rfc1952 (gzip format). diff --git a/deps/zlib/LICENSE b/deps/zlib/LICENSE new file mode 100644 index 00000000000..ab8ee6f7142 --- /dev/null +++ b/deps/zlib/LICENSE @@ -0,0 +1,22 @@ +Copyright notice: + + (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/deps/zlib/adler32.c b/deps/zlib/adler32.c index d0be4380a39..04b81d29bad 100644 --- a/deps/zlib/adler32.c +++ b/deps/zlib/adler32.c @@ -7,8 +7,6 @@ #include "zutil.h" -local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); - #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ @@ -60,11 +58,7 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #endif /* ========================================================================= */ -uLong ZEXPORT adler32_z(adler, buf, len) - uLong adler; - const Bytef *buf; - z_size_t len; -{ +uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { unsigned long sum2; unsigned n; @@ -131,20 +125,12 @@ uLong ZEXPORT adler32_z(adler, buf, len) } /* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { return adler32_z(adler, buf, len); } /* ========================================================================= */ -local uLong adler32_combine_(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { unsigned long sum1; unsigned long sum2; unsigned rem; @@ -169,18 +155,10 @@ local uLong adler32_combine_(adler1, adler2, len2) } /* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { return adler32_combine_(adler1, adler2, len2); } -uLong ZEXPORT adler32_combine64(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ +uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { return adler32_combine_(adler1, adler2, len2); } diff --git a/deps/zlib/crc32.c b/deps/zlib/crc32.c index 25cb7a009e1..6c38f5c04c6 100644 --- a/deps/zlib/crc32.c +++ b/deps/zlib/crc32.c @@ -98,10 +98,6 @@ # endif #endif -/* Local functions. */ -local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); -local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); - /* If available, use the ARM processor CRC32 instruction. */ #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 # define ARMCRC32 @@ -114,12 +110,7 @@ local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); instruction, if one is available. This assumes that word_t is either 32 bits or 64 bits. */ - -local z_word_t byte_swap(z_word_t word); - -local z_word_t byte_swap(word) - z_word_t word; -{ +local z_word_t byte_swap(z_word_t word) { # if W == 8 return (word & 0xff00000000000000) >> 56 | @@ -140,24 +131,77 @@ local z_word_t byte_swap(word) } #endif +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Table of powers of x for combining CRC-32s, filled in by make_crc_table() + * below. + */ + local z_crc_t FAR x2n_table[32]; +#else +/* ========================================================================= + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +# include "crc32.h" +#endif + /* CRC polynomial. */ #define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ -#ifdef DYNAMIC_CRC_TABLE +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp(z_crc_t a, z_crc_t b) { + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp(z_off64_t n, unsigned k) { + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Build the tables for byte-wise and braided CRC-32 calculations, and a table + * of powers of x for combining CRC-32s. + */ local z_crc_t FAR crc_table[256]; -local z_crc_t FAR x2n_table[32]; -local void make_crc_table OF((void)); #ifdef W local z_word_t FAR crc_big_table[256]; local z_crc_t FAR crc_braid_table[W][256]; local z_word_t FAR crc_braid_big_table[W][256]; - local void braid OF((z_crc_t [][256], z_word_t [][256], int, int)); + local void braid(z_crc_t [][256], z_word_t [][256], int, int); #endif #ifdef MAKECRCH - local void write_table OF((FILE *, const z_crc_t FAR *, int)); - local void write_table32hi OF((FILE *, const z_word_t FAR *, int)); - local void write_table64 OF((FILE *, const z_word_t FAR *, int)); + local void write_table(FILE *, const z_crc_t FAR *, int); + local void write_table32hi(FILE *, const z_word_t FAR *, int); + local void write_table64(FILE *, const z_word_t FAR *, int); #endif /* MAKECRCH */ /* @@ -170,7 +214,6 @@ local void make_crc_table OF((void)); /* Definition of once functionality. */ typedef struct once_s once_t; -local void once OF((once_t *, void (*)(void))); /* Check for the availability of atomics. */ #if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ @@ -190,10 +233,7 @@ struct once_s { invoke once() at the same time. The state must be a once_t initialized with ONCE_INIT. */ -local void once(state, init) - once_t *state; - void (*init)(void); -{ +local void once(once_t *state, void (*init)(void)) { if (!atomic_load(&state->done)) { if (atomic_flag_test_and_set(&state->begun)) while (!atomic_load(&state->done)) @@ -216,10 +256,7 @@ struct once_s { /* Test and set. Alas, not atomic, but tries to minimize the period of vulnerability. */ -local int test_and_set OF((int volatile *)); -local int test_and_set(flag) - int volatile *flag; -{ +local int test_and_set(int volatile *flag) { int was; was = *flag; @@ -228,10 +265,7 @@ local int test_and_set(flag) } /* Run the provided init() function once. This is not thread-safe. */ -local void once(state, init) - once_t *state; - void (*init)(void); -{ +local void once(once_t *state, void (*init)(void)) { if (!state->done) { if (test_and_set(&state->begun)) while (!state->done) @@ -273,8 +307,7 @@ local once_t made = ONCE_INIT; combinations of CRC register values and incoming bytes. */ -local void make_crc_table() -{ +local void make_crc_table(void) { unsigned i, j, n; z_crc_t p; @@ -441,11 +474,7 @@ local void make_crc_table() Write the 32-bit values in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ -local void write_table(out, table, k) - FILE *out; - const z_crc_t FAR *table; - int k; -{ +local void write_table(FILE *out, const z_crc_t FAR *table, int k) { int n; for (n = 0; n < k; n++) @@ -458,11 +487,7 @@ local void write_table(out, table, k) Write the high 32-bits of each value in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ -local void write_table32hi(out, table, k) -FILE *out; -const z_word_t FAR *table; -int k; -{ +local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) { int n; for (n = 0; n < k; n++) @@ -478,11 +503,7 @@ int k; bits. If not, then the type cast and format string can be adjusted accordingly. */ -local void write_table64(out, table, k) - FILE *out; - const z_word_t FAR *table; - int k; -{ +local void write_table64(FILE *out, const z_word_t FAR *table, int k) { int n; for (n = 0; n < k; n++) @@ -492,8 +513,7 @@ local void write_table64(out, table, k) } /* Actually do the deed. */ -int main() -{ +int main(void) { make_crc_table(); return 0; } @@ -505,12 +525,7 @@ int main() Generate the little and big-endian braid tables for the given n and z_word_t size w. Each array must have room for w blocks of 256 elements. */ -local void braid(ltl, big, n, w) - z_crc_t ltl[][256]; - z_word_t big[][256]; - int n; - int w; -{ +local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { int k; z_crc_t i, p, q; for (k = 0; k < w; k++) { @@ -525,69 +540,13 @@ local void braid(ltl, big, n, w) } #endif -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables for byte-wise and braided CRC-32 calculations, and a table of powers - * of x for combining CRC-32s, all made by make_crc_table(). - */ -#include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Routines used for CRC calculation. Some are also required for the table - * generation above. - */ - -/* - Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, - reflected. For speed, this requires that a not be zero. - */ -local z_crc_t multmodp(a, b) - z_crc_t a; - z_crc_t b; -{ - z_crc_t m, p; - - m = (z_crc_t)1 << 31; - p = 0; - for (;;) { - if (a & m) { - p ^= b; - if ((a & (m - 1)) == 0) - break; - } - m >>= 1; - b = b & 1 ? (b >> 1) ^ POLY : b >> 1; - } - return p; -} - -/* - Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been - initialized. - */ -local z_crc_t x2nmodp(n, k) - z_off64_t n; - unsigned k; -{ - z_crc_t p; - - p = (z_crc_t)1 << 31; /* x^0 == 1 */ - while (n) { - if (n & 1) - p = multmodp(x2n_table[k & 31], p); - n >>= 1; - k++; - } - return p; -} - /* ========================================================================= * This function can be used by asm versions of crc32(), and to force the * generation of the CRC tables in a threaded application. */ -const z_crc_t FAR * ZEXPORT get_crc_table() -{ +const z_crc_t FAR * ZEXPORT get_crc_table(void) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ @@ -613,11 +572,8 @@ const z_crc_t FAR * ZEXPORT get_crc_table() #define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ #define Z_BATCH_MIN 800 /* fewest words in a final batch */ -unsigned long ZEXPORT crc32_z(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { z_crc_t val; z_word_t crc1, crc2; const z_word_t *word; @@ -633,7 +589,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ - crc ^= 0xffffffff; + crc = (~crc) & 0xffffffff; /* Compute the CRC up to a word boundary. */ while (len && ((z_size_t)buf & 7) != 0) { @@ -648,8 +604,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) len &= 7; /* Do three interleaved CRCs to realize the throughput of one crc32x - instruction per cycle. Each CRC is calcuated on Z_BATCH words. The three - CRCs are combined into a single CRC after each set of batches. */ + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ while (num >= 3 * Z_BATCH) { crc1 = 0; crc2 = 0; @@ -712,26 +668,19 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #ifdef W -local z_crc_t crc_word(z_word_t data); -local z_word_t crc_word_big(z_word_t data); - /* Return the CRC of the W bytes in the word_t data, taking the least-significant byte of the word as the first byte of data, without any pre or post conditioning. This is used to combine the CRCs of each braid. */ -local z_crc_t crc_word(data) - z_word_t data; -{ +local z_crc_t crc_word(z_word_t data) { int k; for (k = 0; k < W; k++) data = (data >> 8) ^ crc_table[data & 0xff]; return (z_crc_t)data; } -local z_word_t crc_word_big(data) - z_word_t data; -{ +local z_word_t crc_word_big(z_word_t data) { int k; for (k = 0; k < W; k++) data = (data << 8) ^ @@ -742,11 +691,8 @@ local z_word_t crc_word_big(data) #endif /* ========================================================================= */ -unsigned long ZEXPORT crc32_z(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { /* Return initial CRC, if requested. */ if (buf == Z_NULL) return 0; @@ -755,7 +701,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ - crc ^= 0xffffffff; + crc = (~crc) & 0xffffffff; #ifdef W @@ -778,8 +724,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) words = (z_word_t const *)buf; /* Do endian check at execution time instead of compile time, since ARM - processors can change the endianess at execution time. If the - compiler knows what the endianess will be, it can optimize out the + processors can change the endianness at execution time. If the + compiler knows what the endianness will be, it can optimize out the check and the unused branch. */ endian = 1; if (*(unsigned char *)&endian) { @@ -1066,39 +1012,26 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - uInt len; -{ +unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, + uInt len) { return crc32_z(crc, buf, len); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine64(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ +uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ - return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - return crc32_combine64(crc1, crc2, len2); +uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { + return crc32_combine64(crc1, crc2, (z_off64_t)len2); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine_gen64(len2) - z_off64_t len2; -{ +uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ @@ -1106,17 +1039,11 @@ uLong ZEXPORT crc32_combine_gen64(len2) } /* ========================================================================= */ -uLong ZEXPORT crc32_combine_gen(len2) - z_off_t len2; -{ - return crc32_combine_gen64(len2); +uLong ZEXPORT crc32_combine_gen(z_off_t len2) { + return crc32_combine_gen64((z_off64_t)len2); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine_op(crc1, crc2, op) - uLong crc1; - uLong crc2; - uLong op; -{ - return multmodp(op, crc1) ^ crc2; +uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); } diff --git a/deps/zlib/deflate.c b/deps/zlib/deflate.c index feacd78327d..bd011751920 100644 --- a/deps/zlib/deflate.c +++ b/deps/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.12 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; + " deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -60,9 +60,6 @@ const char deflate_copyright[] = copyright string in the executable of your product. */ -/* =========================================================================== - * Function prototypes. - */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ @@ -70,35 +67,16 @@ typedef enum { finish_done /* finish done, accept no more input or output */ } block_state; -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +typedef block_state (*compress_func)(deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ -local int deflateStateCheck OF((z_streamp strm)); -local void slide_hash OF((deflate_state *s)); -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_stored(deflate_state *s, int flush); +local block_state deflate_fast(deflate_state *s, int flush); #ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local block_state deflate_rle OF((deflate_state *s, int flush)); -local block_state deflate_huff OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV -# pragma message("Assembler code may have bugs -- use at your own risk") - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef ZLIB_DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); +local block_state deflate_slow(deflate_state *s, int flush); #endif +local block_state deflate_rle(deflate_state *s, int flush); +local block_state deflate_huff(deflate_state *s, int flush); /* =========================================================================== * Local data @@ -160,7 +138,7 @@ local const config configuration_table[10] = { * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== @@ -191,9 +169,9 @@ local const config configuration_table[10] = { */ #define CLEAR_HASH(s) \ do { \ - s->head[s->hash_size-1] = NIL; \ + s->head[s->hash_size - 1] = NIL; \ zmemzero((Bytef *)s->head, \ - (unsigned)(s->hash_size-1)*sizeof(*s->head)); \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ } while (0) /* =========================================================================== @@ -203,12 +181,10 @@ local const config configuration_table[10] = { */ #if defined(__has_feature) # if __has_feature(memory_sanitizer) -__attribute__((no_sanitize("memory"))) + __attribute__((no_sanitize("memory"))) # endif #endif -local void slide_hash(s) - deflate_state *s; -{ +local void slide_hash(deflate_state *s) { unsigned n, m; Posf *p; uInt wsize = s->w_size; @@ -232,30 +208,177 @@ local void slide_hash(s) #endif } +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) { + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(deflate_state *s) { + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize + MAX_DIST(s)) { + + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + /* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, + int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size) { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; @@ -290,6 +413,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP @@ -319,7 +444,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); @@ -345,11 +470,11 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, * sym_buf value to read moves forward three bytes. From that symbol, up to * 31 bits are written to pending_buf. The closest the written pending_buf * bits gets to the next sym_buf symbol to read is just before the last - * code is written. At that time, 31*(n-2) bits have been written, just - * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at - * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 * symbols are written.) The closest the writing gets to what is unread is - * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and * can range from 128 to 32768. * * Therefore, at a minimum, there are 142 bits of space between what is @@ -395,9 +520,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -local int deflateStateCheck (strm) - z_streamp strm; -{ +local int deflateStateCheck(z_streamp strm) { deflate_state *s; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) @@ -418,11 +541,8 @@ local int deflateStateCheck (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ +int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { deflate_state *s; uInt str, n; int wrap; @@ -487,11 +607,8 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) - z_streamp strm; - Bytef *dictionary; - uInt *dictLength; -{ +int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { deflate_state *s; uInt len; @@ -509,9 +626,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) - z_streamp strm; -{ +int ZEXPORT deflateResetKeep(z_streamp strm) { deflate_state *s; if (deflateStateCheck(strm)) { @@ -546,10 +661,32 @@ int ZEXPORT deflateResetKeep (strm) return Z_OK; } +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init(deflate_state *s) { + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +} + /* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ +int ZEXPORT deflateReset(z_streamp strm) { int ret; ret = deflateResetKeep(strm); @@ -559,10 +696,7 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ +int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) { if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; @@ -570,11 +704,7 @@ int ZEXPORT deflateSetHeader (strm, head) } /* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) - unsigned *pending; - int *bits; - z_streamp strm; -{ +int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; @@ -584,11 +714,7 @@ int ZEXPORT deflatePending (strm, pending, bits) } /* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ +int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { deflate_state *s; int put; @@ -611,11 +737,7 @@ int ZEXPORT deflatePrime (strm, bits, value) } /* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ +int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) { deflate_state *s; compress_func func; @@ -660,13 +782,8 @@ int ZEXPORT deflateParams(strm, level, strategy) } /* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ +int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, + int nice_length, int max_chain) { deflate_state *s; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -679,36 +796,47 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) } /* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. + * + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ +uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { deflate_state *s; - uLong complen, wraplen; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; - /* if can't get parameters, return conservative bound plus zlib wrapper */ + /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) - return complen + 6; + return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; @@ -745,11 +873,13 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen = 6; } - /* if not default parameters, return conservative bound */ + /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; + return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + + wraplen; - /* default settings: return tight bound for that case */ + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } @@ -759,10 +889,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ +local void putShortMSB(deflate_state *s, uInt b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } @@ -773,9 +900,7 @@ local void putShortMSB (s, b) * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ -local void flush_pending(strm) - z_streamp strm; -{ +local void flush_pending(z_streamp strm) { unsigned len; deflate_state *s = strm->state; @@ -806,10 +931,7 @@ local void flush_pending(strm) } while (0) /* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ +int ZEXPORT deflate(z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; @@ -861,7 +983,7 @@ int ZEXPORT deflate (strm, flush) s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) @@ -1121,9 +1243,7 @@ int ZEXPORT deflate (strm, flush) } /* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ +int ZEXPORT deflateEnd(z_streamp strm) { int status; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1147,11 +1267,10 @@ int ZEXPORT deflateEnd (strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ +int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { #ifdef MAXSEG_64K + (void)dest; + (void)source; return Z_STREAM_ERROR; #else deflate_state *ds; @@ -1199,71 +1318,6 @@ int ZEXPORT deflateCopy (dest, source) #endif /* MAXSEG_64K */ } -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local unsigned read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, buf, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, buf, len); - } -#endif - strm->next_in += len; - strm->total_in += len; - - return len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->insert = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and @@ -1274,14 +1328,7 @@ local void lm_init (s) * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ @@ -1302,10 +1349,10 @@ local uInt longest_match(s, cur_match) */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); + register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif @@ -1323,7 +1370,8 @@ local uInt longest_match(s, cur_match) */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); @@ -1341,43 +1389,44 @@ local uInt longest_match(s, cur_match) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ - if (*(ushf*)(match+best_len-1) != scan_end || + if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient + * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); if (*scan == *match) scan++; - len = (MAX_MATCH - 1) - (int)(strend-scan); + len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1387,7 +1436,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1396,7 +1445,8 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; @@ -1408,9 +1458,9 @@ local uInt longest_match(s, cur_match) best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); + scan_end = *(ushf*)(scan + best_len - 1); #else - scan_end1 = scan[best_len-1]; + scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } @@ -1420,17 +1470,13 @@ local uInt longest_match(s, cur_match) if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } -#endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ @@ -1441,7 +1487,8 @@ local uInt longest_match(s, cur_match) */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); Assert(cur_match < s->strstart, "no future"); @@ -1451,7 +1498,7 @@ local uInt longest_match(s, cur_match) */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1461,7 +1508,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1470,7 +1517,7 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); @@ -1490,11 +1537,7 @@ local uInt longest_match(s, cur_match) /* =========================================================================== * Check that the match at match_start is indeed a match. */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ +local void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { @@ -1506,7 +1549,7 @@ local void check_match(s, start, match, length) z_error("invalid match"); } if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); + fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } @@ -1514,137 +1557,6 @@ local void check_match(s, start, match, length) # define check_match(s, start, match, length) #endif /* ZLIB_DEBUG */ -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - unsigned n; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - if (s->insert > s->strstart) - s->insert = s->strstart; - slide_hash(s); - more += wsize; - } - if (s->strm->avail_in == 0) break; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead + s->insert >= MIN_MATCH) { - uInt str = s->strstart - s->insert; - s->ins_h = s->window[str]; - UPDATE_HASH(s, s->ins_h, s->window[str + 1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - while (s->insert) { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - s->insert--; - if (s->lookahead + s->insert < MIN_MATCH) - break; - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ - if (s->high_water < s->window_size) { - ulg curr = s->strstart + (ulg)(s->lookahead); - ulg init; - - if (s->high_water < curr) { - /* Previous high water mark below current data -- zero WIN_INIT - * bytes or up to end of window, whichever is less. - */ - init = s->window_size - curr; - if (init > WIN_INIT) - init = WIN_INIT; - zmemzero(s->window + curr, (unsigned)init); - s->high_water = curr + init; - } - else if (s->high_water < (ulg)curr + WIN_INIT) { - /* High water mark at or above current data, but below current data - * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up - * to end of window, whichever is less. - */ - init = (ulg)curr + WIN_INIT - s->high_water; - if (init > s->window_size - s->high_water) - init = s->window_size - s->high_water; - zmemzero(s->window + s->high_water, (unsigned)init); - s->high_water += init; - } - } - - Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, - "not enough room for search"); -} - /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. @@ -1685,12 +1597,9 @@ local void fill_window(s) * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. + * maximizes the opportunities to have a single copy from next_in to next_out. */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_stored(deflate_state *s, int flush) { /* Smallest worthy block size when not flushing or finishing. By default * this is 32K. This can be as small as 507 bytes for memLevel == 1. For * large input and output buffers, the stored block size will be larger. @@ -1874,10 +1783,7 @@ local block_state deflate_stored(s, flush) * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_fast(deflate_state *s, int flush) { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ @@ -1895,7 +1801,7 @@ local block_state deflate_fast(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1943,7 +1849,7 @@ local block_state deflate_fast(s, flush) s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif @@ -1954,7 +1860,7 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -1976,10 +1882,7 @@ local block_state deflate_fast(s, flush) * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_slow(deflate_state *s, int flush) { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ @@ -1998,7 +1901,7 @@ local block_state deflate_slow(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -2040,17 +1943,17 @@ local block_state deflate_slow(s, flush) uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - check_match(s, s->strstart-1, s->prev_match, s->prev_length); + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - _tr_tally_dist(s, s->strstart -1 - s->prev_match, + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not + * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ - s->lookahead -= s->prev_length-1; + s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { @@ -2068,8 +1971,8 @@ local block_state deflate_slow(s, flush) * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } @@ -2087,8 +1990,8 @@ local block_state deflate_slow(s, flush) } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; @@ -2107,10 +2010,7 @@ local block_state deflate_slow(s, flush) * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_rle(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ @@ -2145,7 +2045,8 @@ local block_state deflate_rle(s, flush) if (s->match_length > s->lookahead) s->match_length = s->lookahead; } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ @@ -2160,7 +2061,7 @@ local block_state deflate_rle(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -2180,10 +2081,7 @@ local block_state deflate_rle(s, flush) * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ -local block_state deflate_huff(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_huff(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ for (;;) { @@ -2200,7 +2098,7 @@ local block_state deflate_huff(s, flush) /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); diff --git a/deps/zlib/deflate.h b/deps/zlib/deflate.h index 1a06cd5f25d..8696791429f 100644 --- a/deps/zlib/deflate.h +++ b/deps/zlib/deflate.h @@ -291,14 +291,14 @@ typedef struct internal_state { memory checker errors from longest match routines */ /* in trees.c */ -void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); -int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); -void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_init(deflate_state *s); +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc); +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last); +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s); +void ZLIB_INTERNAL _tr_align(deflate_state *s); +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) diff --git a/deps/zlib/gzguts.h b/deps/zlib/gzguts.h index 57faf37165a..f9375047e8c 100644 --- a/deps/zlib/gzguts.h +++ b/deps/zlib/gzguts.h @@ -7,9 +7,8 @@ # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif -# ifdef _FILE_OFFSET_BITS -# undef _FILE_OFFSET_BITS -# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS #endif #ifdef HAVE_HIDDEN @@ -119,8 +118,8 @@ /* gz* functions always use library allocation functions */ #ifndef STDC - extern voidp malloc OF((uInt size)); - extern void free OF((voidpf ptr)); + extern voidp malloc(uInt size); + extern void free(voidpf ptr); #endif /* get errno and strerror definition */ @@ -138,10 +137,10 @@ /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); #endif /* default memLevel */ @@ -203,9 +202,9 @@ typedef struct { typedef gz_state FAR *gz_statep; /* shared functions */ -void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); #if defined UNDER_CE -char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +char ZLIB_INTERNAL *gz_strwinerror(DWORD error); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t @@ -214,6 +213,6 @@ char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else -unsigned ZLIB_INTERNAL gz_intmax OF((void)); +unsigned ZLIB_INTERNAL gz_intmax(void); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif diff --git a/deps/zlib/infback.c b/deps/zlib/infback.c index a390c58e816..e7b25b307a3 100644 --- a/deps/zlib/infback.c +++ b/deps/zlib/infback.c @@ -15,9 +15,6 @@ #include "inflate.h" #include "inffast.h" -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. @@ -25,13 +22,9 @@ local void fixedtables OF((struct inflate_state FAR *state)); windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ +int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, const char *version, + int stream_size) { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || @@ -66,6 +59,7 @@ int stream_size; state->window = window; state->wnext = 0; state->whave = 0; + state->sane = 1; return Z_OK; } @@ -79,9 +73,7 @@ int stream_size; used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ +local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; @@ -247,13 +239,8 @@ struct inflate_state FAR *state; inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ +int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ @@ -605,33 +592,33 @@ void FAR *out_desc; break; case DONE: - /* inflate stream terminated properly -- write leftover output */ + /* inflate stream terminated properly */ ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; - default: /* can't happen, but makes compilers happy */ + default: + /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } - /* Return unused input */ + /* Write leftover output and return unused input */ inf_leave: + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left) && + ret == Z_STREAM_END) + ret = Z_BUF_ERROR; + } strm->next_in = next; strm->avail_in = have; return ret; } -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ +int ZEXPORT inflateBackEnd(z_streamp strm) { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); diff --git a/deps/zlib/inffast.c b/deps/zlib/inffast.c index 1fec7f363fa..9354676e786 100644 --- a/deps/zlib/inffast.c +++ b/deps/zlib/inffast.c @@ -47,10 +47,7 @@ requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ -void ZLIB_INTERNAL inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ diff --git a/deps/zlib/inffast.h b/deps/zlib/inffast.h index e5c1aa4ca8c..49c6d156c5c 100644 --- a/deps/zlib/inffast.h +++ b/deps/zlib/inffast.h @@ -8,4 +8,4 @@ subject to change. Applications should only use zlib.h. */ -void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); diff --git a/deps/zlib/inflate.c b/deps/zlib/inflate.c index 7be8c63662a..b0757a9b249 100644 --- a/deps/zlib/inflate.c +++ b/deps/zlib/inflate.c @@ -91,20 +91,7 @@ # endif #endif -/* function prototypes */ -local int inflateStateCheck OF((z_streamp strm)); -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, - unsigned copy)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, - unsigned len)); - -local int inflateStateCheck(strm) -z_streamp strm; -{ +local int inflateStateCheck(z_streamp strm) { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) @@ -116,9 +103,7 @@ z_streamp strm; return 0; } -int ZEXPORT inflateResetKeep(strm) -z_streamp strm; -{ +int ZEXPORT inflateResetKeep(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -142,9 +127,7 @@ z_streamp strm; return Z_OK; } -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ +int ZEXPORT inflateReset(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -155,10 +138,7 @@ z_streamp strm; return inflateResetKeep(strm); } -int ZEXPORT inflateReset2(strm, windowBits) -z_streamp strm; -int windowBits; -{ +int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { int wrap; struct inflate_state FAR *state; @@ -168,6 +148,8 @@ int windowBits; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } @@ -193,12 +175,8 @@ int windowBits; return inflateReset(strm); } -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ +int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) { int ret; struct inflate_state FAR *state; @@ -237,22 +215,17 @@ int stream_size; return ret; } -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ +int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ +int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; @@ -276,9 +249,7 @@ int value; used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ +local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; @@ -340,7 +311,7 @@ struct inflate_state FAR *state; a.out > inffixed.h */ -void makefixed() +void makefixed(void) { unsigned low, size; struct inflate_state state; @@ -394,11 +365,7 @@ void makefixed() output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ -local int updatewindow(strm, end, copy) -z_streamp strm; -const Bytef *end; -unsigned copy; -{ +local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { struct inflate_state FAR *state; unsigned dist; @@ -620,10 +587,7 @@ unsigned copy; will return Z_BUF_ERROR if it has not reached the end of the stream. */ -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ +int ZEXPORT inflate(z_streamp strm, int flush) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ @@ -764,8 +728,9 @@ int flush; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); @@ -1298,9 +1263,7 @@ int flush; return ret; } -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ +int ZEXPORT inflateEnd(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1312,11 +1275,8 @@ z_streamp strm; return Z_OK; } -int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) -z_streamp strm; -Bytef *dictionary; -uInt *dictLength; -{ +int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { struct inflate_state FAR *state; /* check state */ @@ -1335,11 +1295,8 @@ uInt *dictLength; return Z_OK; } -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ +int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { struct inflate_state FAR *state; unsigned long dictid; int ret; @@ -1370,10 +1327,7 @@ uInt dictLength; return Z_OK; } -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ +int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { struct inflate_state FAR *state; /* check state */ @@ -1398,11 +1352,8 @@ gz_headerp head; called again with more data and the *have state. *have is initialized to zero for the first call. */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -const unsigned char FAR *buf; -unsigned len; -{ +local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, + unsigned len) { unsigned got; unsigned next; @@ -1421,9 +1372,7 @@ unsigned len; return next; } -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ +int ZEXPORT inflateSync(z_streamp strm) { unsigned len; /* number of bytes to look at or looked at */ int flags; /* temporary to save header status */ unsigned long in, out; /* temporary to save total_in and total_out */ @@ -1479,9 +1428,7 @@ z_streamp strm; block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ +int ZEXPORT inflateSyncPoint(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1489,10 +1436,7 @@ z_streamp strm; return state->mode == STORED && state->bits == 0; } -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ +int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; @@ -1536,10 +1480,7 @@ z_streamp source; return Z_OK; } -int ZEXPORT inflateUndermine(strm, subvert) -z_streamp strm; -int subvert; -{ +int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1554,10 +1495,7 @@ int subvert; #endif } -int ZEXPORT inflateValidate(strm, check) -z_streamp strm; -int check; -{ +int ZEXPORT inflateValidate(z_streamp strm, int check) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1569,9 +1507,7 @@ int check; return Z_OK; } -long ZEXPORT inflateMark(strm) -z_streamp strm; -{ +long ZEXPORT inflateMark(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) @@ -1582,9 +1518,7 @@ z_streamp strm; (state->mode == MATCH ? state->was - state->length : 0)); } -unsigned long ZEXPORT inflateCodesUsed(strm) -z_streamp strm; -{ +unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; diff --git a/deps/zlib/inftrees.c b/deps/zlib/inftrees.c index 09462a740b1..8a208c2daa8 100644 --- a/deps/zlib/inftrees.c +++ b/deps/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2022 Mark Adler + * Copyright (C) 1995-2023 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.12 Copyright 1995-2022 Mark Adler "; + " inflate 1.3 Copyright 1995-2023 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -29,14 +29,9 @@ const char inflate_copyright[] = table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ -int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work) { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ @@ -62,7 +57,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 199, 202}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/deps/zlib/inftrees.h b/deps/zlib/inftrees.h index baa53a0b1a1..a10712d8cb5 100644 --- a/deps/zlib/inftrees.h +++ b/deps/zlib/inftrees.h @@ -38,7 +38,7 @@ typedef struct { /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that + examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. @@ -57,6 +57,6 @@ typedef enum { DISTS } codetype; -int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); diff --git a/deps/zlib/trees.c b/deps/zlib/trees.c index 8b438cce4f3..8dbdc40bacc 100644 --- a/deps/zlib/trees.c +++ b/deps/zlib/trees.c @@ -122,39 +122,116 @@ struct static_tree_desc_s { int max_length; /* max bit length for the codes */ }; -local const static_tree_desc static_l_desc = +#ifdef NO_INIT_GLOBAL_POINTERS +# define TCONST +#else +# define TCONST const +#endif + +local TCONST static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -local const static_tree_desc static_d_desc = +local TCONST static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -local const static_tree_desc static_bl_desc = +local TCONST static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== - * Local (static) routines in this file. + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, const ct_data *ltree, - const ct_data *dtree)); -local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned code, int len)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(unsigned code, int len) { + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(deflate_state *s) { + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(deflate_state *s) { + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent + 7) & ~7; +#endif +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) { + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); + } +} #ifdef GEN_TREES_H -local void gen_trees_header OF((void)); +local void gen_trees_header(void); #endif #ifndef ZLIB_DEBUG @@ -167,33 +244,18 @@ local void gen_trees_header OF((void)); send_bits(s, tree[c].Code, tree[c].Len); } #endif -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef ZLIB_DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ +local void send_bits(deflate_state *s, int value, int length) { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { @@ -229,8 +291,7 @@ local void send_bits(s, value, length) /* =========================================================================== * Initialize the various 'constant' tables. */ -local void tr_static_init() -{ +local void tr_static_init(void) { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ @@ -256,7 +317,7 @@ local void tr_static_init() length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; @@ -312,7 +373,7 @@ local void tr_static_init() } /* =========================================================================== - * Genererate the file trees.h describing the static trees. + * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG @@ -321,10 +382,9 @@ local void tr_static_init() # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) -void gen_trees_header() -{ +void gen_trees_header(void) { FILE *header = fopen("trees.h", "w"); int i; @@ -373,12 +433,26 @@ void gen_trees_header() } #endif /* GEN_TREES_H */ +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(deflate_state *s) { + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ -void ZLIB_INTERNAL _tr_init(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_init(deflate_state *s) { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; @@ -401,24 +475,6 @@ void ZLIB_INTERNAL _tr_init(s) init_block(s); } -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->sym_next = s->matches = 0; -} - #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ @@ -448,17 +504,13 @@ local void init_block(s) * when the heap property is re-established (each father smaller than its * two sons). */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ +local void pqdownheap(deflate_state *s, ct_data *tree, int k) { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ @@ -483,10 +535,7 @@ local void pqdownheap(s, tree, k) * The length opt_len is updated; static_len is also updated if stree is * not null. */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void gen_bitlen(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; @@ -507,7 +556,7 @@ local void gen_bitlen(s, desc) */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; @@ -518,7 +567,7 @@ local void gen_bitlen(s, desc) s->bl_count[bits]++; xbits = 0; - if (n >= base) xbits = extra[n-base]; + if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); @@ -530,10 +579,10 @@ local void gen_bitlen(s, desc) /* Find the first bit length which could increase: */ do { - bits = max_length-1; + bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -561,48 +610,9 @@ local void gen_bitlen(s, desc) } } -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - unsigned code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; - next_code[bits] = (ush)code; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1< +#endif /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. @@ -612,10 +622,7 @@ local void gen_codes (tree, max_code, bl_count) * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ -local void build_tree(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void build_tree(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; @@ -624,7 +631,7 @@ local void build_tree(s, desc) int node; /* new node being created */ /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; @@ -652,7 +659,7 @@ local void build_tree(s, desc) } desc->max_code = max_code; - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); @@ -700,11 +707,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void scan_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -714,10 +717,10 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ + tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -745,11 +748,7 @@ local void scan_tree (s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void send_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -758,11 +757,11 @@ local void send_tree (s, tree, max_code) int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ - /* tree[max_code+1].Len = -1; */ /* guard already set */ + /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -773,13 +772,13 @@ local void send_tree (s, tree, max_code) send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { @@ -796,9 +795,7 @@ local void send_tree (s, tree, max_code) * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ -local int build_bl_tree(s) - deflate_state *s; -{ +local int build_bl_tree(deflate_state *s) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ @@ -807,8 +804,8 @@ local int build_bl_tree(s) /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format @@ -819,7 +816,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -831,42 +828,36 @@ local int build_bl_tree(s) * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ +local void send_all_trees(deflate_state *s, int lcodes, int dcodes, + int blcodes) { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ -void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); @@ -877,16 +868,14 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; + s->bits_sent += stored_len << 3; #endif } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ -void ZLIB_INTERNAL _tr_flush_bits(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) { bi_flush(s); } @@ -894,9 +883,7 @@ void ZLIB_INTERNAL _tr_flush_bits(s) * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ -void ZLIB_INTERNAL _tr_align(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_align(deflate_state *s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef ZLIB_DEBUG @@ -905,16 +892,99 @@ void ZLIB_INTERNAL _tr_align(s) bi_flush(s); } +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(deflate_state *s, const ct_data *ltree, + const ct_data *dtree) { + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in sym_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->sym_next != 0) do { + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and sym_buf is ok: */ + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); + + } while (sx < s->sym_next); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(deflate_state *s) { + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long block_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>= 1) + if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("allow-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ -void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ @@ -943,14 +1013,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); @@ -960,7 +1033,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. @@ -971,21 +1044,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) */ _tr_stored_block(s, buf, stored_len, last); -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG @@ -1004,19 +1073,15 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) s->compressed_len += 7; /* align on byte boundary */ #endif } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { s->sym_buf[s->sym_next++] = (uch)dist; s->sym_buf[s->sym_next++] = (uch)(dist >> 8); s->sym_buf[s->sym_next++] = (uch)lc; @@ -1031,152 +1096,8 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } return (s->sym_next == s->sym_end); } - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - const ct_data *ltree; /* literal tree */ - const ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned sx = 0; /* running index in sym_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->sym_next != 0) do { - dist = s->sym_buf[sx++] & 0xff; - dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; - lc = s->sym_buf[sx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= (unsigned)base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and sym_buf is ok: */ - Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); - - } while (sx < s->sym_next); - - send_code(s, END_BLOCK, ltree); -} - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "block list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local int detect_data_type(s) - deflate_state *s; -{ - /* block_mask is the bit mask of block-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - unsigned long block_mask = 0xf3ffc07fUL; - int n; - - /* Check for non-textual ("block-listed") bytes. */ - for (n = 0; n <= 31; n++, block_mask >>= 1) - if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) - return Z_BINARY; - - /* Check for textual ("allow-listed") bytes. */ - if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 - || s->dyn_ltree[13].Freq != 0) - return Z_TEXT; - for (n = 32; n < LITERALS; n++) - if (s->dyn_ltree[n].Freq != 0) - return Z_TEXT; - - /* There are no "block-listed" or "allow-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} diff --git a/deps/zlib/zconf.h b/deps/zlib/zconf.h index 5e1d68a004e..fb76ffe312a 100644 --- a/deps/zlib/zconf.h +++ b/deps/zlib/zconf.h @@ -38,6 +38,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -238,7 +241,11 @@ #endif #ifdef Z_SOLO - typedef unsigned long z_size_t; +# ifdef _WIN64 + typedef unsigned long long z_size_t; +# else + typedef unsigned long z_size_t; +# endif #else # define z_longlong long long # if defined(NO_SIZE_T) @@ -349,6 +356,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -467,11 +477,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ @@ -507,7 +524,7 @@ typedef uLong FAR uLongf; #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else -# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t diff --git a/deps/zlib/zlib.h b/deps/zlib/zlib.h index d074d8398a6..6b7244f9943 100644 --- a/deps/zlib/zlib.h +++ b/deps/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.12, March 11th, 2022 + version 1.3, August 18th, 2023 - Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.12" -#define ZLIB_VERNUM 0x12c0 +#define ZLIB_VERSION "1.3" +#define ZLIB_VERNUM 0x1300 #define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 12 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 0 #define ZLIB_VER_SUBREVISION 0 /* @@ -78,8 +78,8 @@ extern "C" { even in the case of corrupted input. */ -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); +typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); +typedef void (*free_func)(voidpf opaque, voidpf address); struct internal_state; @@ -217,7 +217,7 @@ typedef gz_header FAR *gz_headerp; /* basic functions */ -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +ZEXTERN const char * ZEXPORT zlibVersion(void); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check @@ -225,12 +225,12 @@ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); */ /* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); +ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default - allocation functions. + allocation functions. total_in, total_out, adler, and msg are initialized. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all @@ -247,7 +247,7 @@ ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); */ -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce @@ -276,7 +276,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput + which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to @@ -320,8 +320,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was @@ -360,7 +360,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); */ -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending @@ -375,7 +375,7 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateInit(z_streamp strm); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by @@ -383,7 +383,8 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates - them to use default allocation functions. + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the @@ -397,7 +398,7 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); */ -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce @@ -517,7 +518,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); */ -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending @@ -535,12 +536,12 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); */ /* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); +ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); This is another version of deflateInit with more compression options. The fields zalloc, zfree and opaque must be initialized before by the caller. @@ -607,9 +608,9 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this @@ -651,16 +652,16 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, not perform any compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); +ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up @@ -673,8 +674,8 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, stream state is inconsistent. */ -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, + z_streamp source); /* Sets the destination stream as a complete copy of the source stream. @@ -691,20 +692,20 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, destination. */ -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateReset(z_streamp strm); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been - set unchanged. + set unchanged. total_in, total_out, adler, and msg are initialized. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); +ZEXTERN int ZEXPORT deflateParams(z_streamp strm, + int level, + int strategy); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be @@ -729,7 +730,7 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be - applied to the the data compressed after deflateParams(). + applied to the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if @@ -740,11 +741,11 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, retried with more output space. */ -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); +ZEXTERN int ZEXPORT deflateTune(z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for @@ -757,8 +758,8 @@ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); +ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, + uLong sourceLen); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or @@ -772,9 +773,9 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, than Z_FINISH or Z_NO_FLUSH are used. */ -ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, - unsigned *pending, - int *bits)); +ZEXTERN int ZEXPORT deflatePending(z_streamp strm, + unsigned *pending, + int *bits); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not @@ -787,9 +788,9 @@ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, stream state was inconsistent. */ -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); +ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, + int bits, + int value); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits @@ -804,8 +805,8 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, source stream state was inconsistent. */ -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); +ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, + gz_headerp head); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called @@ -821,16 +822,17 @@ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, + int windowBits); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized @@ -883,9 +885,9 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, deferred until inflate() is called. */ -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, @@ -906,22 +908,22 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflate(). */ -ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); +ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateSync(z_streamp strm); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all @@ -940,8 +942,8 @@ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); input each time, until success or end of the input data. */ -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + z_streamp source); /* Sets the destination stream as a complete copy of the source stream. @@ -956,18 +958,19 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, destination. */ -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateReset(z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ -ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + int windowBits); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted @@ -980,9 +983,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, the windowBits parameter is invalid. */ -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); +ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the @@ -1001,7 +1004,7 @@ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, stream state was inconsistent. */ -ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +ZEXTERN long ZEXPORT inflateMark(z_streamp strm); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the @@ -1029,8 +1032,8 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); source stream state was inconsistent. */ -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); +ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + gz_headerp head); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after @@ -1070,8 +1073,8 @@ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, */ /* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); +ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized @@ -1091,13 +1094,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, the version of the header file. */ -typedef unsigned (*in_func) OF((void FAR *, - z_const unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); +typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); +typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); +ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than @@ -1165,7 +1168,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, cannot return Z_OK. */ -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); /* All memory allocated by inflateBackInit() is freed. @@ -1173,7 +1176,7 @@ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); state was inconsistent. */ -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +ZEXTERN uLong ZEXPORT zlibCompileFlags(void); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: @@ -1226,8 +1229,8 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); you need special options. */ -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size @@ -1241,9 +1244,9 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, buffer. */ -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); +ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte @@ -1257,15 +1260,15 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, Z_STREAM_ERROR if the level parameter is invalid. */ -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size @@ -1282,8 +1285,8 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, buffer with the uncompressed data up to that point. */ -ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong *sourceLen)); +ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of @@ -1302,7 +1305,7 @@ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); Open the gzip (.gz) file at path for reading and decompressing, or compressing and writing. The mode parameter is as in fopen ("rb" or "wb") @@ -1339,7 +1342,7 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); file could not be opened. */ -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); /* Associate a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has @@ -1362,7 +1365,7 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); will not detect if fd is invalid (unless fd is -1). */ -ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); /* Set the internal buffer size used by this library's functions for file to size. The default buffer size is 8192 bytes. This function must be called @@ -1378,7 +1381,7 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); too late. */ -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); /* Dynamically update the compression level and strategy for file. See the description of deflateInit2 for the meaning of these parameters. Previously @@ -1389,7 +1392,7 @@ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); or Z_MEM_ERROR if there is a memory allocation error. */ -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); /* Read and decompress up to len uncompressed bytes from file into buf. If the input file is not in gzip format, gzread copies the given number of @@ -1419,8 +1422,8 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); Z_STREAM_ERROR. */ -ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, - gzFile file)); +ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, + gzFile file); /* Read and decompress up to nitems items of size size from file into buf, otherwise operating as gzread() does. This duplicates the interface of @@ -1437,22 +1440,22 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf + multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. + file, resetting and retrying on end-of-file, when size is not 1. */ -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); +ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); /* Compress and write the len uncompressed bytes at buf to file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ -ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, - z_size_t nitems, gzFile file)); +ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, + z_size_t nitems, gzFile file); /* Compress and write nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If @@ -1465,7 +1468,7 @@ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, is returned, and the error state is set to Z_STREAM_ERROR. */ -ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); /* Convert, format, compress, and write the arguments (...) to file under control of the string format, as in fprintf. gzprintf returns the number of @@ -1480,7 +1483,7 @@ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); This can be determined using zlibCompileFlags(). */ -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); /* Compress and write the given null-terminated string s to file, excluding the terminating null character. @@ -1488,7 +1491,7 @@ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); gzputs returns the number of characters written, or -1 in case of error. */ -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); /* Read and decompress bytes from file into buf, until len-1 characters are read, or until a newline character is read and transferred to buf, or an @@ -1502,13 +1505,13 @@ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); buf are indeterminate. */ -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +ZEXTERN int ZEXPORT gzputc(gzFile file, int c); /* Compress and write c, converted to an unsigned char, into file. gzputc returns the value that was written, or -1 in case of error. */ -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +ZEXTERN int ZEXPORT gzgetc(gzFile file); /* Read and decompress one byte from file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. @@ -1517,7 +1520,7 @@ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); points to has been clobbered or not. */ -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); /* Push c back onto the stream for file to be read as the first character on the next read. At least one character of push-back is always allowed. @@ -1529,7 +1532,7 @@ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); gzseek() or gzrewind(). */ -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); /* Flush all pending output to file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function @@ -1545,8 +1548,8 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); */ /* -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); +ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, + z_off_t offset, int whence); Set the starting position to offset relative to whence for the next gzread or gzwrite on file. The offset represents a number of bytes in the @@ -1564,7 +1567,7 @@ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, would be before the current position. */ -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +ZEXTERN int ZEXPORT gzrewind(gzFile file); /* Rewind file. This function is supported only for reading. @@ -1572,7 +1575,7 @@ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); */ /* -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +ZEXTERN z_off_t ZEXPORT gztell(gzFile file); Return the starting position for the next gzread or gzwrite on file. This position represents a number of bytes in the uncompressed data stream, @@ -1583,7 +1586,7 @@ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); */ /* -ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); +ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); Return the current compressed (actual) read or write offset of file. This offset includes the count of bytes that precede the gzip stream, for example @@ -1592,7 +1595,7 @@ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); be used for a progress indicator. On error, gzoffset() returns -1. */ -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +ZEXTERN int ZEXPORT gzeof(gzFile file); /* Return true (1) if the end-of-file indicator for file has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set @@ -1607,7 +1610,7 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); has grown since the previous end of file was detected. */ -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +ZEXTERN int ZEXPORT gzdirect(gzFile file); /* Return true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. @@ -1628,7 +1631,7 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); gzip file reading and decompression, which may not be desired.) */ -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose(gzFile file); /* Flush all pending output for file, if necessary, close file and deallocate the (de)compression state. Note that once file is closed, you @@ -1641,8 +1644,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); last read ended in the middle of a gzip stream, or Z_OK on success. */ -ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); -ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_r(gzFile file); +ZEXTERN int ZEXPORT gzclose_w(gzFile file); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to @@ -1653,7 +1656,7 @@ ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); zlib library. */ -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); /* Return the error message for the last error which occurred on file. errnum is set to zlib error number. If an error occurred in the file system @@ -1669,7 +1672,7 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); functions above that do not distinguish those cases in their return values. */ -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +ZEXTERN void ZEXPORT gzclearerr(gzFile file); /* Clear the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip @@ -1686,7 +1689,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); library. */ -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. An Adler-32 value is in the range of a 32-bit @@ -1706,15 +1709,15 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ -ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); +ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, + z_size_t len); /* Same as adler32(), but with a size_t length. */ /* -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); +ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, + z_off_t len2); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for @@ -1724,7 +1727,7 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, negative, the result has no meaning or utility. */ -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. @@ -1742,14 +1745,14 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ -ZEXTERN uLong ZEXPORT crc32_z OF((uLong crc, const Bytef *buf, - z_size_t len)); +ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, + z_size_t len); /* Same as crc32(), but with a size_t length. */ /* -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); +ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were @@ -1759,13 +1762,13 @@ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); */ /* -ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2)); +ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); Return the operator corresponding to length len2, to be used with crc32_combine_op(). */ -ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); +ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); /* Give the same result as crc32_combine(), using op in place of len2. op is is generated from len2 by crc32_combine_gen(). This will be faster than @@ -1778,20 +1781,20 @@ ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); +ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, + const char *version, int stream_size); +ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size); +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) @@ -1836,7 +1839,7 @@ struct gzFile_s { unsigned char *next; z_off64_t pos; }; -ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ @@ -1853,13 +1856,13 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off64_t)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) @@ -1881,53 +1884,50 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ # define crc32_combine_gen crc32_combine_gen64 # endif # ifndef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); # endif #else - ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off64_t)); + ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif #else /* Z_SOLO */ - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif /* !Z_SOLO */ /* undocumented functions */ -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); -ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); -ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); -ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); -ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +ZEXTERN const char * ZEXPORT zError(int); +ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); +ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); +ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); +ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); +ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); #if defined(_WIN32) && !defined(Z_SOLO) -ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, - const char *mode)); +ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, + const char *mode); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO -ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, - const char *format, - va_list va)); +ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + const char *format, + va_list va); # endif #endif diff --git a/deps/zlib/zutil.c b/deps/zlib/zutil.c index dcab28a0d51..b1c5d2d3c6d 100644 --- a/deps/zlib/zutil.c +++ b/deps/zlib/zutil.c @@ -24,13 +24,11 @@ z_const char * const z_errmsg[10] = { }; -const char * ZEXPORT zlibVersion() -{ +const char * ZEXPORT zlibVersion(void) { return ZLIB_VERSION; } -uLong ZEXPORT zlibCompileFlags() -{ +uLong ZEXPORT zlibCompileFlags(void) { uLong flags; flags = 0; @@ -61,9 +59,11 @@ uLong ZEXPORT zlibCompileFlags() #ifdef ZLIB_DEBUG flags += 1 << 8; #endif + /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif + */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif @@ -119,9 +119,7 @@ uLong ZEXPORT zlibCompileFlags() # endif int ZLIB_INTERNAL z_verbose = verbose; -void ZLIB_INTERNAL z_error (m) - char *m; -{ +void ZLIB_INTERNAL z_error(char *m) { fprintf(stderr, "%s\n", m); exit(1); } @@ -130,9 +128,7 @@ void ZLIB_INTERNAL z_error (m) /* exported to allow conversion of error code to string for compress() and * uncompress() */ -const char * ZEXPORT zError(err) - int err; -{ +const char * ZEXPORT zError(int err) { return ERR_MSG(err); } @@ -146,22 +142,14 @@ const char * ZEXPORT zError(err) #ifndef HAVE_MEMCPY -void ZLIB_INTERNAL zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ +void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } -int ZLIB_INTERNAL zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ +int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { uInt j; for (j = 0; j < len; j++) { @@ -170,10 +158,7 @@ int ZLIB_INTERNAL zmemcmp(s1, s2, len) return 0; } -void ZLIB_INTERNAL zmemzero(dest, len) - Bytef* dest; - uInt len; -{ +void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ @@ -214,8 +199,7 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; @@ -240,8 +224,7 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) return buf; } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; (void)opaque; @@ -277,14 +260,12 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } @@ -297,25 +278,18 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); +extern voidp malloc(uInt size); +extern voidp calloc(uInt items, uInt size); +extern void free(voidpf ptr); #endif -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } -void ZLIB_INTERNAL zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; free(ptr); } diff --git a/deps/zlib/zutil.h b/deps/zlib/zutil.h index d9a20ae1bf4..902a304cc2d 100644 --- a/deps/zlib/zutil.h +++ b/deps/zlib/zutil.h @@ -191,8 +191,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); #endif /* common defaults */ @@ -231,16 +232,16 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define zmemzero(dest, len) memset(dest, 0, len) # endif #else - void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); + void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; - extern void ZLIB_INTERNAL z_error OF((char *m)); + extern void ZLIB_INTERNAL z_error(char *m); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} @@ -257,9 +258,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #endif #ifndef Z_SOLO - voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); - void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); + voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, + unsigned size); + void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); #endif #define ZALLOC(strm, items, size) \ From f004096fff7c00f7ff17f8232f4d2d65ba4c546f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 11:20:45 +0000 Subject: [PATCH 350/816] examples: use unsigned int for bitfields --- examples/args.h | 2 +- examples/checkout.c | 6 +++--- examples/merge.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/args.h b/examples/args.h index d626f98c8a7..4db0493bb2d 100644 --- a/examples/args.h +++ b/examples/args.h @@ -8,7 +8,7 @@ struct args_info { int argc; char **argv; int pos; - int opts_done : 1; /**< Did we see a -- separator */ + unsigned int opts_done : 1; /**< Did we see a -- separator */ }; #define ARGS_INFO_INIT { argc, argv, 0, 0 } #define ARGS_CURRENT(args) args->argv[args->pos] diff --git a/examples/checkout.c b/examples/checkout.c index ac7b7422d7b..82567cdc432 100644 --- a/examples/checkout.c +++ b/examples/checkout.c @@ -35,9 +35,9 @@ */ typedef struct { - int force : 1; - int progress : 1; - int perf : 1; + unsigned int force : 1; + unsigned int progress : 1; + unsigned int perf : 1; } checkout_options; static void print_usage(void) diff --git a/examples/merge.c b/examples/merge.c index 460c06a2567..7a76912cd24 100644 --- a/examples/merge.c +++ b/examples/merge.c @@ -30,7 +30,7 @@ struct merge_options { git_annotated_commit **annotated; size_t annotated_count; - int no_commit : 1; + unsigned int no_commit : 1; }; static void print_usage(void) From 032a8c2d5c75a3c23888a7e809e536636dfd54d5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 16:36:30 +0000 Subject: [PATCH 351/816] util: our strcmp cb should use git__strcmp --- src/util/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/util.c b/src/util/util.c index c8e8303afe1..e86bceeb5a8 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -623,12 +623,12 @@ int git__bsearch_r( */ int git__strcmp_cb(const void *a, const void *b) { - return strcmp((const char *)a, (const char *)b); + return git__strcmp((const char *)a, (const char *)b); } int git__strcasecmp_cb(const void *a, const void *b) { - return strcasecmp((const char *)a, (const char *)b); + return git__strcasecmp((const char *)a, (const char *)b); } int git__parse_bool(int *out, const char *value) From 6816f30cbecab8224e716db5d449767feb20a8b7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 13:34:25 +0000 Subject: [PATCH 352/816] Use the correct function definition for function pointers Passing a function pointer with different parameters is UB, even if those params are (void *). Use our separate `_cb` functions that will do the correct casting. --- src/libgit2/iterator.c | 14 ++++++++++---- src/libgit2/refs.c | 6 ++++++ src/libgit2/refs.h | 6 ++++++ tests/libgit2/iterator/workdir.c | 6 +++--- tests/libgit2/network/remote/rename.c | 2 +- tests/libgit2/odb/sorting.c | 7 ++++++- 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/libgit2/iterator.c b/src/libgit2/iterator.c index 95ded1046dc..bef9c609079 100644 --- a/src/libgit2/iterator.c +++ b/src/libgit2/iterator.c @@ -26,9 +26,10 @@ #define iterator__ignore_dot_git(I) iterator__flag(I,IGNORE_DOT_GIT) #define iterator__descend_symlinks(I) iterator__flag(I,DESCEND_SYMLINKS) - static void iterator_set_ignore_case(git_iterator *iter, bool ignore_case) { + int (*vector_cmp)(const void *a, const void *b); + if (ignore_case) iter->flags |= GIT_ITERATOR_IGNORE_CASE; else @@ -39,7 +40,9 @@ static void iterator_set_ignore_case(git_iterator *iter, bool ignore_case) iter->prefixcomp = ignore_case ? git__prefixcmp_icase : git__prefixcmp; iter->entry_srch = ignore_case ? git_index_entry_isrch : git_index_entry_srch; - git_vector_set_cmp(&iter->pathlist, (git_vector_cmp)iter->strcomp); + vector_cmp = ignore_case ? git__strcasecmp_cb : git__strcmp_cb; + + git_vector_set_cmp(&iter->pathlist, vector_cmp); } static int iterator_range_init( @@ -299,6 +302,7 @@ typedef enum { static iterator_pathlist_search_t iterator_pathlist_search( git_iterator *iter, const char *path, size_t path_len) { + int (*vector_cmp)(const void *a, const void *b); const char *p; size_t idx; int error; @@ -308,8 +312,10 @@ static iterator_pathlist_search_t iterator_pathlist_search( git_vector_sort(&iter->pathlist); - error = git_vector_bsearch2(&idx, &iter->pathlist, - (git_vector_cmp)iter->strcomp, path); + vector_cmp = (iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0 ? + git__strcasecmp_cb : git__strcmp_cb; + + error = git_vector_bsearch2(&idx, &iter->pathlist, vector_cmp, path); /* the given path was found in the pathlist. since the pathlist only * matches directories when they're suffixed with a '/', analyze the diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index 5e2fe97e76f..c1ed04d233a 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -1080,6 +1080,12 @@ int git_reference_cmp( return git_oid__cmp(&ref1->target.oid, &ref2->target.oid); } +int git_reference__cmp_cb(const void *a, const void *b) +{ + return git_reference_cmp( + (const git_reference *)a, (const git_reference *)b); +} + /* * Starting with the reference given by `ref_name`, follows symbolic * references until a direct reference is found and updated the OID diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index cb888bf8f49..588af82fe40 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -92,6 +92,12 @@ int git_reference__is_tag(const char *ref_name); int git_reference__is_note(const char *ref_name); const char *git_reference__shorthand(const char *name); +/* + * A `git_reference_cmp` wrapper suitable for passing to generic + * comparators, like `vector_cmp` / `tsort` / etc. + */ +int git_reference__cmp_cb(const void *a, const void *b); + /** * Lookup a reference by name and try to resolve to an OID. * diff --git a/tests/libgit2/iterator/workdir.c b/tests/libgit2/iterator/workdir.c index 7634997e1e5..af47d8b3601 100644 --- a/tests/libgit2/iterator/workdir.c +++ b/tests/libgit2/iterator/workdir.c @@ -585,9 +585,9 @@ void test_iterator_workdir__filesystem(void) expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); git_iterator_free(i); - git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp); - git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp); - git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_base, 8, git__strcasecmp_cb); + git__tsort((void **)expect_trees, 18, git__strcasecmp_cb); + git__tsort((void **)expect_noauto, 5, git__strcasecmp_cb); i_opts.flags = GIT_ITERATOR_IGNORE_CASE; cl_git_pass(git_iterator_for_filesystem(&i, "status/subdir", &i_opts)); diff --git a/tests/libgit2/network/remote/rename.c b/tests/libgit2/network/remote/rename.c index b071f9ceffe..21ea216545c 100644 --- a/tests/libgit2/network/remote/rename.c +++ b/tests/libgit2/network/remote/rename.c @@ -216,7 +216,7 @@ void test_network_remote_rename__symref_head(void) cl_assert_equal_i(0, problems.count); git_strarray_dispose(&problems); - cl_git_pass(git_vector_init(&refs, 2, (git_vector_cmp) git_reference_cmp)); + cl_git_pass(git_vector_init(&refs, 2, git_reference__cmp_cb)); cl_git_pass(git_branch_iterator_new(&iter, _repo, GIT_BRANCH_REMOTE)); while ((error = git_branch_next(&ref, &btype, iter)) == 0) { diff --git a/tests/libgit2/odb/sorting.c b/tests/libgit2/odb/sorting.c index ec4e3696ba1..3fe52e852cd 100644 --- a/tests/libgit2/odb/sorting.c +++ b/tests/libgit2/odb/sorting.c @@ -7,6 +7,11 @@ typedef struct { size_t position; } fake_backend; +static void odb_backend_free(git_odb_backend *odb) +{ + git__free(odb); +} + static git_odb_backend *new_backend(size_t position) { fake_backend *b; @@ -15,7 +20,7 @@ static git_odb_backend *new_backend(size_t position) if (b == NULL) return NULL; - b->base.free = (void (*)(git_odb_backend *)) git__free; + b->base.free = odb_backend_free; b->base.version = GIT_ODB_BACKEND_VERSION; b->position = position; return (git_odb_backend *)b; From 01d2adcb605e10e9fdc803a4c683c315f67566f1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 16:12:35 +0000 Subject: [PATCH 353/816] remote: pass the commit not its id in tests `git_commit_create_v` takes _commits_ not _commit ids_. Fix the test to call the API correctly. --- tests/libgit2/remote/fetch.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/libgit2/remote/fetch.c b/tests/libgit2/remote/fetch.c index 85e99206fdc..a5d3272c56b 100644 --- a/tests/libgit2/remote/fetch.c +++ b/tests/libgit2/remote/fetch.c @@ -75,6 +75,7 @@ static void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, /* create two commits in repo 1 and a reference to them */ { git_oid empty_tree_id; + git_commit *commit1; git_tree *empty_tree; git_signature *sig; git_treebuilder *tb; @@ -84,10 +85,12 @@ static void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, cl_git_pass(git_signature_default(&sig, repo1)); cl_git_pass(git_commit_create(commit1id, repo1, REPO1_REFNAME, sig, sig, NULL, "one", empty_tree, 0, NULL)); + cl_git_pass(git_commit_lookup(&commit1, repo1, commit1id)); cl_git_pass(git_commit_create_v(commit2id, repo1, REPO1_REFNAME, sig, - sig, NULL, "two", empty_tree, 1, commit1id)); + sig, NULL, "two", empty_tree, 1, commit1)); git_tree_free(empty_tree); + git_commit_free(commit1); git_signature_free(sig); git_treebuilder_free(tb); } From a80c52693545f7bcf6d4ad3ef189e08aa76ce27d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 21 Dec 2023 13:27:27 +0000 Subject: [PATCH 354/816] diff: move non-blob handling out of is_target --- src/libgit2/diff_tform.c | 41 ++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/libgit2/diff_tform.c b/src/libgit2/diff_tform.c index a90ab07c9b9..9fa3cef8358 100644 --- a/src/libgit2/diff_tform.c +++ b/src/libgit2/diff_tform.c @@ -653,6 +653,23 @@ static int calc_self_similarity( return 0; } +static void handle_non_blob( + git_diff *diff, + const git_diff_find_options *opts, + size_t delta_idx) +{ + git_diff_delta *delta = GIT_VECTOR_GET(&diff->deltas, delta_idx); + + /* skip things that are blobs */ + if (GIT_MODE_ISBLOB(delta->old_file.mode)) + return; + + /* honor "remove unmodified" flag for non-blobs (eg submodules) */ + if (delta->status == GIT_DELTA_UNMODIFIED && + FLAG_SET(opts, GIT_DIFF_FIND_REMOVE_UNMODIFIED)) + delta->flags |= GIT_DIFF_FLAG__TO_DELETE; +} + static bool is_rename_target( git_diff *diff, const git_diff_find_options *opts, @@ -718,15 +735,8 @@ static bool is_rename_source( git_diff_delta *delta = GIT_VECTOR_GET(&diff->deltas, delta_idx); /* skip things that aren't blobs */ - if (!GIT_MODE_ISBLOB(delta->old_file.mode)) { - - /* but still honor "remove unmodified" flag */ - if (delta->status == GIT_DELTA_UNMODIFIED && - FLAG_SET(opts, GIT_DIFF_FIND_REMOVE_UNMODIFIED)) - delta->flags |= GIT_DIFF_FLAG__TO_DELETE; - + if (!GIT_MODE_ISBLOB(delta->old_file.mode)) return false; - } switch (delta->status) { case GIT_DELTA_ADDED: @@ -817,7 +827,8 @@ int git_diff_find_similar( git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; size_t num_deltas, num_srcs = 0, num_tgts = 0; size_t tried_srcs = 0, tried_tgts = 0; - size_t num_rewrites = 0, num_updates = 0, num_bumped = 0, num_to_delete = 0; + size_t num_rewrites = 0, num_updates = 0, num_bumped = 0, + num_to_delete = 0; size_t sigcache_size; void **sigcache = NULL; /* cache of similarity metric file signatures */ diff_find_match *tgt2src = NULL; @@ -851,6 +862,8 @@ int git_diff_find_similar( * mark them for splitting if break-rewrites is enabled */ git_vector_foreach(&diff->deltas, t, tgt) { + handle_non_blob(diff, &opts, t); + if (is_rename_source(diff, &opts, t, sigcache)) ++num_srcs; @@ -861,7 +874,7 @@ int git_diff_find_similar( num_rewrites++; if ((tgt->flags & GIT_DIFF_FLAG__TO_DELETE) != 0) - num_to_delete++; + num_to_delete++; } /* If there are no candidate srcs or tgts, no need to find matches */ @@ -1108,11 +1121,15 @@ int git_diff_find_similar( * Actually split and delete entries as needed */ - if (num_rewrites > 0 || num_updates > 0 || num_to_delete > 0) + if (num_rewrites > 0 || num_updates > 0 || num_to_delete > 0) { + size_t apply_len = diff->deltas.length - + num_rewrites - num_to_delete; + error = apply_splits_and_deletes( - diff, diff->deltas.length - num_rewrites - num_to_delete, + diff, apply_len, FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES) && !FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY)); + } cleanup: git__free(tgt2src); From 52daefc6f34b52820df2191e79c1dfb43e826b2f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 22:19:54 +0000 Subject: [PATCH 355/816] httpclient: clear client->parser.data after use Some static code analysis complains that we're putting a stack variable into client->parser.data (which persists past the function calls). Clear that on function exit to avoid confusion. --- src/libgit2/transports/httpclient.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index 278d7c8e0ab..e22a07ba1a0 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -1252,6 +1252,7 @@ static void complete_response_body(git_http_client *client) } done: + client->parser.data = NULL; git_str_clear(&client->read_buf); } @@ -1441,6 +1442,7 @@ int git_http_client_read_response( done: git_str_dispose(&parser_context.parse_header_name); git_str_dispose(&parser_context.parse_header_value); + client->parser.data = NULL; return error; } @@ -1496,6 +1498,8 @@ int git_http_client_read_body( if (error < 0) client->connected = 0; + client->parser.data = NULL; + return error; } @@ -1530,6 +1534,8 @@ int git_http_client_skip_body(git_http_client *client) if (error < 0) client->connected = 0; + client->parser.data = NULL; + return error; } From 66f587b5260a9e28a36d40696171e16afd15d652 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 21:50:13 +0000 Subject: [PATCH 356/816] ntlmclient: update to latest upstream ntlmclient --- deps/ntlmclient/unicode_builtin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/ntlmclient/unicode_builtin.c b/deps/ntlmclient/unicode_builtin.c index e2ee0abf71e..6d398b7c9f8 100644 --- a/deps/ntlmclient/unicode_builtin.c +++ b/deps/ntlmclient/unicode_builtin.c @@ -372,13 +372,13 @@ static inline bool unicode_builtin_encoding_convert( goto done; } + out_len = out_start - out; + if ((new_out = realloc(out, out_size)) == NULL) { ntlm_client_set_errmsg(ntlm, "out of memory"); goto done; } - out_len = out_start - out; - out = new_out; out_start = new_out + out_len; out_end = out + out_size; From edeec76a29912b3fdcd566ebc422fd47b32386c7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 21 Dec 2023 17:00:52 +0000 Subject: [PATCH 357/816] ci: update all images to use libssh2 v1.11.0 --- ci/docker/centos7 | 6 +++--- ci/docker/centos8 | 6 +++--- ci/docker/focal | 2 +- ci/docker/xenial | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ci/docker/centos7 b/ci/docker/centos7 index 28ed650811c..45c299d10bb 100644 --- a/ci/docker/centos7 +++ b/ci/docker/centos7 @@ -18,13 +18,13 @@ RUN yum install -y \ FROM yum AS libssh2 RUN cd /tmp && \ - curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.0.tar.gz | tar -xz && \ - cd libssh2-1.8.0 && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ ./configure && \ make && \ make install && \ cd .. && \ - rm -rf libssh-1.8.0 + rm -rf libssh-1.11.0 FROM libssh2 AS valgrind RUN cd /tmp && \ diff --git a/ci/docker/centos8 b/ci/docker/centos8 index 81f0c3c7698..c2ac5f07af3 100644 --- a/ci/docker/centos8 +++ b/ci/docker/centos8 @@ -24,13 +24,13 @@ RUN yum install -y \ FROM yum AS libssh2 RUN cd /tmp && \ - curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.0.tar.gz | tar -xz && \ - cd libssh2-1.8.0 && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ ./configure && \ make && \ make install && \ cd .. && \ - rm -rf libssh2-1.8.0 + rm -rf libssh2-1.11.0 FROM libssh2 AS valgrind RUN cd /tmp && \ diff --git a/ci/docker/focal b/ci/docker/focal index b3a402cb011..62f5b6301ae 100644 --- a/ci/docker/focal +++ b/ci/docker/focal @@ -53,7 +53,7 @@ RUN cd /tmp && \ cd libssh2-1.9.0 && \ mkdir build build-msan && \ cd build && \ - CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ ninja install && \ cd ../build-msan && \ CC=clang-10 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ diff --git a/ci/docker/xenial b/ci/docker/xenial index 578f0a962a9..793df4bda50 100644 --- a/ci/docker/xenial +++ b/ci/docker/xenial @@ -53,12 +53,12 @@ RUN cd /tmp && \ FROM mbedtls AS libssh2 RUN cd /tmp && \ - curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | tar -xz && \ - cd libssh2-1.8.2 && \ - CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt . && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON . && \ ninja install && \ cd .. && \ - rm -rf libssh2-1.8.2 + rm -rf libssh2-1.11.0 FROM libssh2 AS valgrind RUN cd /tmp && \ From 4da4bea79f5a0bb1c77b6670af8400b9bf9708a9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 10:21:27 +0000 Subject: [PATCH 358/816] ci: add an Ubuntu Noble dockerfile --- ci/docker/noble | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 ci/docker/noble diff --git a/ci/docker/noble b/ci/docker/noble new file mode 100644 index 00000000000..05cd2768fe4 --- /dev/null +++ b/ci/docker/noble @@ -0,0 +1,88 @@ +ARG BASE=ubuntu:noble + +FROM ${BASE} AS apt +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + bzip2 \ + clang \ + cmake \ + curl \ + gcc \ + git \ + krb5-user \ + libclang-rt-17-dev \ + libcurl4-gnutls-dev \ + libgcrypt20-dev \ + libkrb5-dev \ + libpcre3-dev \ + libssl-dev \ + libz-dev \ + llvm-17 \ + make \ + ninja-build \ + openjdk-8-jre-headless \ + openssh-server \ + openssl \ + pkgconf \ + python3 \ + sudo \ + valgrind \ + && \ + rm -rf /var/lib/apt/lists/* && \ + mkdir /usr/local/msan + +FROM apt AS mbedtls +RUN cd /tmp && \ + curl --location --silent --show-error https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-2.28.6.tar.gz | \ + tar -xz && \ + cd mbedtls-mbedtls-2.28.6 && \ + scripts/config.pl unset MBEDTLS_AESNI_C && \ + scripts/config.pl set MBEDTLS_MD4_C 1 && \ + mkdir build build-msan && \ + cd build && \ + CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + ninja install && \ + cd ../build-msan && \ + CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ + ninja install && \ + cd .. && \ + rm -rf mbedtls-mbedtls-2.28.6 + +FROM mbedtls AS libssh2 +RUN cd /tmp && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + mkdir build build-msan && \ + cd build && \ + CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + ninja install && \ + cd ../build-msan && \ + CC=clang-17 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ + ninja install && \ + cd .. && \ + rm -rf libssh2-1.11.0 + +FROM libssh2 AS valgrind +RUN cd /tmp && \ + curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.22.0.tar.bz2 | \ + tar -xj && \ + cd valgrind-3.22.0 && \ + CC=clang-17 ./configure && \ + make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \ + make install && \ + cd .. && \ + rm -rf valgrind-3.22.0 + +FROM valgrind AS adduser +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 + +FROM adduser AS ldconfig +RUN ldconfig + +FROM ldconfig AS configure +RUN mkdir /var/run/sshd From 8329f7ace3523df1eb070a3d2690ef1f6e031f41 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Dec 2023 10:23:35 +0000 Subject: [PATCH 359/816] ci: upgrade focal builds to noble Let's use the latest & greatest for building our sanitizer / fuzzing builds. --- .github/workflows/main.yml | 40 +++++++++++++++--------------- .github/workflows/nightly.yml | 46 +++++++++++++++++------------------ 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3aa214cd397..e045bb436f2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,42 +30,42 @@ jobs: matrix: platform: # All builds: core platforms - - name: "Linux (Xenial, GCC, OpenSSL, libssh2)" - id: xenial-gcc-openssl + - name: "Linux (Noble, GCC, OpenSSL, libssh2)" + id: noble-gcc-openssl os: ubuntu-latest container: - name: xenial + name: noble env: CC: gcc CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - - name: Linux (Xenial, GCC, mbedTLS, OpenSSH) - id: xenial-gcc-mbedtls + - name: "Linux (Noble, Clang, mbedTLS, OpenSSH)" + id: noble-clang-mbedtls os: ubuntu-latest container: - name: xenial + name: noble env: - CC: gcc + CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec - - name: "Linux (Xenial, Clang, OpenSSL, OpenSSH)" - id: xenial-clang-openssl + - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" + id: xenial-gcc-openssl os: ubuntu-latest container: name: xenial env: - CC: clang + CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" - id: xenial-clang-mbedtls + id: xenial-gcc-mbedtls os: ubuntu-latest container: name: xenial env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - name: "macOS" id: macos os: macos-12 @@ -130,9 +130,9 @@ jobs: - name: "Sanitizer (Memory)" id: sanitizer-memory container: - name: focal + name: noble env: - CC: clang-10 + CC: clang CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -145,9 +145,9 @@ jobs: id: sanitizer-ub os: ubuntu-latest container: - name: focal + name: noble env: - CC: clang-10 + CC: clang CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -159,9 +159,9 @@ jobs: id: sanitizer-thread os: ubuntu-latest container: - name: focal + name: noble env: - CC: clang-10 + CC: clang CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index aca4506b26b..776b58b12db 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -27,42 +27,42 @@ jobs: matrix: platform: # All builds: core platforms - - name: "Linux (Xenial, GCC, OpenSSL, libssh2)" - id: xenial-gcc-openssl + - name: "Linux (Noble, GCC, OpenSSL, libssh2)" + id: noble-gcc-openssl os: ubuntu-latest container: - name: xenial + name: noble env: CC: gcc CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - - name: Linux (Xenial, GCC, mbedTLS, OpenSSH) - id: xenial-gcc-mbedtls + - name: "Linux (Noble, Clang, mbedTLS, OpenSSH)" + id: noble-clang-mbedtls os: ubuntu-latest container: - name: xenial + name: noble env: - CC: gcc + CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec - - name: "Linux (Xenial, Clang, OpenSSL, OpenSSH)" - id: xenial-clang-openssl + - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" + id: xenial-gcc-openssl os: ubuntu-latest container: name: xenial env: - CC: clang + CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" - id: xenial-clang-mbedtls + id: xenial-gcc-mbedtls os: ubuntu-latest container: name: xenial env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - name: "macOS" id: macos os: macos-12 @@ -127,9 +127,9 @@ jobs: - name: "Sanitizer (Memory)" id: memorysanitizer container: - name: focal + name: noble env: - CC: clang-10 + CC: clang-17 CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -142,9 +142,9 @@ jobs: id: ubsanitizer os: ubuntu-latest container: - name: focal + name: noble env: - CC: clang-10 + CC: clang-17 CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -156,9 +156,9 @@ jobs: id: threadsanitizer os: ubuntu-latest container: - name: focal + name: noble env: - CC: clang-10 + CC: clang-17 CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -277,12 +277,12 @@ jobs: CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja - name: "Linux (no mmap)" - id: focal-nommap + id: noble-nommap os: ubuntu-latest container: - name: focal + name: noble env: - CC: clang-10 + CC: gcc CFLAGS: -DNO_MMAP CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local CMAKE_GENERATOR: Ninja From 383e5ed5812ed5f0069fa0ca92b429f675560e55 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 21 Dec 2023 16:30:10 +0000 Subject: [PATCH 360/816] ci: use ecdsa keys for ssh Using modern rsa (sha2-256 or sha2-512) with libssh2 is complicated and depends on numerous factors for support. Just use ecdsa, which is supported by both libssh2 v1.11.0 and modern OpenSSH (which we use for our server in CI). --- ci/test.sh | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index 56cb78ce7d5..e55c6261f27 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -25,6 +25,8 @@ CTEST=$(which ctest) TMPDIR=${TMPDIR:-/tmp} USER=${USER:-$(whoami)} +GITTEST_SSH_KEYTYPE=${GITTEST_SSH_KEYTYPE:="ecdsa"} + HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX` export CLAR_HOMEDIR=${HOME} @@ -207,7 +209,7 @@ if should_run "SSH_TESTS"; then Port 2222 ListenAddress 0.0.0.0 Protocol 2 - HostKey ${SSHD_DIR}/id_rsa + HostKey ${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE} PidFile ${SSHD_DIR}/pid AuthorizedKeysFile ${HOME}/.ssh/authorized_keys LogLevel DEBUG @@ -216,21 +218,21 @@ if should_run "SSH_TESTS"; then PubkeyAuthentication yes ChallengeResponseAuthentication no StrictModes no - HostCertificate ${SSHD_DIR}/id_rsa.pub - HostKey ${SSHD_DIR}/id_rsa + HostCertificate ${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE}.pub + HostKey ${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE} # Required here as sshd will simply close connection otherwise UsePAM no EOF - ssh-keygen -t rsa -f "${SSHD_DIR}/id_rsa" -N "" -q + ssh-keygen -t "${GITTEST_SSH_KEYTYPE}" -f "${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE}" -N "" -q /usr/sbin/sshd -f "${SSHD_DIR}/sshd_config" -E "${SSHD_DIR}/log" # Set up keys mkdir "${HOME}/.ssh" - ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa" -N "" -q - cat "${HOME}/.ssh/id_rsa.pub" >>"${HOME}/.ssh/authorized_keys" + ssh-keygen -t "${GITTEST_SSH_KEYTYPE}" -f "${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}" -N "" -q + cat "${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}.pub" >>"${HOME}/.ssh/authorized_keys" while read algorithm key comment; do echo "[localhost]:2222 $algorithm $key" >>"${HOME}/.ssh/known_hosts" - done <"${SSHD_DIR}/id_rsa.pub" + done <"${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE}.pub" # Append the github.com keys for the tests that don't override checks. # We ask for ssh-rsa to test that the selection based off of known_hosts @@ -428,12 +430,12 @@ fi if should_run "SSH_TESTS"; then export GITTEST_REMOTE_USER=$USER - export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_rsa" - export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_rsa.pub" + export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}" + export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}.pub" export GITTEST_REMOTE_SSH_PASSPHRASE="" export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}" - export GITTEST_SSH_CMD="ssh -i ${HOME}/.ssh/id_rsa -o UserKnownHostsFile=${HOME}/.ssh/known_hosts" + export GITTEST_SSH_CMD="ssh -i ${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE} -o UserKnownHostsFile=${HOME}/.ssh/known_hosts" echo "" echo "Running ssh tests" From e2027c006b44c9c4bcbf885b57189aacdf582608 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 23 Dec 2023 13:43:48 +0000 Subject: [PATCH 361/816] ci: add noble to build-container matrix --- .github/workflows/build-containers.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 767798bf6d0..56ac66a9016 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -24,6 +24,7 @@ jobs: - name: xenial - name: bionic - name: focal + - name: noble - name: docurium - name: bionic-x86 dockerfile: bionic From 0572884693c00ea73c6e79057b3ca8ae8bd55531 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 22 Dec 2023 23:17:29 +0000 Subject: [PATCH 362/816] commit: introduce `git_repository_commit_parents` Emulating `git commit` is clunky - identifying your commit's parents is part of the problem. Provide a helper to give you the parents given the current repository state. --- include/git2/commit.h | 18 +++++++++++ include/git2/repository.h | 12 +++++++ src/libgit2/commit.c | 15 +++++++++ src/libgit2/repository.c | 62 ++++++++++++++++++++++++++++++++++++ tests/libgit2/repo/getters.c | 60 ++++++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+) diff --git a/include/git2/commit.h b/include/git2/commit.h index 67170cb9c83..e3e5d723624 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -541,6 +541,24 @@ typedef int (*git_commit_create_cb)( const git_commit *parents[], void *payload); +/** An array of commits returned from the library */ +typedef struct git_commitarray { + git_commit **commits; + size_t count; +} git_commitarray; + +/** + * Free the commits contained in a commit array. This method should + * be called on `git_commitarray` objects that were provided by the + * library. Not doing so will result in a memory leak. + * + * This does not free the `git_commitarray` itself, since the library + * will never allocate that object directly itself. + * + * @param array The git_commitarray that contains commits to free + */ +GIT_EXTERN(void) git_commitarray_dispose(git_commitarray *array); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/repository.h b/include/git2/repository.h index 6ec2ac8220c..0ff0856510f 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -11,6 +11,7 @@ #include "types.h" #include "oid.h" #include "buffer.h" +#include "commit.h" /** * @file git2/repository.h @@ -978,6 +979,17 @@ GIT_EXTERN(int) git_repository_set_ident(git_repository *repo, const char *name, */ GIT_EXTERN(git_oid_t) git_repository_oid_type(git_repository *repo); +/** + * Gets the parents of the next commit, given the current repository state. + * Generally, this is the HEAD commit, except when performing a merge, in + * which case it is two or more commits. + * + * @param commits a `git_commitarray` that will contain the commit parents + * @param repo the repository + * @return 0 or an error code + */ +GIT_EXTERN(int) git_repository_commit_parents(git_commitarray *commits, git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index f7be73acf3f..b2c335e81b6 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -1097,3 +1097,18 @@ int git_commit_author_with_mailmap( { return git_mailmap_resolve_signature(out, mailmap, commit->author); } + +void git_commitarray_dispose(git_commitarray *array) +{ + size_t i; + + if (array == NULL) + return; + + for (i = 0; i < array->count; i++) + git_commit_free(array->commits[i]); + + git__free(array->commits); + + memset(array, 0, sizeof(*array)); +} diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 0b76e0464a6..c11fef403fc 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3874,3 +3874,65 @@ git_oid_t git_repository_oid_type(git_repository *repo) { return repo ? repo->oid_type : 0; } + +struct mergehead_data { + git_repository *repo; + git_vector *parents; +}; + +static int insert_mergehead(const git_oid *oid, void *payload) +{ + git_commit *commit; + struct mergehead_data *data = (struct mergehead_data *)payload; + + if (git_commit_lookup(&commit, data->repo, oid) < 0) + return -1; + + return git_vector_insert(data->parents, commit); +} + +int git_repository_commit_parents(git_commitarray *out, git_repository *repo) +{ + git_commit *first_parent = NULL, *commit; + git_reference *head_ref = NULL; + git_vector parents = GIT_VECTOR_INIT; + struct mergehead_data data; + size_t i; + int error; + + GIT_ASSERT_ARG(out && repo); + + out->count = 0; + out->commits = NULL; + + error = git_revparse_ext((git_object **)&first_parent, &head_ref, repo, "HEAD"); + + if (error != 0) { + if (error == GIT_ENOTFOUND) + error = 0; + + goto done; + } + + if ((error = git_vector_insert(&parents, first_parent)) < 0) + goto done; + + data.repo = repo; + data.parents = &parents; + + error = git_repository_mergehead_foreach(repo, insert_mergehead, &data); + + if (error == GIT_ENOTFOUND) + error = 0; + else if (error != 0) + goto done; + + out->commits = (git_commit **)git_vector_detach(&out->count, NULL, &parents); + +done: + git_vector_foreach(&parents, i, commit) + git__free(commit); + + git_reference_free(head_ref); + return error; +} diff --git a/tests/libgit2/repo/getters.c b/tests/libgit2/repo/getters.c index d401bb8327f..8e21d35b512 100644 --- a/tests/libgit2/repo/getters.c +++ b/tests/libgit2/repo/getters.c @@ -51,3 +51,63 @@ void test_repo_getters__retrieving_the_odb_honors_the_refcount(void) git_odb_free(odb); } + +void test_repo_getters__commit_parents(void) +{ + git_repository *repo; + git_commitarray parents; + git_oid first_parent; + git_oid merge_parents[4]; + + git_oid__fromstr(&first_parent, "099fabac3a9ea935598528c27f866e34089c2eff", GIT_OID_SHA1); + + /* A commit on a new repository has no parents */ + + cl_git_pass(git_repository_init(&repo, "new_repo", false)); + cl_git_pass(git_repository_commit_parents(&parents, repo)); + + cl_assert_equal_sz(0, parents.count); + cl_assert_equal_p(NULL, parents.commits); + + git_commitarray_dispose(&parents); + git_repository_free(repo); + + /* A standard commit has one parent */ + + repo = cl_git_sandbox_init("testrepo"); + cl_git_pass(git_repository_commit_parents(&parents, repo)); + + cl_assert_equal_sz(1, parents.count); + cl_assert_equal_oid(&first_parent, git_commit_id(parents.commits[0])); + + git_commitarray_dispose(&parents); + + /* A merge commit has multiple parents */ + + cl_git_rewritefile("testrepo/.git/MERGE_HEAD", + "8496071c1b46c854b31185ea97743be6a8774479\n" + "5b5b025afb0b4c913b4c338a42934a3863bf3644\n" + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045\n" + "9fd738e8f7967c078dceed8190330fc8648ee56a\n"); + + cl_git_pass(git_repository_commit_parents(&parents, repo)); + + cl_assert_equal_sz(5, parents.count); + + cl_assert_equal_oid(&first_parent, git_commit_id(parents.commits[0])); + + git_oid__fromstr(&merge_parents[0], "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1); + cl_assert_equal_oid(&merge_parents[0], git_commit_id(parents.commits[1])); + git_oid__fromstr(&merge_parents[1], "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); + cl_assert_equal_oid(&merge_parents[1], git_commit_id(parents.commits[2])); + git_oid__fromstr(&merge_parents[2], "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1); + cl_assert_equal_oid(&merge_parents[2], git_commit_id(parents.commits[3])); + git_oid__fromstr(&merge_parents[3], "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1); + cl_assert_equal_oid(&merge_parents[3], git_commit_id(parents.commits[4])); + + git_commitarray_dispose(&parents); + + git_repository_free(repo); + + cl_fixture_cleanup("testrepo"); +} From 98075baed20d7688147bf49d7a6ecfc565e3eb69 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 23 Dec 2023 15:30:31 +0000 Subject: [PATCH 363/816] fixup! commit: introduce `git_repository_commit_parents` --- include/git2/commit.h | 2 +- src/libgit2/commit.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/commit.h b/include/git2/commit.h index e3e5d723624..8841aa033f3 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -543,7 +543,7 @@ typedef int (*git_commit_create_cb)( /** An array of commits returned from the library */ typedef struct git_commitarray { - git_commit **commits; + git_commit *const *commits; size_t count; } git_commitarray; diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index b2c335e81b6..2e30c1be9b0 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -1108,7 +1108,7 @@ void git_commitarray_dispose(git_commitarray *array) for (i = 0; i < array->count; i++) git_commit_free(array->commits[i]); - git__free(array->commits); + git__free((git_commit **)array->commits); memset(array, 0, sizeof(*array)); } From 0589ba6cccbf05aeaa3d7ce8253ca939799d0da0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 10 Jan 2024 01:29:04 +0000 Subject: [PATCH 364/816] ci: use newest libssh2 in bionic builds --- ci/docker/bionic | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ci/docker/bionic b/ci/docker/bionic index f1b69edefeb..f42c6d2aa0b 100644 --- a/ci/docker/bionic +++ b/ci/docker/bionic @@ -12,7 +12,6 @@ RUN apt-get update && \ libcurl4-openssl-dev \ libkrb5-dev \ libpcre3-dev \ - libssh2-1-dev \ libssl-dev \ libz-dev \ ninja-build \ @@ -37,7 +36,16 @@ RUN cd /tmp && \ cd .. && \ rm -rf mbedtls-mbedtls-2.16.2 -FROM mbedtls AS adduser +FROM mbedtls AS libssh2 +RUN cd /tmp && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON . && \ + ninja install && \ + cd .. && \ + rm -rf libssh2-1.11.0 + +FROM libssh2 AS adduser ARG UID="" ARG GID="" RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ From 235f8e222d1d71f32b804dc56f3956337d846dda Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 23 Dec 2023 14:27:59 +0000 Subject: [PATCH 365/816] ci: update nightlies There's been drift in our nightly builds vs our main builds. Unfortunately, sharing steps remains clunky with our matrix-heavy setup. So this remains copy-pasta. --- .github/workflows/nightly.yml | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 776b58b12db..0474df7bbad 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -364,7 +364,11 @@ jobs: working-directory: ${{ env.docker-config-path }} if: matrix.platform.container.name != '' - name: Create container - run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ env.dockerfile }} . + run: | + if [ "${{ matrix.container.base }}" != "" ]; then + BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" + fi + docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . working-directory: ${{ env.docker-config-path }} if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - name: Prepare build @@ -372,15 +376,36 @@ jobs: - name: Build uses: ./source/.github/actions/run-build with: - command: cd build && ../source/ci/build.sh + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/build.sh container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} - name: Test uses: ./source/.github/actions/run-build with: - command: cd build && ../source/ci/test.sh + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/test.sh container: ${{ matrix.platform.container.name }} container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Upload test results + uses: actions/upload-artifact@v3 + if: success() || failure() + with: + name: test-results-${{ matrix.platform.id }} + path: build/results_*.xml + + test_results: + name: Test results + needs: [ build ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Download test results + uses: actions/download-artifact@v3 + - name: Generate test summary + uses: test-summary/action@v2 + with: + paths: 'test-results-*/*.xml' coverity: # Only run scheduled workflows on the main repository; prevents people From ee1d9a065a15981ec68d5b10a4fb7d7a22d1635b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 23 Dec 2023 14:55:35 +0000 Subject: [PATCH 366/816] ci: actually push new build containers When we update the build container, actually do a push. Remove the broken build-containers.yml step and just do it in the workflow. --- .github/workflows/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e045bb436f2..a5d10b708eb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,14 +18,10 @@ permissions: packages: write jobs: - containers: - uses: ./.github/workflows/build-containers.yml - # Run our CI/CD builds. We build a matrix with the various build targets # and their details. Then we build either in a docker container (Linux) # or on the actual hosts (macOS, Windows). build: - needs: [ containers ] strategy: matrix: platform: @@ -232,6 +228,11 @@ jobs: BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" fi docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . + docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} + if [ "${{ github.event_name }}" != "pull_request" ]; then + docker push ${{ env.docker-registry-container-sha }} + docker push ${{ env.docker-registry-container-latest }} + fi working-directory: ${{ env.docker-config-path }} if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - name: Prepare build @@ -278,7 +279,6 @@ jobs: # published to our documentation site. documentation: name: Generate documentation - needs: [ containers ] if: success() || failure() runs-on: ubuntu-latest steps: From d15be592db7bb9a52d5b287bd3af99b49a1ac258 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 23 Dec 2023 15:20:47 +0000 Subject: [PATCH 367/816] ci: move docker container creation to an action --- .../download-or-build-container/action.yml | 109 ++++++++++++++++++ .github/workflows/main.yml | 38 +++--- .github/workflows/nightly.yml | 40 +++---- ci/getcontainer.sh | 55 --------- 4 files changed, 143 insertions(+), 99 deletions(-) create mode 100644 .github/actions/download-or-build-container/action.yml delete mode 100755 ci/getcontainer.sh diff --git a/.github/actions/download-or-build-container/action.yml b/.github/actions/download-or-build-container/action.yml new file mode 100644 index 00000000000..9c83a9836c3 --- /dev/null +++ b/.github/actions/download-or-build-container/action.yml @@ -0,0 +1,109 @@ +# Run a build step in a container or directly on the Actions runner +name: Download or Build Container +description: Download a container from the package registry, or build it if it's not found + +inputs: + container: + description: Container name + type: string + required: true + dockerfile: + description: Dockerfile + type: string + base: + description: Container base + type: string + registry: + description: Docker registry to read and publish to + type: string + default: ghcr.io + config-path: + description: Path to Dockerfiles + type: string + github_token: + description: GitHub Token + type: string + +runs: + using: 'composite' + steps: + - name: Download container + run: | + IMAGE_NAME="${{ inputs.container }}" + DOCKERFILE_PATH="${{ inputs.dockerfile }}" + DOCKER_REGISTRY="${{ inputs.registry }}" + DOCKERFILE_ROOT="${{ inputs.config-path }}" + + if [ "${DOCKERFILE_PATH}" = "" ]; then + DOCKERFILE_PATH="${DOCKERFILE_ROOT}/${IMAGE_NAME}" + else + DOCKERFILE_PATH="${DOCKERFILE_ROOT}/${DOCKERFILE_PATH}" + fi + + GIT_WORKTREE=$(cd "${GITHUB_ACTION_PATH}" && git rev-parse --show-toplevel) + echo "::: git worktree is ${GIT_WORKTREE}" + cd "${GIT_WORKTREE}" + + DOCKER_CONTAINER="${GITHUB_REPOSITORY}/${IMAGE_NAME}" + DOCKER_REGISTRY_CONTAINER="${DOCKER_REGISTRY}/${DOCKER_CONTAINER}" + + echo "dockerfile=${DOCKERFILE_PATH}" >> $GITHUB_ENV + echo "docker-container=${DOCKER_CONTAINER}" >> $GITHUB_ENV + echo "docker-registry-container=${DOCKER_REGISTRY_CONTAINER}" >> $GITHUB_ENV + + # Identify the last git commit that touched the Dockerfiles + # Use this as a hash to identify the resulting docker containers + echo "::: dockerfile path is ${DOCKERFILE_PATH}" + + DOCKER_SHA=$(git log -1 --pretty=format:"%h" -- "${DOCKERFILE_PATH}") + echo "docker-sha=${DOCKER_SHA}" >> $GITHUB_ENV + + echo "::: docker sha is ${DOCKER_SHA}" + + DOCKER_REGISTRY_CONTAINER_SHA="${DOCKER_REGISTRY_CONTAINER}:${DOCKER_SHA}" + + echo "docker-registry-container-sha=${DOCKER_REGISTRY_CONTAINER_SHA}" >> $GITHUB_ENV + echo "docker-registry-container-latest=${DOCKER_REGISTRY_CONTAINER}:latest" >> $GITHUB_ENV + + echo "::: logging in to ${DOCKER_REGISTRY} as ${GITHUB_ACTOR}" + + exists="true" + docker login https://${DOCKER_REGISTRY} -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN} || exists="false" + + echo "::: pulling ${DOCKER_REGISTRY_CONTAINER_SHA}" + + if [ "${exists}" != "false" ]; then + docker pull ${DOCKER_REGISTRY_CONTAINER_SHA} || exists="false" + fi + + if [ "${exists}" = "true" ]; then + echo "::: docker container exists in registry" + echo "docker-container-exists=true" >> $GITHUB_ENV + else + echo "::: docker container does not exist in registry" + echo "docker-container-exists=false" >> $GITHUB_ENV + fi + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + - name: Create container + run: | + if [ "${{ inputs.base }}" != "" ]; then + BASE_ARG="--build-arg BASE=${{ inputs.base }}" + fi + + GIT_WORKTREE=$(cd "${GITHUB_ACTION_PATH}" && git rev-parse --show-toplevel) + echo "::: git worktree is ${GIT_WORKTREE}" + cd "${GIT_WORKTREE}" + + docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . + docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} + shell: bash + working-directory: source/${{ inputs.config-path }} + if: env.docker-container-exists != 'true' + - name: Publish container + run: | + docker push ${{ env.docker-registry-container-sha }} + docker push ${{ env.docker-registry-container-latest }} + shell: bash + if: env.docker-container-exists != 'true' && github.event_name != 'pull_request' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a5d10b708eb..f6a087b89b2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ on: env: docker-registry: ghcr.io - docker-config-path: source/ci/docker + docker-config-path: ci/docker permissions: contents: write @@ -214,27 +214,15 @@ jobs: - name: Setup QEMU run: docker run --rm --privileged multiarch/qemu-user-static:register --reset if: matrix.platform.container.qemu == true - - name: Download container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.platform.container.name }}" "${{ matrix.platform.container.dockerfile }}" - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: ${{ matrix.platform.container.name }} + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} if: matrix.platform.container.name != '' - - name: Create container - run: | - if [ "${{ matrix.container.base }}" != "" ]; then - BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" - fi - docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . - docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} - if [ "${{ github.event_name }}" != "pull_request" ]; then - docker push ${{ env.docker-registry-container-sha }} - docker push ${{ env.docker-registry-container-latest }} - fi - working-directory: ${{ env.docker-config-path }} - if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - name: Prepare build run: mkdir build - name: Build @@ -287,6 +275,14 @@ jobs: with: path: source fetch-depth: 0 + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: docurium + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} - name: Generate documentation working-directory: source run: | diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 0474df7bbad..43796859762 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -8,7 +8,7 @@ on: env: docker-registry: ghcr.io - docker-config-path: source/ci/docker + docker-config-path: ci/docker permissions: contents: read @@ -355,22 +355,15 @@ jobs: - name: Setup QEMU run: docker run --rm --privileged multiarch/qemu-user-static:register --reset if: matrix.platform.container.qemu == true - - name: Download container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.platform.container.name }}" "${{ matrix.platform.container.dockerfile }}" - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: ${{ matrix.platform.container.name }} + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} if: matrix.platform.container.name != '' - - name: Create container - run: | - if [ "${{ matrix.container.base }}" != "" ]; then - BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" - fi - docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . - working-directory: ${{ env.docker-config-path }} - if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - name: Prepare build run: mkdir build - name: Build @@ -420,13 +413,14 @@ jobs: with: path: source fetch-depth: 0 - - name: Download container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" xenial - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: xenial + github_token: ${{ secrets.github_token }} + if: matrix.platform.container.name != '' - name: Run Coverity run: source/ci/coverity.sh env: diff --git a/ci/getcontainer.sh b/ci/getcontainer.sh deleted file mode 100755 index 81d0c1d9266..00000000000 --- a/ci/getcontainer.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -set -e - -IMAGE_NAME=$1 -DOCKERFILE_PATH=$2 - -if [ "${IMAGE_NAME}" = "" ]; then - echo "usage: $0 image_name [dockerfile]" - exit 1 -fi - -if [ "${DOCKERFILE_PATH}" = "" ]; then - DOCKERFILE_PATH="${IMAGE_NAME}" -fi - -if [ "${DOCKER_REGISTRY}" = "" ]; then - echo "DOCKER_REGISTRY environment variable is unset." - echo "Not running inside GitHub Actions or misconfigured?" - exit 1 -fi - -DOCKER_CONTAINER="${GITHUB_REPOSITORY}/${IMAGE_NAME}" -DOCKER_REGISTRY_CONTAINER="${DOCKER_REGISTRY}/${DOCKER_CONTAINER}" - -echo "dockerfile=${DOCKERFILE_PATH}" >> $GITHUB_ENV -echo "docker-container=${DOCKER_CONTAINER}" >> $GITHUB_ENV -echo "docker-registry-container=${DOCKER_REGISTRY_CONTAINER}" >> $GITHUB_ENV - -# Identify the last git commit that touched the Dockerfiles -# Use this as a hash to identify the resulting docker containers -DOCKER_SHA=$(git log -1 --pretty=format:"%h" -- "${DOCKERFILE_PATH}") -echo "docker-sha=${DOCKER_SHA}" >> $GITHUB_ENV - -DOCKER_REGISTRY_CONTAINER_SHA="${DOCKER_REGISTRY_CONTAINER}:${DOCKER_SHA}" - -echo "docker-registry-container-sha=${DOCKER_REGISTRY_CONTAINER_SHA}" >> $GITHUB_ENV -echo "docker-registry-container-latest=${DOCKER_REGISTRY_CONTAINER}:latest" >> $GITHUB_ENV - -echo "::: logging in to ${DOCKER_REGISTRY} as ${GITHUB_ACTOR}" - -exists="true" -docker login https://${DOCKER_REGISTRY} -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN} || exists="false" - -echo "::: pulling ${DOCKER_REGISTRY_CONTAINER_SHA}" - -if [ "${exists}" != "false" ]; then - docker pull ${DOCKER_REGISTRY_CONTAINER_SHA} || exists="false" -fi - -if [ "${exists}" = "true" ]; then - echo "docker-container-exists=true" >> $GITHUB_ENV -else - echo "docker-container-exists=false" >> $GITHUB_ENV -fi From d6454dd467750c0e1d3eb5bc69742d8825534ca1 Mon Sep 17 00:00:00 2001 From: DavHau Date: Thu, 11 Jan 2024 16:34:36 +0700 Subject: [PATCH 368/816] docs: fix mistake in attr.h Also fix indentation --- include/git2/attr.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/git2/attr.h b/include/git2/attr.h index 0c838727d14..69929b3dfc6 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -116,14 +116,12 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); */ #define GIT_ATTR_CHECK_FILE_THEN_INDEX 0 #define GIT_ATTR_CHECK_INDEX_THEN_FILE 1 -#define GIT_ATTR_CHECK_INDEX_ONLY 2 +#define GIT_ATTR_CHECK_INDEX_ONLY 2 /** * Check attribute flags: controlling extended attribute behavior. * * Normally, attribute checks include looking in the /etc (or system - * equivalent) directory for a `gitattributes` file. Passing this - * flag will cause attribute checks to ignore that file. * equivalent) directory for a `gitattributes` file. Passing the * `GIT_ATTR_CHECK_NO_SYSTEM` flag will cause attribute checks to * ignore that file. From 45c8caad1cd10434e4c77df619da6f021558fede Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 7 Jan 2024 04:04:39 +0000 Subject: [PATCH 369/816] benchmarks: update name to be "libgit2" --- .github/workflows/benchmark.yml | 2 +- tests/benchmarks/benchmark.sh | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 7705d89e97a..67a00298783 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -76,7 +76,7 @@ jobs: fi mkdir benchmark && cd benchmark - ../source/tests/benchmarks/benchmark.sh --baseline-cli "git" --cli "${GIT2_CLI}" --json benchmarks.json --zip benchmarks.zip + ../source/tests/benchmarks/benchmark.sh --baseline-cli "git" --cli "${GIT2_CLI}" --name libgit2 --json benchmarks.json --zip benchmarks.zip shell: bash - name: Upload results uses: actions/upload-artifact@v2 diff --git a/tests/benchmarks/benchmark.sh b/tests/benchmarks/benchmark.sh index 4a89807b789..4cb2b2fbfd3 100755 --- a/tests/benchmarks/benchmark.sh +++ b/tests/benchmarks/benchmark.sh @@ -6,9 +6,10 @@ set -eo pipefail # parse the command line # -usage() { echo "usage: $(basename "$0") [--cli ] [--baseline-cli ] [--suite ] [--json ] [--zip ] [--verbose] [--debug]"; } +usage() { echo "usage: $(basename "$0") [--cli ] [--name ] [--baseline-cli ] [--suite ] [--json ] [--zip ] [--verbose] [--debug]"; } TEST_CLI="git" +TEST_CLI_NAME= BASELINE_CLI= SUITE= JSON_RESULT= @@ -22,6 +23,9 @@ for a in "$@"; do if [ "${NEXT}" = "cli" ]; then TEST_CLI="${a}" NEXT= + elif [ "${NEXT}" = "name" ]; then + TEST_CLI_NAME="${a}" + NEXT= elif [ "${NEXT}" = "baseline-cli" ]; then BASELINE_CLI="${a}" NEXT= @@ -41,6 +45,10 @@ for a in "$@"; do NEXT="cli" elif [[ "${a}" == "-c"* ]]; then TEST_CLI="${a/-c/}" + elif [ "${a}" = "n" ] || [ "${a}" = "--name" ]; then + NEXT="name" + elif [[ "${a}" == "-n"* ]]; then + TEST_CLI_NAME="${a/-n/}" elif [ "${a}" = "b" ] || [ "${a}" = "--baseline-cli" ]; then NEXT="baseline-cli" elif [[ "${a}" == "-b"* ]]; then From 155eb67f2893091cab39585f5d509a5166dcd344 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 7 Jan 2024 04:06:50 +0000 Subject: [PATCH 370/816] benchmarks: use upload-artifact v3 --- .github/workflows/benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 67a00298783..d47f2cc2900 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -79,7 +79,7 @@ jobs: ../source/tests/benchmarks/benchmark.sh --baseline-cli "git" --cli "${GIT2_CLI}" --name libgit2 --json benchmarks.json --zip benchmarks.zip shell: bash - name: Upload results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: benchmark-${{ matrix.platform.id }} path: benchmark From a79e48addb34a2736943d6bd6bf7676214ec7ece Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 11 Jan 2024 17:04:06 +0000 Subject: [PATCH 371/816] benchmarks: publish benchmarks as a static api --- .github/workflows/benchmark.yml | 56 ++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index d47f2cc2900..831ffbb8235 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -49,7 +49,7 @@ jobs: id: windows setup-script: win32 fail-fast: false - name: "Build ${{ matrix.platform.name }}" + name: "Benchmark ${{ matrix.platform.name }}" env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} steps: @@ -84,3 +84,57 @@ jobs: name: benchmark-${{ matrix.platform.id }} path: benchmark if: always() + + # Publish the results + publish: + name: Publish results + needs: [ build ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check out benchmark repository + uses: actions/checkout@v3 + with: + repository: libgit2/benchmarks + path: site + fetch-depth: 0 + ssh-key: ${{ secrets.BENCHMARKS_PUBLISH_KEY }} + - name: Download test results + uses: actions/download-artifact@v3 + - name: Publish API + run: | + # Move today's benchmark run into the right place + for platform in linux macos windows; do + TIMESTAMP=$(jq .time.start < "benchmark-${platform}/benchmarks.json") + TIMESTAMP_LEN=$(echo -n ${TIMESTAMP} | wc -c | xargs) + DENOMINATOR=1 + if [ "${TIMESTAMP_LEN}" = "19" ]; then + DENOMINATOR="1000000000" + elif [ "${TIMESTAMP_LEN}" = "13" ]; then + DENOMINATOR="1000" + else + echo "unknown timestamp" + exit 1 + fi + + if [[ "$(uname -s)" == "Darwin" ]]; then + DATE=$(date -R -r $(("${TIMESTAMP}/${DENOMINATOR}")) +"%Y-%m-%d") + else + DATE=$(date -d @$(("${TIMESTAMP}/${DENOMINATOR}")) +"%Y-%m-%d") + fi + + mkdir -p "site/public/api/runs/${DATE}" + cp "benchmark-${platform}/benchmarks.json" "site/public/api/runs/${DATE}/${platform}.json" + done + + (cd site && node scripts/aggregate.js) + + ( + cd site && + git config user.name 'Benchmark Site Generation' && + git config user.email 'libgit2@users.noreply.github.com' && + git add . && + git commit --allow-empty -m"benchmark update ${DATE}" && + git push origin main + ) + shell: bash From 516749fe7dc60ebad7b18aae610e626d11ba1f94 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 14 Jan 2024 01:03:29 +0000 Subject: [PATCH 372/816] repo: simplify safe.directory comparison Keep the `git_str` buf that prevents unnecessary small allocations, and simplify the comparisons compared to what was there previously. --- src/libgit2/repository.c | 52 ++++++++++++++++----------------------- tests/libgit2/repo/open.c | 4 +-- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index f9d639b6144..2db106ce6eb 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -537,7 +537,8 @@ static int read_gitfile(git_str *path_out, const char *file_path) } typedef struct { - git_str repo_path; + const char *repo_path; + git_str tmp; bool *is_safe; } validate_ownership_data; @@ -552,6 +553,18 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) } else { const char *test_path = entry->value; + if (git_str_sets(&data->tmp, test_path) < 0 || + git_fs_path_to_dir(&data->tmp) < 0) + return -1; + + /* + * Ensure that `git_fs_path_to_dir` mutated the + * input path by adding a trailing backslash. + * A trailing backslash on the input is not allowed. + */ + if (strcmp(data->tmp.ptr, test_path) == 0) + return 0; + #ifdef GIT_WIN32 /* * Git for Windows does some truly bizarre things with @@ -581,7 +594,8 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) strncmp(test_path, "//wsl.localhost/", strlen("//wsl.localhost/")) != 0) test_path++; #endif - if (strcmp(test_path, data->repo_path.ptr) == 0) + + if (strcmp(data->tmp.ptr, data->repo_path) == 0) *data->is_safe = true; } @@ -594,7 +608,7 @@ static int validate_ownership_config( bool use_env) { validate_ownership_data ownership_data = { - GIT_STR_INIT, is_safe + path, GIT_STR_INIT, is_safe }; git_config *config; int error; @@ -602,13 +616,6 @@ static int validate_ownership_config( if (load_global_config(&config, use_env) != 0) return 0; - git_str_sets(&ownership_data.repo_path, path); - if (git_str_oom(&ownership_data.repo_path)) - return -1; - if (git_str_len(&ownership_data.repo_path) > 1 && - ownership_data.repo_path.ptr[git_str_len(&ownership_data.repo_path) - 1] == '/') - git_str_shorten(&ownership_data.repo_path, 1); - error = git_config_get_multivar_foreach(config, "safe.directory", NULL, validate_ownership_cb, @@ -618,7 +625,7 @@ static int validate_ownership_config( error = 0; git_config_free(config); - git_str_dispose(&ownership_data.repo_path); + git_str_dispose(&ownership_data.tmp); return error; } @@ -685,26 +692,9 @@ static int validate_ownership(git_repository *repo) goto done; if (!is_safe) { - git_str nice_path = GIT_STR_INIT; -#ifdef GIT_WIN32 - /* see comment above in validate_ownership_cb */ - if (!strncasecmp(path, "//", strlen("//"))) - git_str_puts(&nice_path, "%(prefix)/"); -#endif - git_str_puts(&nice_path, path); - if (!git_str_oom(&nice_path)) { - if (git_str_len(&nice_path) > 1 && nice_path.ptr[git_str_len(&nice_path) - 1] == '/') - git_str_shorten(&nice_path, 1); - git_error_set( - GIT_ERROR_CONFIG, - "repository path '%s' is not owned by current user.\n\nTo add an exception use the path '%s'.", - path, nice_path.ptr); - } else - git_error_set( - GIT_ERROR_CONFIG, - "repository path '%s' is not owned by current user.", - path); - git_str_dispose(&nice_path); + git_error_set(GIT_ERROR_CONFIG, + "repository path '%s' is not owned by current user", + path); error = GIT_EOWNER; } diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index 547e300a170..9c0bfde7b57 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -555,7 +555,7 @@ void test_repo_open__can_allowlist_dirs_with_problematic_ownership(void) git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); - // Test with incorrect exception (slash at the end) + /* Test with incorrect exception (slash at the end) */ git_str_printf(&config_data, "[foo]\n" \ "\tbar = Foobar\n" \ @@ -572,7 +572,7 @@ void test_repo_open__can_allowlist_dirs_with_problematic_ownership(void) cl_git_rewritefile(config_filename.ptr, config_data.ptr); cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); - // Test with correct exception + /* Test with correct exception */ git_str_clear(&config_data); git_str_printf(&config_data, "[foo]\n" \ From f62abd00db3618afff5eb4fd1c23bd7259d8e6d8 Mon Sep 17 00:00:00 2001 From: u_quark Date: Mon, 18 Dec 2023 15:26:55 +0000 Subject: [PATCH 373/816] Use environment variables when creating signatures When creating an action signature (e.g. for a commit author and committer) read the following environment variables that can override the configuration options: * `GIT_AUTHOR_NAME` is the human-readable name in the "author" field. * `GIT_AUTHOR_EMAIL` is the email for the "author" field. * `GIT_AUTHOR_DATE` is the timestamp used for the "author" field. * `GIT_COMMITTER_NAME` sets the human name for the "committer" field. * `GIT_COMMITTER_EMAIL` is the email address for the "committer" field. * `GIT_COMMITTER_DATE` is used for the timestamp in the "committer" field. * `EMAIL` is the fallback email address in case the user.email configuration value isn't set. If this isn't set, Git falls back to the system user and host names. This is taken from the git documentation chapter "10.8 Environment Variables": https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables This PR adds support for reading these environment variables by adding two new functions `git_signature_default_author` and `git_signature_default_committer` and deprecates the `git_signature_default` function. Fixes: https://github.com/libgit2/libgit2/issues/3751 Prior work: * https://github.com/libgit2/libgit2/pull/4409 * https://github.com/libgit2/libgit2/pull/5479 * https://github.com/libgit2/libgit2/pull/6290 --- examples/commit.c | 14 ++++-- examples/init.c | 10 ++-- examples/stash.c | 2 +- examples/tag.c | 2 +- include/git2/signature.h | 48 +++++++++++++++++++ src/libgit2/rebase.c | 2 +- src/libgit2/refs.c | 2 +- src/libgit2/signature.c | 73 +++++++++++++++++++++++++++++ src/libgit2/signature.h | 2 +- src/util/date.c | 10 +++- src/util/date.h | 12 +++++ tests/libgit2/commit/signature.c | 80 ++++++++++++++++++++++++++++++++ tests/libgit2/date/date.c | 8 ++++ tests/libgit2/remote/fetch.c | 2 +- tests/libgit2/repo/init.c | 12 +++-- 15 files changed, 258 insertions(+), 21 deletions(-) diff --git a/examples/commit.c b/examples/commit.c index aedc1af7e1c..1ba4739f051 100644 --- a/examples/commit.c +++ b/examples/commit.c @@ -39,7 +39,7 @@ int lg2_commit(git_repository *repo, int argc, char **argv) git_index *index; git_object *parent = NULL; git_reference *ref = NULL; - git_signature *signature; + git_signature *author_signature, *committer_signature; /* Validate args */ if (argc < 3 || strcmp(opt, "-m") != 0) { @@ -63,21 +63,25 @@ int lg2_commit(git_repository *repo, int argc, char **argv) check_lg2(git_tree_lookup(&tree, repo, &tree_oid), "Error looking up tree", NULL); - check_lg2(git_signature_default(&signature, repo), "Error creating signature", NULL); + check_lg2(git_signature_default_author(&author_signature, repo), + "Error creating author signature", NULL); + check_lg2(git_signature_default_committer(&committer_signature, repo), + "Error creating committer signature", NULL); check_lg2(git_commit_create_v( &commit_oid, repo, "HEAD", - signature, - signature, + author_signature, + committer_signature, NULL, comment, tree, parent ? 1 : 0, parent), "Error creating commit", NULL); git_index_free(index); - git_signature_free(signature); + git_signature_free(author_signature); + git_signature_free(committer_signature); git_tree_free(tree); git_object_free(parent); git_reference_free(ref); diff --git a/examples/init.c b/examples/init.c index 2f681c5ae6e..4cd55abad1e 100644 --- a/examples/init.c +++ b/examples/init.c @@ -123,14 +123,15 @@ int lg2_init(git_repository *repo, int argc, char *argv[]) */ static void create_initial_commit(git_repository *repo) { - git_signature *sig; + git_signature *author_sig, *committer_sig; git_index *index; git_oid tree_id, commit_id; git_tree *tree; /** First use the config to initialize a commit signature for the user. */ - if (git_signature_default(&sig, repo) < 0) + if ((git_signature_default_author(&author_sig, repo) < 0) || + (git_signature_default_committer(&committer_sig, repo) < 0)) fatal("Unable to create a commit signature.", "Perhaps 'user.name' and 'user.email' are not set"); @@ -162,14 +163,15 @@ static void create_initial_commit(git_repository *repo) */ if (git_commit_create_v( - &commit_id, repo, "HEAD", sig, sig, + &commit_id, repo, "HEAD", author_sig, committer_sig, NULL, "Initial commit", tree, 0) < 0) fatal("Could not create the initial commit", NULL); /** Clean up so we don't leak memory. */ git_tree_free(tree); - git_signature_free(sig); + git_signature_free(author_sig); + git_signature_free(committer_sig); } static void usage(const char *error, const char *arg) diff --git a/examples/stash.c b/examples/stash.c index 8142439c702..c330cbce102 100644 --- a/examples/stash.c +++ b/examples/stash.c @@ -108,7 +108,7 @@ static int cmd_push(git_repository *repo, struct opts *opts) if (opts->argc) usage("push does not accept any parameters"); - check_lg2(git_signature_default(&signature, repo), + check_lg2(git_signature_default_author(&signature, repo), "Unable to get signature", NULL); check_lg2(git_stash_save(&stashid, repo, signature, NULL, GIT_STASH_DEFAULT), "Unable to save stash", NULL); diff --git a/examples/tag.c b/examples/tag.c index e4f71ae625f..9bebcd1e68e 100644 --- a/examples/tag.c +++ b/examples/tag.c @@ -226,7 +226,7 @@ static void action_create_tag(tag_state *state) check_lg2(git_revparse_single(&target, repo, opts->target), "Unable to resolve spec", opts->target); - check_lg2(git_signature_default(&tagger, repo), + check_lg2(git_signature_default_author(&tagger, repo), "Unable to create signature", NULL); check_lg2(git_tag_create(&oid, repo, opts->tag_name, diff --git a/include/git2/signature.h b/include/git2/signature.h index 849998e66f7..31aa9676d9f 100644 --- a/include/git2/signature.h +++ b/include/git2/signature.h @@ -48,6 +48,52 @@ GIT_EXTERN(int) git_signature_new(git_signature **out, const char *name, const c */ GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const char *email); +/** Create a new author action signature with default information based on the + * configuration and environment variables. + * + * If GIT_AUTHOR_NAME environment variable is set it uses that over the + * user.name value from the configuration. + * + * If GIT_AUTHOR_EMAIL environment variable is set it uses that over the + * user.email value from the configuration. The EMAIL environment variable is + * the fallback email address in case the user.email configuration value isn't + * set. + * + * If GIT_AUTHOR_DATE is set it uses that, otherwise it uses the current time + * as the timestamp. + * + * It will return GIT_ENOTFOUND if either the user.name or user.email are not + * set and there is no fallback from an environment variable. + * + * @param out new signature + * @param repo repository pointer + * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code + */ +GIT_EXTERN(int) git_signature_default_author(git_signature **out, git_repository *repo); + +/** Create a new committer action signature with default information based on + * the configuration and environment variables. + * + * If GIT_COMMITTER_NAME environment variable is set it uses that over the + * user.name value from the configuration. + * + * If GIT_COMMITTER_EMAIL environment variable is set it uses that over the + * user.email value from the configuration. The EMAIL environment variable is + * the fallback email address in case the user.email configuration value isn't + * set. + * + * If GIT_COMMITTER_DATE is set it uses that, otherwise it uses the current + * time as the timestamp. + * + * It will return GIT_ENOTFOUND if either the user.name or user.email are not + * set and there is no fallback from an environment variable. + * + * @param out new signature @param repo repository pointer @return 0 on + * success, GIT_ENOTFOUND if config is missing, or error code + */ +GIT_EXTERN(int) git_signature_default_committer(git_signature **out, git_repository *repo); + +#ifndef GIT_DEPRECATE_HARD /** * Create a new action signature with default user and now timestamp. * @@ -56,11 +102,13 @@ GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const c * based on that information. It will return GIT_ENOTFOUND if either the * user.name or user.email are not set. * + * @deprecated use git_signature_default_author or git_signature_default_committer instead * @param out new signature * @param repo repository pointer * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code */ GIT_EXTERN(int) git_signature_default(git_signature **out, git_repository *repo); +#endif /** * Create a new signature by parsing the given buffer, which is diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c index 77e442e981d..e9de626521a 100644 --- a/src/libgit2/rebase.c +++ b/src/libgit2/rebase.c @@ -1268,7 +1268,7 @@ static int rebase_copy_note( } if (!committer) { - if((error = git_signature_default(&who, rebase->repo)) < 0) { + if((error = git_signature_default_committer(&who, rebase->repo)) < 0) { if (error != GIT_ENOTFOUND || (error = git_signature_now(&who, "unknown", "unknown")) < 0) goto done; diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index c1ed04d233a..8b553d40ae8 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -451,7 +451,7 @@ int git_reference__log_signature(git_signature **out, git_repository *repo) git_signature *who; if(((error = refs_configured_ident(&who, repo)) < 0) && - ((error = git_signature_default(&who, repo)) < 0) && + ((error = git_signature_default_author(&who, repo)) < 0) && ((error = git_signature_now(&who, "unknown", "unknown")) < 0)) return error; diff --git a/src/libgit2/signature.c b/src/libgit2/signature.c index 12d2b5f8d50..1a694c4cf52 100644 --- a/src/libgit2/signature.c +++ b/src/libgit2/signature.c @@ -10,6 +10,7 @@ #include "repository.h" #include "git2/common.h" #include "posix.h" +#include "date.h" void git_signature_free(git_signature *sig) { @@ -201,6 +202,78 @@ int git_signature_default(git_signature **out, git_repository *repo) return error; } +int git_signature__default_from_env(const char *name_env_var, const char *email_env_var, + const char *date_env_var, git_signature **out, git_repository *repo) +{ + int error; + git_config *cfg; + const char *name, *email, *date; + git_time_t timestamp; + int offset; + git_str name_env = GIT_STR_INIT; + git_str email_env = GIT_STR_INIT; + git_str date_env = GIT_STR_INIT; + int have_email_env = -1; + + if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) + return error; + + /* Check if the environment variable for the name is set */ + if (!(git__getenv(&name_env, name_env_var))) + name = git_str_cstr(&name_env); + else + /* or else read the configuration value. */ + if ((error = git_config_get_string(&name, cfg, "user.name")) < 0) + goto done; + + /* Check if the environment variable for the email is set. */ + if (!(git__getenv(&email_env, email_env_var))) + email = git_str_cstr(&email_env); + else { + /* Check if the fallback EMAIL environment variable is set + * before we check the configuration so that we preserve the + * error message if the configuration value is missing. */ + git_str_dispose(&email_env); + have_email_env = !git__getenv(&email_env, "EMAIL"); + if ((error = git_config_get_string(&email, cfg, "user.email")) < 0) { + if (have_email_env) { + email = git_str_cstr(&email_env); + error = 0; + } else + goto done; + } + } + + /* Check if the environment variable for the timestamp is set */ + if (!(git__getenv(&date_env, date_env_var))) { + date = git_str_cstr(&date_env); + if ((error = git_date_offset_parse(×tamp, &offset, date)) < 0) + goto done; + error = git_signature_new(out, name, email, timestamp, offset); + } else + /* or else default to the current timestamp. */ + error = git_signature_now(out, name, email); + +done: + git_config_free(cfg); + git_str_dispose(&name_env); + git_str_dispose(&email_env); + git_str_dispose(&date_env); + return error; +} + +int git_signature_default_author(git_signature **out, git_repository *repo) +{ + return git_signature__default_from_env("GIT_AUTHOR_NAME", "GIT_AUTHOR_EMAIL", + "GIT_AUTHOR_DATE", out, repo); +} + +int git_signature_default_committer(git_signature **out, git_repository *repo) +{ + return git_signature__default_from_env("GIT_COMMITTER_NAME", "GIT_COMMITTER_EMAIL", + "GIT_COMMITTER_DATE", out, repo); +} + int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender) { diff --git a/src/libgit2/signature.h b/src/libgit2/signature.h index 5c8270954e7..23356161eff 100644 --- a/src/libgit2/signature.h +++ b/src/libgit2/signature.h @@ -17,7 +17,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender); void git_signature__writebuf(git_str *buf, const char *header, const git_signature *sig); bool git_signature__equal(const git_signature *one, const git_signature *two); - int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool); +int git_signature__default_from_env(const char *name_env_var, const char *email_env_var, const char *date_env_var, git_signature **out, git_repository *repo); #endif diff --git a/src/util/date.c b/src/util/date.c index 4d757e21a00..161712e163f 100644 --- a/src/util/date.c +++ b/src/util/date.c @@ -858,7 +858,7 @@ static git_time_t approxidate_str(const char *date, return update_tm(&tm, &now, 0); } -int git_date_parse(git_time_t *out, const char *date) +int git_date_offset_parse(git_time_t *out, int * out_offset, const char *date) { time_t time_sec; git_time_t timestamp; @@ -866,6 +866,7 @@ int git_date_parse(git_time_t *out, const char *date) if (!parse_date_basic(date, ×tamp, &offset)) { *out = timestamp; + *out_offset = offset; return 0; } @@ -876,6 +877,13 @@ int git_date_parse(git_time_t *out, const char *date) return error_ret; } +int git_date_parse(git_time_t *out, const char *date) +{ + int offset; + + return git_date_offset_parse(out, &offset, date); +} + int git_date_rfc2822_fmt(git_str *out, git_time_t time, int offset) { time_t t; diff --git a/src/util/date.h b/src/util/date.h index 7ebd3c30e41..785fc064bf5 100644 --- a/src/util/date.h +++ b/src/util/date.h @@ -10,9 +10,21 @@ #include "util.h" #include "str.h" +/* + * Parse a string into a value as a git_time_t with a timezone offset. + * + * Sample valid input: + * - "yesterday" + * - "July 17, 2003" + * - "2003-7-17 08:23i+03" + */ +extern int git_date_offset_parse(git_time_t *out, int *out_offset, const char *date); + /* * Parse a string into a value as a git_time_t. * + * Timezone offset is ignored. + * * Sample valid input: * - "yesterday" * - "July 17, 2003" diff --git a/tests/libgit2/commit/signature.c b/tests/libgit2/commit/signature.c index fddd5076eb7..b41182ce61e 100644 --- a/tests/libgit2/commit/signature.c +++ b/tests/libgit2/commit/signature.c @@ -153,3 +153,83 @@ void test_commit_signature__pos_and_neg_zero_offsets_dont_match(void) git_signature_free((git_signature *)with_neg_zero); git_signature_free((git_signature *)with_pos_zero); } + +static git_repository *g_repo; + +void test_commit_signature__initialize(void) +{ + g_repo = cl_git_sandbox_init("empty_standard_repo"); +} + +void test_commit_signature__cleanup(void) +{ + cl_git_sandbox_cleanup(); + g_repo = NULL; +} + +void test_commit_signature__signature_default(void) +{ + git_signature *author_sign, *committer_sign; + git_config *cfg, *local; + cl_git_pass(git_repository_config(&cfg, g_repo)); + cl_git_pass(git_config_open_level(&local, cfg, GIT_CONFIG_LEVEL_LOCAL)); + /* No configuration value is set and no environment variable */ + cl_git_fail(git_signature_default_author(&author_sign, g_repo)); + cl_git_fail(git_signature_default_committer(&committer_sign, g_repo)); + /* Name is read from configuration and email is read from fallback EMAIL + * environment variable */ + cl_git_pass(git_config_set_string(local, "user.name", "Name (config)")); + cl_setenv("EMAIL", "email-envvar@example.com"); + cl_git_pass(git_signature_default_author(&author_sign, g_repo)); + cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_assert_equal_s("Name (config)", author_sign->name); + cl_assert_equal_s("email-envvar@example.com", author_sign->email); + cl_assert_equal_s("Name (config)", committer_sign->name); + cl_assert_equal_s("email-envvar@example.com", committer_sign->email); + cl_setenv("EMAIL", NULL); + git_signature_free(author_sign); + git_signature_free(committer_sign); + /* Environment variables have precedence over configuration */ + cl_git_pass(git_config_set_string(local, "user.email", "config@example.com")); + cl_setenv("GIT_AUTHOR_NAME", "Author (envvar)"); + cl_setenv("GIT_AUTHOR_EMAIL", "author-envvar@example.com"); + cl_setenv("GIT_COMMITTER_NAME", "Committer (envvar)"); + cl_setenv("GIT_COMMITTER_EMAIL", "committer-envvar@example.com"); + cl_git_pass(git_signature_default_author(&author_sign, g_repo)); + cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_assert_equal_s("Author (envvar)", author_sign->name); + cl_assert_equal_s("author-envvar@example.com", author_sign->email); + cl_assert_equal_s("Committer (envvar)", committer_sign->name); + cl_assert_equal_s("committer-envvar@example.com", committer_sign->email); + git_signature_free(author_sign); + git_signature_free(committer_sign); + /* When environment variables are not set we can still read from + * configuration */ + cl_setenv("GIT_AUTHOR_NAME", NULL); + cl_setenv("GIT_AUTHOR_EMAIL", NULL); + cl_setenv("GIT_COMMITTER_NAME", NULL); + cl_setenv("GIT_COMMITTER_EMAIL", NULL); + cl_git_pass(git_signature_default_author(&author_sign, g_repo)); + cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_assert_equal_s("Name (config)", author_sign->name); + cl_assert_equal_s("config@example.com", author_sign->email); + cl_assert_equal_s("Name (config)", committer_sign->name); + cl_assert_equal_s("config@example.com", committer_sign->email); + git_signature_free(author_sign); + git_signature_free(committer_sign); + /* We can also override the timestamp with an environment variable */ + cl_setenv("GIT_AUTHOR_DATE", "1971-02-03 04:05:06+01"); + cl_setenv("GIT_COMMITTER_DATE", "1988-09-10 11:12:13-01"); + cl_git_pass(git_signature_default_author(&author_sign, g_repo)); + cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_assert_equal_i(34398306, author_sign->when.time); /* 1971-02-03 03:05:06 UTC */ + cl_assert_equal_i(60, author_sign->when.offset); + cl_assert_equal_i(589896733, committer_sign->when.time); /* 1988-09-10 12:12:13 UTC */ + cl_assert_equal_i(-60, committer_sign->when.offset); + git_signature_free(author_sign); + git_signature_free(committer_sign); + cl_setenv("GIT_AUTHOR_DATE", NULL); + cl_setenv("GIT_COMMITTER_DATE", NULL); + git_config_free(local); + git_config_free(cfg); +} diff --git a/tests/libgit2/date/date.c b/tests/libgit2/date/date.c index 82b5c67282e..b5796861ce4 100644 --- a/tests/libgit2/date/date.c +++ b/tests/libgit2/date/date.c @@ -20,3 +20,11 @@ void test_date_date__invalid_date(void) cl_git_fail(git_date_parse(&d, "")); cl_git_fail(git_date_parse(&d, "NEITHER_INTEGER_NOR_DATETIME")); } + +void test_date_date__offset(void) +{ + git_time_t d; + int offset; + cl_git_pass(git_date_offset_parse(&d, &offset, "1970-1-1 01:00:00+03")); + cl_assert_equal_i(offset, 3*60); +} diff --git a/tests/libgit2/remote/fetch.c b/tests/libgit2/remote/fetch.c index a5d3272c56b..c24ec5a01f6 100644 --- a/tests/libgit2/remote/fetch.c +++ b/tests/libgit2/remote/fetch.c @@ -82,7 +82,7 @@ static void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, cl_git_pass(git_treebuilder_new(&tb, repo1, NULL)); cl_git_pass(git_treebuilder_write(&empty_tree_id, tb)); cl_git_pass(git_tree_lookup(&empty_tree, repo1, &empty_tree_id)); - cl_git_pass(git_signature_default(&sig, repo1)); + cl_git_pass(git_signature_default_author(&sig, repo1)); cl_git_pass(git_commit_create(commit1id, repo1, REPO1_REFNAME, sig, sig, NULL, "one", empty_tree, 0, NULL)); cl_git_pass(git_commit_lookup(&commit1, repo1, commit1id)); diff --git a/tests/libgit2/repo/init.c b/tests/libgit2/repo/init.c index d78ec063cd2..bb26e5443ae 100644 --- a/tests/libgit2/repo/init.c +++ b/tests/libgit2/repo/init.c @@ -581,7 +581,7 @@ void test_repo_init__init_with_initial_commit(void) * made to a repository... */ - /* Make sure we're ready to use git_signature_default :-) */ + /* Make sure we're ready to use git_signature_default_author :-) */ { git_config *cfg, *local; cl_git_pass(git_repository_config(&cfg, g_repo)); @@ -594,20 +594,22 @@ void test_repo_init__init_with_initial_commit(void) /* Create a commit with the new contents of the index */ { - git_signature *sig; + git_signature *author_sig, *committer_sig; git_oid tree_id, commit_id; git_tree *tree; - cl_git_pass(git_signature_default(&sig, g_repo)); + cl_git_pass(git_signature_default_author(&author_sig, g_repo)); + cl_git_pass(git_signature_default_committer(&committer_sig, g_repo)); cl_git_pass(git_index_write_tree(&tree_id, index)); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); cl_git_pass(git_commit_create_v( - &commit_id, g_repo, "HEAD", sig, sig, + &commit_id, g_repo, "HEAD", author_sig, committer_sig, NULL, "First", tree, 0)); git_tree_free(tree); - git_signature_free(sig); + git_signature_free(author_sig); + git_signature_free(committer_sig); } git_index_free(index); From 47ec74b7c1caa840661e88550e9a909779e8aab6 Mon Sep 17 00:00:00 2001 From: u_quark Date: Fri, 22 Dec 2023 12:14:12 +0000 Subject: [PATCH 374/816] Guard deprecated function definition - fix CI --- src/libgit2/signature.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libgit2/signature.c b/src/libgit2/signature.c index 1a694c4cf52..fa067c7ad17 100644 --- a/src/libgit2/signature.c +++ b/src/libgit2/signature.c @@ -185,6 +185,7 @@ int git_signature_now(git_signature **sig_out, const char *name, const char *ema return 0; } +#ifndef GIT_DEPRECATE_HARD int git_signature_default(git_signature **out, git_repository *repo) { int error; @@ -201,6 +202,7 @@ int git_signature_default(git_signature **out, git_repository *repo) git_config_free(cfg); return error; } +#endif int git_signature__default_from_env(const char *name_env_var, const char *email_env_var, const char *date_env_var, git_signature **out, git_repository *repo) From 94125fb5c7241efb59bf4717561d7f18fd07ae87 Mon Sep 17 00:00:00 2001 From: u_quark Date: Sun, 24 Dec 2023 09:26:37 +0000 Subject: [PATCH 375/816] Fix clang tests: uninitialized variable --- examples/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/init.c b/examples/init.c index 4cd55abad1e..f0f0105be6e 100644 --- a/examples/init.c +++ b/examples/init.c @@ -123,7 +123,7 @@ int lg2_init(git_repository *repo, int argc, char *argv[]) */ static void create_initial_commit(git_repository *repo) { - git_signature *author_sig, *committer_sig; + git_signature *author_sig = NULL, *committer_sig = NULL; git_index *index; git_oid tree_id, commit_id; git_tree *tree; From 080248352b4517bf07525036be29c87a0198b0c6 Mon Sep 17 00:00:00 2001 From: u_quark Date: Sun, 14 Jan 2024 12:13:25 +0000 Subject: [PATCH 376/816] Address review comments Also fix some comment formatting. --- include/git2/signature.h | 17 +++++++++++------ src/libgit2/signature.c | 2 +- src/libgit2/signature.h | 1 - src/util/date.c | 2 +- tests/libgit2/commit/signature.c | 5 +++++ 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/git2/signature.h b/include/git2/signature.h index 31aa9676d9f..845cca214a6 100644 --- a/include/git2/signature.h +++ b/include/git2/signature.h @@ -48,7 +48,8 @@ GIT_EXTERN(int) git_signature_new(git_signature **out, const char *name, const c */ GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const char *email); -/** Create a new author action signature with default information based on the +/** + * Create a new author action signature with default information based on the * configuration and environment variables. * * If GIT_AUTHOR_NAME environment variable is set it uses that over the @@ -71,7 +72,8 @@ GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const c */ GIT_EXTERN(int) git_signature_default_author(git_signature **out, git_repository *repo); -/** Create a new committer action signature with default information based on +/** + * Create a new committer action signature with default information based on * the configuration and environment variables. * * If GIT_COMMITTER_NAME environment variable is set it uses that over the @@ -88,15 +90,19 @@ GIT_EXTERN(int) git_signature_default_author(git_signature **out, git_repository * It will return GIT_ENOTFOUND if either the user.name or user.email are not * set and there is no fallback from an environment variable. * - * @param out new signature @param repo repository pointer @return 0 on - * success, GIT_ENOTFOUND if config is missing, or error code + * @param out new signature + * @param repo repository pointer + * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code */ GIT_EXTERN(int) git_signature_default_committer(git_signature **out, git_repository *repo); -#ifndef GIT_DEPRECATE_HARD /** * Create a new action signature with default user and now timestamp. * + * Warning: This function may be deprecated in the future. Use one of + * git_signature_default_author or git_signature_default_committer instead. + * These are more compliant with how git constructs default signatures. + * * This looks up the user.name and user.email from the configuration and * uses the current time as the timestamp, and creates a new signature * based on that information. It will return GIT_ENOTFOUND if either the @@ -108,7 +114,6 @@ GIT_EXTERN(int) git_signature_default_committer(git_signature **out, git_reposit * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code */ GIT_EXTERN(int) git_signature_default(git_signature **out, git_repository *repo); -#endif /** * Create a new signature by parsing the given buffer, which is diff --git a/src/libgit2/signature.c b/src/libgit2/signature.c index fa067c7ad17..e6b1ac6622d 100644 --- a/src/libgit2/signature.c +++ b/src/libgit2/signature.c @@ -204,7 +204,7 @@ int git_signature_default(git_signature **out, git_repository *repo) } #endif -int git_signature__default_from_env(const char *name_env_var, const char *email_env_var, +static int git_signature__default_from_env(const char *name_env_var, const char *email_env_var, const char *date_env_var, git_signature **out, git_repository *repo) { int error; diff --git a/src/libgit2/signature.h b/src/libgit2/signature.h index 23356161eff..a5645e9bba5 100644 --- a/src/libgit2/signature.h +++ b/src/libgit2/signature.h @@ -18,6 +18,5 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, const char void git_signature__writebuf(git_str *buf, const char *header, const git_signature *sig); bool git_signature__equal(const git_signature *one, const git_signature *two); int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool); -int git_signature__default_from_env(const char *name_env_var, const char *email_env_var, const char *date_env_var, git_signature **out, git_repository *repo); #endif diff --git a/src/util/date.c b/src/util/date.c index 161712e163f..2e9fc00e145 100644 --- a/src/util/date.c +++ b/src/util/date.c @@ -858,7 +858,7 @@ static git_time_t approxidate_str(const char *date, return update_tm(&tm, &now, 0); } -int git_date_offset_parse(git_time_t *out, int * out_offset, const char *date) +int git_date_offset_parse(git_time_t *out, int *out_offset, const char *date) { time_t time_sec; git_time_t timestamp; diff --git a/tests/libgit2/commit/signature.c b/tests/libgit2/commit/signature.c index b41182ce61e..2ad91f3f3d0 100644 --- a/tests/libgit2/commit/signature.c +++ b/tests/libgit2/commit/signature.c @@ -174,6 +174,11 @@ void test_commit_signature__signature_default(void) cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_open_level(&local, cfg, GIT_CONFIG_LEVEL_LOCAL)); /* No configuration value is set and no environment variable */ + cl_setenv("EMAIL", NULL); + cl_setenv("GIT_AUTHOR_NAME", NULL); + cl_setenv("GIT_AUTHOR_EMAIL", NULL); + cl_setenv("GIT_COMMITTER_NAME", NULL); + cl_setenv("GIT_COMMITTER_EMAIL", NULL); cl_git_fail(git_signature_default_author(&author_sign, g_repo)); cl_git_fail(git_signature_default_committer(&committer_sign, g_repo)); /* Name is read from configuration and email is read from fallback EMAIL From 48cb38a1b8f4479c940068be45d4b2b66686611e Mon Sep 17 00:00:00 2001 From: u_quark Date: Sun, 14 Jan 2024 12:22:26 +0000 Subject: [PATCH 377/816] Remove deprecated annotation --- include/git2/signature.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/git2/signature.h b/include/git2/signature.h index 845cca214a6..84c36a33d98 100644 --- a/include/git2/signature.h +++ b/include/git2/signature.h @@ -108,7 +108,6 @@ GIT_EXTERN(int) git_signature_default_committer(git_signature **out, git_reposit * based on that information. It will return GIT_ENOTFOUND if either the * user.name or user.email are not set. * - * @deprecated use git_signature_default_author or git_signature_default_committer instead * @param out new signature * @param repo repository pointer * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code From 048421a404d3c4e4ba524496e551e61077b11a2b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 14 Jan 2024 14:39:17 +0000 Subject: [PATCH 378/816] repo: add `head_commit` helper Provide a helper method to provide the HEAD's commit, much like our existing `head_tree` helper. --- src/libgit2/repository.c | 19 +++++++++++++++++++ src/libgit2/repository.h | 1 + 2 files changed, 20 insertions(+) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index cb6658cfc75..b2afc4f59d2 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3314,6 +3314,25 @@ int git_repository_set_bare(git_repository *repo) return 0; } +int git_repository_head_commit(git_commit **commit, git_repository *repo) +{ + git_reference *head; + git_object *obj; + int error; + + if ((error = git_repository_head(&head, repo)) < 0) + return error; + + if ((error = git_reference_peel(&obj, head, GIT_OBJECT_COMMIT)) < 0) + goto cleanup; + + *commit = (git_commit *)obj; + +cleanup: + git_reference_free(head); + return error; +} + int git_repository_head_tree(git_tree **tree, git_repository *repo) { git_reference *head; diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index be4bc8860d6..f45a3591981 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -173,6 +173,7 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) return repo->attrcache; } +int git_repository_head_commit(git_commit **commit, git_repository *repo); int git_repository_head_tree(git_tree **tree, git_repository *repo); int git_repository_create_head(const char *git_dir, const char *ref_name); From cf19ddc52227f4ec2efd4c0a84aa5d2362f0ffc7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 14 Jan 2024 15:37:20 +0000 Subject: [PATCH 379/816] commit: fix const declaration commit functions should take an array of const pointers, not a const array. --- examples/merge.c | 2 +- include/git2/commit.h | 6 +++--- src/libgit2/commit.c | 8 ++++---- src/libgit2/commit.h | 2 +- src/libgit2/notes.c | 4 ++-- src/libgit2/rebase.c | 9 ++++----- src/libgit2/stash.c | 4 ++-- tests/libgit2/checkout/tree.c | 2 +- tests/libgit2/cherrypick/workdir.c | 2 +- tests/libgit2/commit/commit.c | 4 ++-- tests/libgit2/commit/write.c | 2 +- tests/libgit2/diff/rename.c | 2 +- tests/libgit2/odb/freshen.c | 2 +- tests/libgit2/rebase/sign.c | 6 +++--- tests/libgit2/refs/reflog/messages.c | 2 +- tests/libgit2/revert/workdir.c | 6 +++--- tests/libgit2/revwalk/basic.c | 3 +-- 17 files changed, 32 insertions(+), 34 deletions(-) diff --git a/examples/merge.c b/examples/merge.c index 7a76912cd24..718c767d038 100644 --- a/examples/merge.c +++ b/examples/merge.c @@ -263,7 +263,7 @@ static int create_merge_commit(git_repository *repo, git_index *index, struct me sign, sign, NULL, msg, tree, - opts->annotated_count + 1, (const git_commit **)parents); + opts->annotated_count + 1, parents); check_lg2(err, "failed to create commit", NULL); /* We're done merging, cleanup the repository state */ diff --git a/include/git2/commit.h b/include/git2/commit.h index 8841aa033f3..ea0e94969a8 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -366,7 +366,7 @@ GIT_EXTERN(int) git_commit_create( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[]); + git_commit * const parents[]); /** * Create new commit in the repository using a variable argument list. @@ -469,7 +469,7 @@ GIT_EXTERN(int) git_commit_create_buffer( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[]); + git_commit * const parents[]); /** * Create a commit object from the given buffer and signature @@ -538,7 +538,7 @@ typedef int (*git_commit_create_cb)( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[], + git_commit * const parents[], void *payload); /** An array of commits returned from the library */ diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 2e30c1be9b0..9e3b29a00b8 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -281,7 +281,7 @@ int git_commit_create_from_ids( typedef struct { size_t total; - const git_commit **parents; + git_commit * const *parents; git_repository *repo; } commit_parent_data; @@ -307,7 +307,7 @@ int git_commit_create( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[]) + git_commit * const parents[]) { commit_parent_data data = { parent_count, parents, repo }; @@ -945,7 +945,7 @@ int git_commit_create_buffer( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[]) + git_commit * const parents[]) { GIT_BUF_WRAP_PRIVATE(out, git_commit__create_buffer, repo, author, committer, message_encoding, message, @@ -961,7 +961,7 @@ int git_commit__create_buffer( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[]) + git_commit * const parents[]) { int error; commit_parent_data data = { parent_count, parents, repo }; diff --git a/src/libgit2/commit.h b/src/libgit2/commit.h index c25fee327b8..53128ba5d83 100644 --- a/src/libgit2/commit.h +++ b/src/libgit2/commit.h @@ -64,7 +64,7 @@ int git_commit__create_buffer( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[]); + git_commit * const parents[]); int git_commit__parse( void *commit, diff --git a/src/libgit2/notes.c b/src/libgit2/notes.c index 13ca3824bf1..2dd194581fd 100644 --- a/src/libgit2/notes.c +++ b/src/libgit2/notes.c @@ -303,7 +303,7 @@ static int note_write( error = git_commit_create(&oid, repo, notes_ref, author, committer, NULL, GIT_NOTES_DEFAULT_MSG_ADD, - tree, *parents == NULL ? 0 : 1, (const git_commit **) parents); + tree, *parents == NULL ? 0 : 1, parents); if (notes_commit_out) git_oid_cpy(notes_commit_out, &oid); @@ -394,7 +394,7 @@ static int note_remove( NULL, GIT_NOTES_DEFAULT_MSG_RM, tree_after_removal, *parents == NULL ? 0 : 1, - (const git_commit **) parents); + parents); if (error < 0) goto cleanup; diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c index 77e442e981d..2fce3e7bc06 100644 --- a/src/libgit2/rebase.c +++ b/src/libgit2/rebase.c @@ -952,7 +952,7 @@ static int create_signed( const char *message, git_tree *tree, size_t parent_count, - const git_commit **parents) + git_commit * const *parents) { git_str commit_content = GIT_STR_INIT; git_buf commit_signature = { NULL, 0, 0 }, @@ -1040,8 +1040,7 @@ static int rebase_commit__create( if (rebase->options.commit_create_cb) { error = rebase->options.commit_create_cb(&commit_id, author, committer, message_encoding, message, - tree, 1, (const git_commit **)&parent_commit, - rebase->options.payload); + tree, 1, &parent_commit, rebase->options.payload); git_error_set_after_callback_function(error, "commit_create_cb"); @@ -1050,14 +1049,14 @@ static int rebase_commit__create( else if (rebase->options.signing_cb) { error = create_signed(&commit_id, rebase, author, committer, message_encoding, message, tree, - 1, (const git_commit **)&parent_commit); + 1, &parent_commit); } #endif if (error == GIT_PASSTHROUGH) error = git_commit_create(&commit_id, rebase->repo, NULL, author, committer, message_encoding, message, - tree, 1, (const git_commit **)&parent_commit); + tree, 1, &parent_commit); if (error) goto done; diff --git a/src/libgit2/stash.c b/src/libgit2/stash.c index b49e95cdb21..a0a72deacc6 100644 --- a/src/libgit2/stash.c +++ b/src/libgit2/stash.c @@ -124,7 +124,7 @@ static int commit_index( git_index *index, const git_signature *stasher, const char *message, - const git_commit *parent) + git_commit *parent) { git_tree *i_tree = NULL; git_oid i_commit_oid; @@ -423,7 +423,7 @@ static int build_stash_commit_from_tree( git_commit *u_commit, const git_tree *tree) { - const git_commit *parents[] = { NULL, NULL, NULL }; + git_commit *parents[] = { NULL, NULL, NULL }; parents[0] = b_commit; parents[1] = i_commit; diff --git a/tests/libgit2/checkout/tree.c b/tests/libgit2/checkout/tree.c index 65df00cd87b..97935aaeaa1 100644 --- a/tests/libgit2/checkout/tree.c +++ b/tests/libgit2/checkout/tree.c @@ -1235,7 +1235,7 @@ void test_checkout_tree__case_changing_rename(void) cl_git_pass(git_signature_new(&signature, "Renamer", "rename@contoso.com", time(NULL), 0)); - cl_git_pass(git_commit_create(&commit_id, g_repo, "refs/heads/dir", signature, signature, NULL, "case-changing rename", tree, 1, (const git_commit **)&dir_commit)); + cl_git_pass(git_commit_create(&commit_id, g_repo, "refs/heads/dir", signature, signature, NULL, "case-changing rename", tree, 1, &dir_commit)); cl_assert(git_fs_path_isfile("testrepo/readme")); if (case_sensitive) diff --git a/tests/libgit2/cherrypick/workdir.c b/tests/libgit2/cherrypick/workdir.c index c16b7814ac0..9d9a3f49795 100644 --- a/tests/libgit2/cherrypick/workdir.c +++ b/tests/libgit2/cherrypick/workdir.c @@ -77,7 +77,7 @@ void test_cherrypick_workdir__automerge(void) cl_git_pass(git_index_write_tree(&cherrypicked_tree_oid, repo_index)); cl_git_pass(git_tree_lookup(&cherrypicked_tree, repo, &cherrypicked_tree_oid)); cl_git_pass(git_commit_create(&cherrypicked_oid, repo, "HEAD", signature, signature, NULL, - "Cherry picked!", cherrypicked_tree, 1, (const git_commit **)&head)); + "Cherry picked!", cherrypicked_tree, 1, &head)); cl_assert(merge_test_index(repo_index, merge_index_entries + i * 3, 3)); diff --git a/tests/libgit2/commit/commit.c b/tests/libgit2/commit/commit.c index 140f87d0c72..923740f23af 100644 --- a/tests/libgit2/commit/commit.c +++ b/tests/libgit2/commit/commit.c @@ -36,11 +36,11 @@ void test_commit_commit__create_unexisting_update_ref(void) cl_git_fail(git_reference_lookup(&ref, _repo, "refs/heads/foo/bar")); cl_git_pass(git_commit_create(&oid, _repo, "refs/heads/foo/bar", s, s, - NULL, "some msg", tree, 1, (const git_commit **) &commit)); + NULL, "some msg", tree, 1, &commit)); /* fail because the parent isn't the tip of the branch anymore */ cl_git_fail(git_commit_create(&oid, _repo, "refs/heads/foo/bar", s, s, - NULL, "some msg", tree, 1, (const git_commit **) &commit)); + NULL, "some msg", tree, 1, &commit)); cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/foo/bar")); cl_assert_equal_oid(&oid, git_reference_target(ref)); diff --git a/tests/libgit2/commit/write.c b/tests/libgit2/commit/write.c index 890f7384b1a..d38b54d2077 100644 --- a/tests/libgit2/commit/write.c +++ b/tests/libgit2/commit/write.c @@ -118,7 +118,7 @@ void test_commit_write__into_buf(void) cl_git_pass(git_commit_lookup(&parent, g_repo, &parent_id)); cl_git_pass(git_commit_create_buffer(&commit, g_repo, author, committer, - NULL, root_commit_message, tree, 1, (const git_commit **) &parent)); + NULL, root_commit_message, tree, 1, &parent)); cl_assert_equal_s(commit.ptr, "tree 1810dff58d8a660512d4832e740f692884338ccd\n\ diff --git a/tests/libgit2/diff/rename.c b/tests/libgit2/diff/rename.c index 61a2f839cb3..15dee5c97d5 100644 --- a/tests/libgit2/diff/rename.c +++ b/tests/libgit2/diff/rename.c @@ -424,7 +424,7 @@ void test_diff_rename__test_small_files(void) cl_git_pass(git_index_write_tree(&oid, index)); cl_git_pass(git_tree_lookup(&commit_tree, g_repo, &oid)); cl_git_pass(git_signature_new(&signature, "Rename", "rename@example.com", 1404157834, 0)); - cl_git_pass(git_commit_create(&oid, g_repo, "HEAD", signature, signature, NULL, "Test commit", commit_tree, 1, (const git_commit**)&head_commit)); + cl_git_pass(git_commit_create(&oid, g_repo, "HEAD", signature, signature, NULL, "Test commit", commit_tree, 1, &head_commit)); cl_git_mkfile("renames/copy.txt", "Hello World!\n"); cl_git_rmfile("renames/small.txt"); diff --git a/tests/libgit2/odb/freshen.c b/tests/libgit2/odb/freshen.c index e337c82b773..d0e0e3c3c04 100644 --- a/tests/libgit2/odb/freshen.c +++ b/tests/libgit2/odb/freshen.c @@ -125,7 +125,7 @@ void test_odb_freshen__tree_during_commit(void) cl_git_pass(git_commit_create(&commit_id, repo, NULL, signature, signature, NULL, "New commit pointing to old tree", - tree, 1, (const git_commit **)&parent)); + tree, 1, &parent)); /* make sure we freshen the tree the commit points to */ cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after)); diff --git a/tests/libgit2/rebase/sign.c b/tests/libgit2/rebase/sign.c index 69bb1c6f998..45bac29d095 100644 --- a/tests/libgit2/rebase/sign.c +++ b/tests/libgit2/rebase/sign.c @@ -26,7 +26,7 @@ static int create_cb_passthrough( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[], + git_commit * const parents[], void *payload) { GIT_UNUSED(out); @@ -94,7 +94,7 @@ static int create_cb_signed_gpg( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[], + git_commit * const parents[], void *payload) { git_buf commit_content = GIT_BUF_INIT; @@ -202,7 +202,7 @@ static int create_cb_error( const char *message, const git_tree *tree, size_t parent_count, - const git_commit *parents[], + git_commit * const parents[], void *payload) { GIT_UNUSED(out); diff --git a/tests/libgit2/refs/reflog/messages.c b/tests/libgit2/refs/reflog/messages.c index 647c00d0dfd..4a2ecb02aed 100644 --- a/tests/libgit2/refs/reflog/messages.c +++ b/tests/libgit2/refs/reflog/messages.c @@ -233,7 +233,7 @@ void test_refs_reflog_messages__show_merge_for_merge_commits(void) cl_git_pass(git_commit_create(&merge_commit_oid, g_repo, "HEAD", s, s, NULL, "Merge commit", tree, - 2, (const struct git_commit **) parent_commits)); + 2, parent_commits)); cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, NULL, diff --git a/tests/libgit2/revert/workdir.c b/tests/libgit2/revert/workdir.c index 3e790b77f78..6d74254e533 100644 --- a/tests/libgit2/revert/workdir.c +++ b/tests/libgit2/revert/workdir.c @@ -188,7 +188,7 @@ void test_revert_workdir__again(void) cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); - cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, &orig_head)); cl_git_pass(git_revert(repo, orig_head, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); @@ -238,7 +238,7 @@ void test_revert_workdir__again_after_automerge(void) cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); - cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&head)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, &head)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, second_revert_entries, 6)); @@ -287,7 +287,7 @@ void test_revert_workdir__again_after_edit(void) cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); - cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, &orig_head)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); diff --git a/tests/libgit2/revwalk/basic.c b/tests/libgit2/revwalk/basic.c index 41090a1dac8..5c53405051b 100644 --- a/tests/libgit2/revwalk/basic.c +++ b/tests/libgit2/revwalk/basic.c @@ -550,8 +550,7 @@ void test_revwalk_basic__big_timestamp(void) cl_git_pass(git_signature_new(&sig, "Joe", "joe@example.com", INT64_C(2399662595), 0)); cl_git_pass(git_commit_tree(&tree, tip)); - cl_git_pass(git_commit_create(&id, _repo, "HEAD", sig, sig, NULL, "some message", tree, 1, - (const git_commit **)&tip)); + cl_git_pass(git_commit_create(&id, _repo, "HEAD", sig, sig, NULL, "some message", tree, 1, &tip)); cl_git_pass(git_revwalk_push_head(_walk)); From fddfca35267765feb23be26e8b402781e778225e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 15 Jan 2024 00:06:26 +0000 Subject: [PATCH 380/816] tests: add `cl_assert_equal_oidstr` helper method --- tests/clar/clar_libgit2.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/clar/clar_libgit2.h b/tests/clar/clar_libgit2.h index c33b5d28bed..d8105c841b4 100644 --- a/tests/clar/clar_libgit2.h +++ b/tests/clar/clar_libgit2.h @@ -166,10 +166,27 @@ GIT_INLINE(void) clar__assert_equal_oid( } } +GIT_INLINE(void) clar__assert_equal_oidstr( + const char *file, const char *func, int line, const char *desc, + const char *one_str, const git_oid *two) +{ + git_oid one; + + if (git_oid__fromstr(&one, one_str, git_oid_type(two)) < 0) { + clar__fail(file, func, line, desc, "could not parse oid string", 1); + } else { + clar__assert_equal_oid(file, func, line, desc, &one, two); + } +} + #define cl_assert_equal_oid(one, two) \ clar__assert_equal_oid(__FILE__, __func__, __LINE__, \ "OID mismatch: " #one " != " #two, (one), (two)) +#define cl_assert_equal_oidstr(one_str, two) \ + clar__assert_equal_oidstr(__FILE__, __func__, __LINE__, \ + "OID mismatch: " #one_str " != " #two, (one_str), (two)) + /* * Some utility macros for building long strings */ From 67a4d04b5984c3dab681b59f67f4255be8c38eef Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 15 Jan 2024 00:08:16 +0000 Subject: [PATCH 381/816] commit: introduce `git_commit_create_from_stage` Provide a simple helper method that allows users to create a commit from the current index with minimal information. --- include/git2/commit.h | 30 +++++++++ include/git2/errors.h | 3 +- src/libgit2/commit.c | 73 ++++++++++++++++++++++ tests/libgit2/commit/create.c | 112 ++++++++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 tests/libgit2/commit/create.c diff --git a/include/git2/commit.h b/include/git2/commit.h index ea0e94969a8..7d2740dc1dd 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -394,6 +394,36 @@ GIT_EXTERN(int) git_commit_create_v( size_t parent_count, ...); +typedef struct { + unsigned int version; + + unsigned int allow_empty_commit : 1; + + const git_signature *author; + const git_signature *committer; +} git_commit_create_options; + +#define GIT_COMMIT_CREATE_OPTIONS_VERSION 1 +#define GIT_COMMIT_CREATE_OPTIONS_INIT { GIT_COMMIT_CREATE_OPTIONS_VERSION } + +/** + * Commits the staged changes in the repository; this is a near analog to + * `git commit -m message`. + * + * By default, empty commits are not allowed. + * + * @param id pointer to store the new commit's object id + * @param repo repository to commit changes in + * @param message the commit message + * @param opts options for creating the commit + * @return 0 on success, GIT_EUNCHANGED if there were no changes to commit, or an error code + */ +GIT_EXTERN(int) git_commit_create_from_stage( + git_oid *id, + git_repository *repo, + const char *message, + const git_commit_create_options *opts); + /** * Amend an existing commit by replacing only non-NULL values. * diff --git a/include/git2/errors.h b/include/git2/errors.h index face0898a12..bdace8c43dd 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -59,7 +59,8 @@ typedef enum { GIT_EINDEXDIRTY = -34, /**< Unsaved changes in the index would be overwritten */ GIT_EAPPLYFAIL = -35, /**< Patch application failed */ GIT_EOWNER = -36, /**< The object is not owned by the current user */ - GIT_TIMEOUT = -37 /**< The operation timed out */ + GIT_TIMEOUT = -37, /**< The operation timed out */ + GIT_EUNCHANGED = -38 /**< There were no changes */ } git_error_code; /** diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 9e3b29a00b8..10257601579 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -1086,6 +1086,79 @@ int git_commit_create_with_signature( return error; } +int git_commit_create_from_stage( + git_oid *out, + git_repository *repo, + const char *message, + const git_commit_create_options *given_opts) +{ + git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT; + git_signature *default_signature = NULL; + const git_signature *author, *committer; + git_index *index = NULL; + git_diff *diff = NULL; + git_oid tree_id; + git_tree *head_tree = NULL, *tree = NULL; + git_commitarray parents = { 0 }; + int error = -1; + + GIT_ASSERT_ARG(out && repo); + + if (given_opts) + memcpy(&opts, given_opts, sizeof(git_commit_create_options)); + + if ((author = opts.author) == NULL || + (committer = opts.committer) == NULL) { + if (git_signature_default(&default_signature, repo) < 0) + goto done; + + if (!author) + author = default_signature; + + if (!committer) + committer = default_signature; + } + + if (git_repository_index(&index, repo) < 0) + goto done; + + if (!opts.allow_empty_commit) { + error = git_repository_head_tree(&head_tree, repo); + + if (error && error != GIT_EUNBORNBRANCH) + goto done; + + error = -1; + + if (git_diff_tree_to_index(&diff, repo, head_tree, index, NULL) < 0) + goto done; + + if (git_diff_num_deltas(diff) == 0) { + git_error_set(GIT_ERROR_REPOSITORY, + "no changes are staged for commit"); + error = GIT_EUNCHANGED; + goto done; + } + } + + if (git_index_write_tree(&tree_id, index) < 0 || + git_tree_lookup(&tree, repo, &tree_id) < 0 || + git_repository_commit_parents(&parents, repo) < 0) + goto done; + + error = git_commit_create(out, repo, "HEAD", author, committer, + NULL, message, tree, parents.count, parents.commits); + +done: + git_commitarray_dispose(&parents); + git_signature_free(default_signature); + git_tree_free(tree); + git_tree_free(head_tree); + git_diff_free(diff); + git_index_free(index); + return error; +} + int git_commit_committer_with_mailmap( git_signature **out, const git_commit *commit, const git_mailmap *mailmap) { diff --git a/tests/libgit2/commit/create.c b/tests/libgit2/commit/create.c new file mode 100644 index 00000000000..9f627dc87b5 --- /dev/null +++ b/tests/libgit2/commit/create.c @@ -0,0 +1,112 @@ +#include "clar_libgit2.h" +#include "repository.h" + +/* Fixture setup */ +static git_repository *g_repo; +static git_signature *g_author, *g_committer; + +void test_commit_create__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo2"); + cl_git_pass(git_signature_new(&g_author, "Edward Thomson", "ethomson@edwardthomson.com", 123456789, 60)); + cl_git_pass(git_signature_new(&g_committer, "libgit2 user", "nobody@noreply.libgit2.org", 987654321, 90)); +} + +void test_commit_create__cleanup(void) +{ + git_signature_free(g_committer); + git_signature_free(g_author); + cl_git_sandbox_cleanup(); +} + + +void test_commit_create__from_stage_simple(void) +{ + git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT; + git_index *index; + git_oid commit_id; + git_tree *tree; + + opts.author = g_author; + opts.committer = g_committer; + + cl_git_rewritefile("testrepo2/newfile.txt", "This is a new file.\n"); + cl_git_rewritefile("testrepo2/newfile2.txt", "This is a new file.\n"); + cl_git_rewritefile("testrepo2/README", "hello, world.\n"); + cl_git_rewritefile("testrepo2/new.txt", "hi there.\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "newfile2.txt")); + cl_git_pass(git_index_add_bypath(index, "README")); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_commit_create_from_stage(&commit_id, g_repo, "This is the message.", &opts)); + + cl_git_pass(git_repository_head_tree(&tree, g_repo)); + + cl_assert_equal_oidstr("241b5b04e847bc38dd7b4b9f49f21e55da40f3a6", &commit_id); + cl_assert_equal_oidstr("b27210772d0633870b4f486d04ed3eb5ebbef5e7", git_tree_id(tree)); + + git_index_free(index); + git_tree_free(tree); +} + +void test_commit_create__from_stage_nochanges(void) +{ + git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT; + git_oid commit_id; + git_tree *tree; + + opts.author = g_author; + opts.committer = g_committer; + + cl_git_fail_with(GIT_EUNCHANGED, git_commit_create_from_stage(&commit_id, g_repo, "Message goes here.", &opts)); + + opts.allow_empty_commit = 1; + + cl_git_pass(git_commit_create_from_stage(&commit_id, g_repo, "Message goes here.", &opts)); + + cl_git_pass(git_repository_head_tree(&tree, g_repo)); + + cl_assert_equal_oidstr("f776dc4c7fd8164b7127dc8e4f9b44421cb01b56", &commit_id); + cl_assert_equal_oidstr("c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", git_tree_id(tree)); + + git_tree_free(tree); +} + +void test_commit_create__from_stage_newrepo(void) +{ + git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT; + git_repository *newrepo; + git_index *index; + git_commit *commit; + git_tree *tree; + git_oid commit_id; + + opts.author = g_author; + opts.committer = g_committer; + + git_repository_init(&newrepo, "newrepo", false); + cl_git_pass(git_repository_index(&index, newrepo)); + + cl_git_rewritefile("newrepo/hello.txt", "hello, world.\n"); + cl_git_rewritefile("newrepo/hi.txt", "hi there.\n"); + cl_git_rewritefile("newrepo/foo.txt", "bar.\n"); + + cl_git_pass(git_index_add_bypath(index, "hello.txt")); + cl_git_pass(git_index_add_bypath(index, "foo.txt")); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_commit_create_from_stage(&commit_id, newrepo, "Initial commit.", &opts)); + cl_git_pass(git_repository_head_commit(&commit, newrepo)); + cl_git_pass(git_repository_head_tree(&tree, newrepo)); + + cl_assert_equal_oid(&commit_id, git_commit_id(commit)); + cl_assert_equal_oidstr("b2fa96a4f191c76eb172437281c66aa29609dcaa", git_commit_tree_id(commit)); + + git_tree_free(tree); + git_commit_free(commit); + git_index_free(index); + git_repository_free(newrepo); + cl_fixture_cleanup("newrepo"); +} From 55381816e83c268651e5adfd4314c724be75ef27 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 15 Jan 2024 15:52:35 +0000 Subject: [PATCH 382/816] commit: support specifying encoding for message --- include/git2/commit.h | 13 +++++++++++++ src/libgit2/commit.c | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/git2/commit.h b/include/git2/commit.h index 7d2740dc1dd..ef38c66e6cc 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -397,10 +397,23 @@ GIT_EXTERN(int) git_commit_create_v( typedef struct { unsigned int version; + /** + * Flags for creating the commit. + * + * If `allow_empty_commit` is specified, a commit with no changes + * from the prior commit (and "empty" commit) is allowed. Otherwise, + * commit creation will be stopped. + */ unsigned int allow_empty_commit : 1; + /** The commit author, or NULL for the default. */ const git_signature *author; + + /** The committer, or NULL for the default. */ const git_signature *committer; + + /** Encoding for the commit message; leave NULL for default. */ + const char *message_encoding; } git_commit_create_options; #define GIT_COMMIT_CREATE_OPTIONS_VERSION 1 diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 10257601579..5582a65aadf 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -1147,7 +1147,8 @@ int git_commit_create_from_stage( goto done; error = git_commit_create(out, repo, "HEAD", author, committer, - NULL, message, tree, parents.count, parents.commits); + opts.message_encoding, message, + tree, parents.count, parents.commits); done: git_commitarray_dispose(&parents); From 216f698eb2e22ca5d6fbd58f60f6481a4e994934 Mon Sep 17 00:00:00 2001 From: Gregory Herrero Date: Mon, 15 Jan 2024 14:14:39 +0100 Subject: [PATCH 383/816] merge: fix incorrect rename detection for empty files. When merging trees containing multiple empty files, make sure a rename is not detected between each empty files. For example Ancestor has files: * foo.c with content * bar.c empty Ours has: * foo.c with content * boo.c empty Theirs has: * foo.c with other content * bar.c with content merge_trees() will incorrectly apply the content of theirs's 'bar.c' in ours's boo.c' thinking 'bar.c' has been renamed to 'boo.c'. This happens because both are empty and their sha1 are the same. Thus merge_diff_mark_similarity_exact() incorrectly mark it as renamed. Signed-off-by: Gregory Herrero --- src/libgit2/merge.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 0114e4b75a0..21e5ef6a8f9 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -1225,6 +1225,13 @@ static int merge_diff_mark_similarity_exact( if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry)) continue; + /* + * Ignore empty files because it has always the same blob sha1 + * and will lead to incorrect matches between all entries. + */ + if (git_oid_equal(&conflict_src->ancestor_entry.id, &git_oid__empty_blob_sha1)) + continue; + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { error = deletes_by_oid_enqueue(ours_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); if (error < 0) From 334dd8da93cb80c353fb3b363bfb730383f09fb8 Mon Sep 17 00:00:00 2001 From: Gregory Herrero Date: Mon, 15 Jan 2024 15:52:44 +0100 Subject: [PATCH 384/816] tests: merge: tree: add support for different ancestor. Add a boolean option to merge_trivial() so that it can use theirs parent instead of merge base as ancestor. This will be needed in the following commit. Signed-off-by: Gregory Herrero --- tests/libgit2/merge/trees/trivial.c | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/tests/libgit2/merge/trees/trivial.c b/tests/libgit2/merge/trees/trivial.c index 287a53cfe7a..becd618d358 100644 --- a/tests/libgit2/merge/trees/trivial.c +++ b/tests/libgit2/merge/trees/trivial.c @@ -25,7 +25,7 @@ void test_merge_trees_trivial__cleanup(void) } -static int merge_trivial(git_index **index, const char *ours, const char *theirs) +static int merge_trivial(git_index **index, const char *ours, const char *theirs, bool ancestor_use_parent) { git_commit *our_commit, *their_commit, *ancestor_commit; git_tree *our_tree, *their_tree, *ancestor_tree; @@ -42,8 +42,12 @@ static int merge_trivial(git_index **index, const char *ours, const char *theirs cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); - cl_git_pass(git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))); - cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); + if (!ancestor_use_parent) { + cl_git_pass(git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))); + cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); + } else { + cl_git_pass(git_commit_parent(&ancestor_commit, their_commit, 0)); + } cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); cl_git_pass(git_commit_tree(&our_tree, our_commit)); @@ -84,7 +88,7 @@ void test_merge_trees_trivial__2alt(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch")); + cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch", false)); cl_assert(entry = git_index_get_bypath(result, "new-in-branch.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -99,7 +103,7 @@ void test_merge_trees_trivial__3alt(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch")); + cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch", false)); cl_assert(entry = git_index_get_bypath(result, "new-in-3alt.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -114,7 +118,7 @@ void test_merge_trees_trivial__4(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch")); + cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch", false)); cl_assert((entry = git_index_get_bypath(result, "new-and-different.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -132,7 +136,7 @@ void test_merge_trees_trivial__5alt_1(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch")); + cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch", false)); cl_assert(entry = git_index_get_bypath(result, "new-and-same.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -147,7 +151,7 @@ void test_merge_trees_trivial__5alt_2(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch")); + cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch", false)); cl_assert(entry = git_index_get_bypath(result, "modified-to-same.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -163,7 +167,7 @@ void test_merge_trees_trivial__6(void) const git_index_entry *entry; const git_index_reuc_entry *reuc; - cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch")); + cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", false)); cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 1); @@ -181,7 +185,7 @@ void test_merge_trees_trivial__8(void) const git_index_entry *entry; const git_index_reuc_entry *reuc; - cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch")); + cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", false)); cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); @@ -199,7 +203,7 @@ void test_merge_trees_trivial__7(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch")); + cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", false)); cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -218,7 +222,7 @@ void test_merge_trees_trivial__10(void) const git_index_entry *entry; const git_index_reuc_entry *reuc; - cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch")); + cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", false)); cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); @@ -236,7 +240,7 @@ void test_merge_trees_trivial__9(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch")); + cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", false)); cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -255,7 +259,7 @@ void test_merge_trees_trivial__13(void) const git_index_entry *entry; git_oid expected_oid; - cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch")); + cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch", false)); cl_assert(entry = git_index_get_bypath(result, "modified-in-13.txt", 0)); cl_git_pass(git_oid__fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b", GIT_OID_SHA1)); @@ -274,7 +278,7 @@ void test_merge_trees_trivial__14(void) const git_index_entry *entry; git_oid expected_oid; - cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch")); + cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch", false)); cl_assert(entry = git_index_get_bypath(result, "modified-in-14-branch.txt", 0)); cl_git_pass(git_oid__fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9", GIT_OID_SHA1)); @@ -292,7 +296,7 @@ void test_merge_trees_trivial__11(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch")); + cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch", false)); cl_assert((entry = git_index_get_bypath(result, "modified-in-both.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); From 16688efa412208d0ed6d90d24ae632abda9c8a4d Mon Sep 17 00:00:00 2001 From: Gregory Herrero Date: Mon, 15 Jan 2024 15:46:00 +0100 Subject: [PATCH 385/816] tests: merge: tree: detect incorrect renames. This test follow "merge: fix incorrect rename detection for empty files." commit. Signed-off-by: Gregory Herrero --- tests/libgit2/merge/trees/trivial.c | 19 ++++++++++++++++++ .../.gitted/logs/refs/heads/trivial-15 | 1 + .../.gitted/logs/refs/heads/trivial-15-branch | 2 ++ .../1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 | Bin 0 -> 279 bytes .../48/320305de02310b9c4fd744243b9b0d1d5f11af | Bin 0 -> 46 bytes .../67/06996f054c6af4fec7c77939d00e2f486dab4c | Bin 0 -> 172 bytes .../c0/d1f321977d1c18e23a28c581fed6d17d0cc013 | Bin 0 -> 273 bytes .../c4/52c5eb5aacf204fc95a55d1eb9668736fecfb6 | Bin 0 -> 163 bytes .../c5/be2acabac675af81df8bb70400235af2a9c225 | 4 ++++ .../cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 | Bin 0 -> 280 bytes .../.gitted/refs/heads/trivial-15 | 1 + .../.gitted/refs/heads/trivial-15-branch | 1 + 12 files changed, 28 insertions(+) create mode 100644 tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 create mode 100644 tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch create mode 100644 tests/resources/merge-resolve/.gitted/objects/1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 create mode 100644 tests/resources/merge-resolve/.gitted/objects/48/320305de02310b9c4fd744243b9b0d1d5f11af create mode 100644 tests/resources/merge-resolve/.gitted/objects/67/06996f054c6af4fec7c77939d00e2f486dab4c create mode 100644 tests/resources/merge-resolve/.gitted/objects/c0/d1f321977d1c18e23a28c581fed6d17d0cc013 create mode 100644 tests/resources/merge-resolve/.gitted/objects/c4/52c5eb5aacf204fc95a55d1eb9668736fecfb6 create mode 100644 tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 create mode 100644 tests/resources/merge-resolve/.gitted/objects/cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 create mode 100644 tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 create mode 100644 tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch diff --git a/tests/libgit2/merge/trees/trivial.c b/tests/libgit2/merge/trees/trivial.c index becd618d358..7f9d918e806 100644 --- a/tests/libgit2/merge/trees/trivial.c +++ b/tests/libgit2/merge/trees/trivial.c @@ -308,3 +308,22 @@ void test_merge_trees_trivial__11(void) git_index_free(result); } + +/* 15: ancest:remote^, head:head, remote:remote = result:no merge */ +void test_merge_trees_trivial__15(void) +{ + git_index *result; + const git_index_entry *entry; + + /* Can't use merge_trivialfalsehere because a different ancestor is used. */ + cl_git_pass(merge_trivial(&result, "trivial-15", "trivial-15-branch", true)); + + cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_NORMAL)) == NULL); + cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_ANCESTOR))); + cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_OURS)) == NULL); + cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_THEIRS))); + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + + git_index_free(result); +} + diff --git a/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 b/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 new file mode 100644 index 00000000000..c71411b5f11 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 c452c5eb5aacf204fc95a55d1eb9668736fecfb6 Gregory Herrero 1705326305 +0100 push diff --git a/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch b/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch new file mode 100644 index 00000000000..f85a1e96dd9 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 6706996f054c6af4fec7c77939d00e2f486dab4c Gregory Herrero 1705326302 +0100 push +6706996f054c6af4fec7c77939d00e2f486dab4c c5be2acabac675af81df8bb70400235af2a9c225 Gregory Herrero 1705326412 +0100 push diff --git a/tests/resources/merge-resolve/.gitted/objects/1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 b/tests/resources/merge-resolve/.gitted/objects/1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 new file mode 100644 index 0000000000000000000000000000000000000000..ec618090bdf04fd36e456a413c316a3e8ab4dca1 GIT binary patch literal 279 zcmV+y0qFjC0V^p=O;s>9H)k+3FfcPQQAo_oFUd$P(#=aP*G|#Ju#>6y3}`-K3(#yyOh9hSfPPi(a@)TI=n&J9|yLsoh+rHQksRaubV7 zQi}*`$j?j5$xJTE%u5F=y`uhL(?g2@DO=Gq<_YDCljTJBx*O7ai1V#(6;Mw#=Y#jm>Q5A6JwpRT>i+fSTp_0?Qy}vHCa*HmqIm^0(}VfFxV+4 dKIH3JZ<^*#A Cyb`|v literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/67/06996f054c6af4fec7c77939d00e2f486dab4c b/tests/resources/merge-resolve/.gitted/objects/67/06996f054c6af4fec7c77939d00e2f486dab4c new file mode 100644 index 0000000000000000000000000000000000000000..92ddbf0be101a048e8e819dac29dfdc5a4305659 GIT binary patch literal 172 zcmV;d08{^X0j17OY6CG0hT*P#3h&Ddl08yf2%)?78n&$YflOS46Ugl|kRx>a@bd9V z+xM;eK=jc~)l01?6+$f)dD5?nDf2WDQjs8;iEzePCij<3Z`}*SX_g2nMU9cF&LK(V z#N`NC<_w_#tGImcYcv02x-@(GUo}%}{=B?lT;K5BEX!3#Y5T?F2`B~*0sSW+fIIYf a+x5RYuG{w5@^wHOishTEqk91!2~$WI3Rb58 literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/c0/d1f321977d1c18e23a28c581fed6d17d0cc013 b/tests/resources/merge-resolve/.gitted/objects/c0/d1f321977d1c18e23a28c581fed6d17d0cc013 new file mode 100644 index 0000000000000000000000000000000000000000..4c20a212ade60c6f8046f0f5384bb06e145ce014 GIT binary patch literal 273 zcmV+s0q*{I0V^p=O;s>9vt%$dFfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRUTV2+ zYHmSErLLhVSnad9k7jSWc+J_nTXS7`)Qv+=dV(iH)fT1Z=9ghO{Ql!l+N8 zkTGc6^*G~R_FYU3NDhy&&R8ygh_N7J5=Yr3_6e($P%su?1|;*!D$i~?K&(uV5($wnQkS}f6h@CV zaLwRG2*M`6`@N~XsN9-NRjNr)yB(hsT0JG@ww#&ae Rrt9>X@?(d7Fh7HwP+9wjOc4M8 literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 b/tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 new file mode 100644 index 00000000000..848f341c929 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 @@ -0,0 +1,4 @@ +xAj1 @Ѭ} +CyFc(%,g2qno G->_o1P3 +ȒT +Qb*{}xJ@9SBܰ$I)/L 㟱v_n[Ժ`Z_prIC̄@=y;ݎn|;x*wY'IS \ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/objects/cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 b/tests/resources/merge-resolve/.gitted/objects/cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 new file mode 100644 index 0000000000000000000000000000000000000000..d2385b8f2353863209a288ba2cd3edc4ef04cfad GIT binary patch literal 280 zcmV+z0q6dB0V^p=O;s>9H)k+3FfcPQQAo_oFUd$P(#=aP*GO{^L*D ztK{>~g}6_UF=*TMIOAUST}%x~j)}3(ST29$SFD--<@UH>;hLAL e6Cd*RtT#<_EJ?4M_+j;{3r}q3#R3319++g`S&~%% literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 b/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 new file mode 100644 index 00000000000..d6149eb8131 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 @@ -0,0 +1 @@ +c452c5eb5aacf204fc95a55d1eb9668736fecfb6 diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch b/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch new file mode 100644 index 00000000000..a255d1a3a95 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch @@ -0,0 +1 @@ +c5be2acabac675af81df8bb70400235af2a9c225 From 392e380463f23981f52fbc0cae53721234984fbf Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 18 Jan 2024 23:13:14 -0500 Subject: [PATCH 386/816] set SSH timeout --- include/git2/common.h | 3 +-- src/libgit2/transports/ssh_libssh2.c | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index ab6bc1333b3..7736a0af9fc 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -490,8 +490,7 @@ typedef enum { * * opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, int timeout) * > Sets the timeout (in milliseconds) to attempt connections to - * > a remote server. This is supported only for HTTP(S) connections - * > and is not supported by SSH. Set to 0 to use the system default. + * > a remote server. Set to 0 to use the system default. * > Note that this may not be able to be configured longer than the * > system default, typically 75 seconds. * diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index d2be2ba3387..89f341f2108 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -23,6 +23,8 @@ #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) +extern int git_socket_stream__connect_timeout; + static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; @@ -539,6 +541,10 @@ static int _git_ssh_session_create( return -1; } + if (git_socket_stream__connect_timeout > 0) { + libssh2_session_set_timeout(s, git_socket_stream__connect_timeout); + } + if ((rc = load_known_hosts(&known_hosts, s)) < 0) { ssh_error(s, "error loading known_hosts"); libssh2_session_free(s); From 7f1d52067a4ecb5cacdff07f3563c400f497235a Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 22 Jan 2024 20:09:26 +0100 Subject: [PATCH 387/816] config: properly rename section containing multivars Renaming a section or deleting its content removes each entry after copying it in its new place if needed. However, since each entry may be part of a multivar, deletion must only remove the exact entry that has just been copied. --- src/libgit2/config.c | 29 ++++++++++++++++++++------ tests/libgit2/config/multivar.c | 31 ++++++++++++++++++++++++++++ tests/libgit2/refs/branches/delete.c | 15 ++++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 23a8f9ffad1..d11e76d9577 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -1509,19 +1509,36 @@ static int rename_config_entries_cb( int error = 0; struct rename_data *data = (struct rename_data *)payload; size_t base_len = git_str_len(data->name); + git_str raw_value = GIT_STR_INIT, value = GIT_STR_INIT; if (base_len > 0 && !(error = git_str_puts(data->name, entry->name + data->old_len))) { - error = git_config_set_string( - data->config, git_str_cstr(data->name), entry->value); - - git_str_truncate(data->name, base_len); + error = git_config_set_multivar( + data->config, git_str_cstr(data->name), "^$", + entry->value); } - if (!error) - error = git_config_delete_entry(data->config, entry->name); + if (!error) { + if ((error = git_str_puts_escape_regex( + &raw_value, entry->value))) + goto cleanup; + git_str_grow(&value, git_str_len(&raw_value) + 2); + git_str_putc(&value, '^'); + git_str_puts(&value, git_str_cstr(&raw_value)); + git_str_putc(&value, '$'); + if (git_str_oom(&value)) { + error = -1; + goto cleanup; + } + error = git_config_delete_multivar( + data->config, entry->name, git_str_cstr(&value)); + } + cleanup: + git_str_truncate(data->name, base_len); + git_str_dispose(&raw_value); + git_str_dispose(&value); return error; } diff --git a/tests/libgit2/config/multivar.c b/tests/libgit2/config/multivar.c index 244e3755965..3ed846012fa 100644 --- a/tests/libgit2/config/multivar.c +++ b/tests/libgit2/config/multivar.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "config.h" +#include "config/config_helpers.h" static const char *_name = "remote.ab.url"; @@ -286,3 +288,32 @@ void test_config_multivar__delete_notfound(void) git_config_free(cfg); } + +void test_config_multivar__rename_section(void) +{ + git_repository *repo; + git_config *cfg; + int n; + + repo = cl_git_sandbox_init("testrepo"); + cl_git_pass(git_repository_config(&cfg, repo)); + + cl_git_pass(git_config_set_multivar(cfg, "branch.foo.name", "^$", "bar")); + cl_git_pass(git_config_set_multivar(cfg, "branch.foo.name", "^$", "xyzzy")); + n = 0; + cl_git_pass(git_config_get_multivar_foreach( + cfg, "branch.foo.name", NULL, cb, &n)); + cl_assert(n == 2); + + cl_git_pass( + git_config_rename_section(repo, "branch.foo", "branch.foobar")); + + assert_config_entry_existence(repo, "branch.foo.name", false); + n = 0; + cl_git_pass(git_config_get_multivar_foreach( + cfg, "branch.foobar.name", NULL, cb, &n)); + cl_assert(n == 2); + + git_config_free(cfg); + cl_git_sandbox_cleanup(); +} diff --git a/tests/libgit2/refs/branches/delete.c b/tests/libgit2/refs/branches/delete.c index 6b3d507a869..63f8c5d95c7 100644 --- a/tests/libgit2/refs/branches/delete.c +++ b/tests/libgit2/refs/branches/delete.c @@ -92,6 +92,21 @@ void test_refs_branches_delete__can_delete_a_local_branch(void) git_reference_free(branch); } +void test_refs_branches_delete__can_delete_a_local_branch_with_multivar(void) +{ + git_reference *branch; + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, repo)); + cl_git_pass(git_config_set_multivar( + cfg, "branch.br2.gitpublishto", "^$", "example1@example.com")); + cl_git_pass(git_config_set_multivar( + cfg, "branch.br2.gitpublishto", "^$", "example2@example.com")); + cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_delete(branch)); + git_reference_free(branch); +} + void test_refs_branches_delete__can_delete_a_remote_branch(void) { git_reference *branch; From 7be7c0c0e01aae938f2aaf78f22f20fc1b7a7763 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 26 Jan 2024 13:37:23 -0500 Subject: [PATCH 388/816] use git_socket_stream__timeout --- include/git2/common.h | 7 +++---- src/libgit2/transports/ssh_libssh2.c | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 7736a0af9fc..140dd95610b 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -490,7 +490,8 @@ typedef enum { * * opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, int timeout) * > Sets the timeout (in milliseconds) to attempt connections to - * > a remote server. Set to 0 to use the system default. + * > a remote server. This is supported only for HTTP(S) connections + * > and is not supported by SSH. Set to 0 to use the system default. * > Note that this may not be able to be configured longer than the * > system default, typically 75 seconds. * @@ -500,9 +501,7 @@ typedef enum { * * opts(GIT_OPT_SET_SERVER_TIMEOUT, int timeout) * > Sets the timeout (in milliseconds) for reading from and writing - * > to a remote server. This is supported only for HTTP(S) - * > connections and is not supported by SSH. Set to 0 to use the - * > system default. + * > to a remote server. Set to 0 to use the system default. * * @param option Option key * @param ... value to set the option diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index 89f341f2108..d1b5d40d51f 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -23,7 +23,7 @@ #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) -extern int git_socket_stream__connect_timeout; +extern int git_socket_stream__timeout; static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; @@ -541,8 +541,8 @@ static int _git_ssh_session_create( return -1; } - if (git_socket_stream__connect_timeout > 0) { - libssh2_session_set_timeout(s, git_socket_stream__connect_timeout); + if (git_socket_stream__timeout > 0) { + libssh2_session_set_timeout(s, git_socket_stream__timeout); } if ((rc = load_known_hosts(&known_hosts, s)) < 0) { From ca864c59141fef29781fcd1a0eb0eed2b5d7fa68 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 4 Feb 2024 14:40:47 +0000 Subject: [PATCH 389/816] clone: don't swallow error in should_checkout When determining whether to check out a branch, we did not actually look at `should_checkout`'s possible error condition. Disconnect the boolean "should checkout" value from the potential error code so that it no longer looks like a function that can be treated as if it returns a boolean. --- src/libgit2/clone.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index 3df28f80aed..db9a898e34e 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -362,25 +362,29 @@ static int create_and_configure_origin( return error; } -static bool should_checkout( +static int should_checkout( + bool *out, git_repository *repo, bool is_bare, const git_checkout_options *opts) { - if (is_bare) - return false; + int error; - if (!opts) - return false; + if (!opts || is_bare || opts->checkout_strategy == GIT_CHECKOUT_NONE) { + *out = 0; + return 0; + } - if (opts->checkout_strategy == GIT_CHECKOUT_NONE) - return false; + if ((error = git_repository_head_unborn(repo)) < 0) + return error; - return !git_repository_head_unborn(repo); + *out = !error; + return 0; } static int checkout_branch(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, const char *reflog_message) { + bool checkout; int error; if (branch) @@ -389,7 +393,13 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c else error = update_head_to_remote(repo, remote, reflog_message); - if (!error && should_checkout(repo, git_repository_is_bare(repo), co_opts)) + if (error < 0) + return error; + + if ((error = should_checkout(&checkout, repo, git_repository_is_bare(repo), co_opts)) < 0) + return error; + + if (checkout) error = git_checkout_head(repo, co_opts); return error; From c3dc87b0c80eb4f885ba1781eed7a029c0e1e53a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 5 Feb 2024 10:16:17 +0000 Subject: [PATCH 390/816] docs: update documentation for timeout The connect timeout *does* apply to SSH connections (at least libssh2), so update the documentation appropriately. --- include/git2/common.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 140dd95610b..0f42c34f683 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -490,10 +490,9 @@ typedef enum { * * opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, int timeout) * > Sets the timeout (in milliseconds) to attempt connections to - * > a remote server. This is supported only for HTTP(S) connections - * > and is not supported by SSH. Set to 0 to use the system default. - * > Note that this may not be able to be configured longer than the - * > system default, typically 75 seconds. + * > a remote server. Set to 0 to use the system default. Note that + * > this may not be able to be configured longer than the system + * > default, typically 75 seconds. * * opts(GIT_OPT_GET_SERVER_TIMEOUT, int *timeout) * > Gets the timeout (in milliseconds) for reading from and writing From 8bd69574bdfba221a365c3d40713e6d13463ae79 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Nov 2023 10:29:08 +0000 Subject: [PATCH 391/816] fuzzers: provide util functions like repo init Many fuzzers will need to operate with a repository; extract the repository initialization from downloads_refs_fuzzer.c into its own utility area. --- fuzzers/CMakeLists.txt | 5 +++- fuzzers/download_refs_fuzzer.c | 35 +++-------------------- fuzzers/fuzzer_utils.c | 51 ++++++++++++++++++++++++++++++++++ fuzzers/fuzzer_utils.h | 14 ++++++++++ 4 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 fuzzers/fuzzer_utils.c create mode 100644 fuzzers/fuzzer_utils.h diff --git a/fuzzers/CMakeLists.txt b/fuzzers/CMakeLists.txt index a2c19ed408a..01f0f51997f 100644 --- a/fuzzers/CMakeLists.txt +++ b/fuzzers/CMakeLists.txt @@ -12,10 +12,13 @@ foreach(fuzz_target_src ${SRC_FUZZERS}) string(REPLACE ".c" "" fuzz_target_name ${fuzz_target_src}) string(REPLACE "_fuzzer" "" fuzz_name ${fuzz_target_name}) - set(${fuzz_target_name}_SOURCES ${fuzz_target_src} ${LIBGIT2_OBJECTS}) + set(${fuzz_target_name}_SOURCES + ${fuzz_target_src} "fuzzer_utils.c" ${LIBGIT2_OBJECTS}) + if(USE_STANDALONE_FUZZERS) list(APPEND ${fuzz_target_name}_SOURCES "standalone_driver.c") endif() + add_executable(${fuzz_target_name} ${${fuzz_target_name}_SOURCES}) set_target_properties(${fuzz_target_name} PROPERTIES C_STANDARD 90) diff --git a/fuzzers/download_refs_fuzzer.c b/fuzzers/download_refs_fuzzer.c index ff95cd107ef..c2b80ccb1f2 100644 --- a/fuzzers/download_refs_fuzzer.c +++ b/fuzzers/download_refs_fuzzer.c @@ -16,6 +16,7 @@ #include "futils.h" #include "standalone_driver.h" +#include "fuzzer_utils.h" #define UNUSED(x) (void)(x) @@ -157,33 +158,10 @@ static int fuzzer_transport_cb(git_transport **out, git_remote *owner, void *par return git_transport_smart(out, owner, &def); } -static void fuzzer_git_abort(const char *op) -{ - const git_error *err = git_error_last(); - fprintf(stderr, "unexpected libgit error: %s: %s\n", - op, err ? err->message : ""); - abort(); -} - int LLVMFuzzerInitialize(int *argc, char ***argv) { -#if defined(_WIN32) - char tmpdir[MAX_PATH], path[MAX_PATH]; - - if (GetTempPath((DWORD)sizeof(tmpdir), tmpdir) == 0) - abort(); - - if (GetTempFileName(tmpdir, "lg2", 1, path) == 0) - abort(); - - if (git_futils_mkdir(path, 0700, 0) < 0) - abort(); -#else - char path[] = "/tmp/git2.XXXXXX"; - - if (mkdtemp(path) != path) - abort(); -#endif + UNUSED(argc); + UNUSED(argv); if (git_libgit2_init() < 0) abort(); @@ -191,12 +169,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0) abort(); - UNUSED(argc); - UNUSED(argv); - - if (git_repository_init(&repo, path, 1) < 0) - fuzzer_git_abort("git_repository_init"); - + repo = fuzzer_repo_init(); return 0; } diff --git a/fuzzers/fuzzer_utils.c b/fuzzers/fuzzer_utils.c new file mode 100644 index 00000000000..cde5065da03 --- /dev/null +++ b/fuzzers/fuzzer_utils.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include + +#include "git2.h" +#include "futils.h" + +#include "fuzzer_utils.h" + +void fuzzer_git_abort(const char *op) +{ + const git_error *err = git_error_last(); + fprintf(stderr, "unexpected libgit error: %s: %s\n", + op, err ? err->message : ""); + abort(); +} + +git_repository *fuzzer_repo_init(void) +{ + git_repository *repo; + +#if defined(_WIN32) + char tmpdir[MAX_PATH], path[MAX_PATH]; + + if (GetTempPath((DWORD)sizeof(tmpdir), tmpdir) == 0) + abort(); + + if (GetTempFileName(tmpdir, "lg2", 1, path) == 0) + abort(); + + if (git_futils_mkdir(path, 0700, 0) < 0) + abort(); +#else + char path[] = "/tmp/git2.XXXXXX"; + + if (mkdtemp(path) != path) + abort(); +#endif + + if (git_repository_init(&repo, path, 1) < 0) + fuzzer_git_abort("git_repository_init"); + + return repo; +} diff --git a/fuzzers/fuzzer_utils.h b/fuzzers/fuzzer_utils.h new file mode 100644 index 00000000000..6b67c9a611d --- /dev/null +++ b/fuzzers/fuzzer_utils.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_fuzzer_utils_h__ +#define INCLUDE_fuzzer_utils_h__ + +extern void fuzzer_git_abort(const char *op); +extern git_repository *fuzzer_repo_init(void); + +#endif From f015996fe3bd61819f3f3ddd85effbeb451ebfac Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Nov 2023 10:29:56 +0000 Subject: [PATCH 392/816] fuzzer: add a revparse fuzzer --- fuzzers/corpora/revparse/head | 1 + fuzzers/corpora/revparse/revat | 1 + fuzzers/revparse_fuzzer.c | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 fuzzers/corpora/revparse/head create mode 100644 fuzzers/corpora/revparse/revat create mode 100644 fuzzers/revparse_fuzzer.c diff --git a/fuzzers/corpora/revparse/head b/fuzzers/corpora/revparse/head new file mode 100644 index 00000000000..e5517e4c5b4 --- /dev/null +++ b/fuzzers/corpora/revparse/head @@ -0,0 +1 @@ +HEAD \ No newline at end of file diff --git a/fuzzers/corpora/revparse/revat b/fuzzers/corpora/revparse/revat new file mode 100644 index 00000000000..382ffc0ba32 --- /dev/null +++ b/fuzzers/corpora/revparse/revat @@ -0,0 +1 @@ +xxxxxxxxxxxxxxxx@ \ No newline at end of file diff --git a/fuzzers/revparse_fuzzer.c b/fuzzers/revparse_fuzzer.c new file mode 100644 index 00000000000..37c22e2221c --- /dev/null +++ b/fuzzers/revparse_fuzzer.c @@ -0,0 +1,52 @@ +/* + * libgit2 revparse fuzzer target. + * + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include + +#include "git2.h" + +#include "standalone_driver.h" +#include "fuzzer_utils.h" + +#define UNUSED(x) (void)(x) + +static git_repository *repo; + +int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + UNUSED(argc); + UNUSED(argv); + + if (git_libgit2_init() < 0) + abort(); + + if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0) + abort(); + + repo = fuzzer_repo_init(); + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + git_object *obj = NULL; + char *c; + + if ((c = calloc(1, size + 1)) == NULL) + abort(); + + memcpy(c, data, size); + + git_revparse_single(&obj, repo, c); + git_object_free(obj); + free(c); + + return 0; +} From cef060a4f2626362f66d1b1b9d30d82bc3f30d92 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Nov 2023 10:52:19 +0000 Subject: [PATCH 393/816] fuzzer: run address sanitization during fuzzing --- .github/workflows/main.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f6a087b89b2..accb042e463 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -137,6 +137,20 @@ jobs: ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 os: ubuntu-latest + - name: "Sanitizer (Address)" + id: sanitizer-address + container: + name: noble + env: + CC: clang + CFLAGS: -fsanitize=address -ggdb -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 + os: ubuntu-latest - name: "Sanitizer (UndefinedBehavior)" id: sanitizer-ub os: ubuntu-latest From d41d32188106a60beeec87be6d398804bcae9785 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Nov 2023 16:25:06 +0000 Subject: [PATCH 394/816] transport: safely handle messages with no caps If there are no caps, don't try to advance past the first NULL to look for object-format. This prevents a possible out-of-bounds read. --- src/libgit2/transports/smart_pkt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 7805f332377..3307acfa08e 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -232,7 +232,8 @@ static int set_data( GIT_ASSERT_ARG(data); - if ((caps = memchr(line, '\0', len)) != NULL) { + if ((caps = memchr(line, '\0', len)) != NULL && + len > (size_t)((caps - line) + 1)) { caps++; if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0) From d353cf4897c719a6e4bd7183747cb8e88ee0481d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Nov 2023 16:54:47 +0000 Subject: [PATCH 395/816] revparse: fix parsing bug for trailing `@` When parsing a revspec that ends with a trailing `@`, explicitly stop parsing. Introduce a sentinel variable to explicitly stop parsing. Prior to this, we would set `spec` to `HEAD`, but were looping on the value of `spec[pos]`, so we would continue walking the (new) `spec` at offset `pos`, looking for a NUL. This is obviously an out-of-bounds read. Credit to Michael Rodler (@f0rki) and Amazon AWS Security. --- src/libgit2/revparse.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libgit2/revparse.c b/src/libgit2/revparse.c index 964afe378da..06d92f82bf2 100644 --- a/src/libgit2/revparse.c +++ b/src/libgit2/revparse.c @@ -701,6 +701,7 @@ static int revparse( git_object *base_rev = NULL; bool should_return_reference = true; + bool parsed = false; GIT_ASSERT_ARG(object_out); GIT_ASSERT_ARG(reference_out); @@ -710,7 +711,7 @@ static int revparse( *object_out = NULL; *reference_out = NULL; - while (spec[pos]) { + while (!parsed && spec[pos]) { switch (spec[pos]) { case '^': should_return_reference = false; @@ -817,6 +818,8 @@ static int revparse( break; } else if (spec[pos+1] == '\0') { spec = "HEAD"; + identifier_len = 4; + parsed = true; break; } /* fall through */ From 56c98a07ed391c73b2ecc4fe86770eb39dd248e2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Dec 2023 11:14:58 +0000 Subject: [PATCH 396/816] index: test adding two identical slash-prefix paths Ensure that we can `git_index_add` a slash-prefixed path, followed by re-adding the same path. The original entry should be replaced by the new entry. --- tests/libgit2/index/add.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/libgit2/index/add.c b/tests/libgit2/index/add.c index b0c3bd2b7ae..588a2ad148c 100644 --- a/tests/libgit2/index/add.c +++ b/tests/libgit2/index/add.c @@ -82,3 +82,27 @@ void test_index_add__invalid_entries_succeeds_by_default(void) test_add_entry(true, valid_commit_id, GIT_FILEMODE_LINK); } +void test_index_add__two_slash_prefixed(void) +{ + git_index_entry one = {{0}}, two = {{0}}; + const git_index_entry *result; + size_t orig_count; + + orig_count = git_index_entrycount(g_index); + + cl_git_pass(git_oid__fromstr(&one.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + one.path = "/a"; + one.mode = GIT_FILEMODE_BLOB; + + cl_git_pass(git_oid__fromstr(&two.id, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc", GIT_OID_SHA1)); + two.path = "/a"; + two.mode = GIT_FILEMODE_BLOB; + + cl_git_pass(git_index_add(g_index, &one)); + cl_git_pass(git_index_add(g_index, &two)); + + cl_assert_equal_i(orig_count + 1, git_index_entrycount(g_index)); + + cl_assert(result = git_index_get_bypath(g_index, "/a", 0)); + cl_assert_equal_oid(&two.id, &result->id); +} From 18ea0b0773ebe24459ee3a5beb790e37746fb2ca Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Dec 2023 11:19:07 +0000 Subject: [PATCH 397/816] index: correct index has_dir_name check `has_dir_name` is used to check for directory/file collisions, and attempts to determine whether the index contains a file with a directory name that is a proper subset of the new index entry that we're trying to add. To determine directory name, the function would walk the path string backwards to identify a `/`, stopping at the end of the string. However, the function assumed that the strings did not start with a `/`. If the paths contain only a single `/` at the beginning of the string, then the function would continue the loop, erroneously, when they should have stopped at the first character. Correct the order of the tests to terminate properly. Credit to Michael Rodler (@f0rki) and Amazon AWS Security. --- src/libgit2/index.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 90580731830..5074e3e1fa4 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -1185,10 +1185,13 @@ static int has_dir_name(git_index *index, size_t len, pos; for (;;) { - if (*--slash == '/') - break; + slash--; + if (slash <= entry->path) return 0; + + if (*slash == '/') + break; } len = slash - name; From 39669956fb510fb7b13289f6ce959884969dbebd Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 5 Feb 2024 10:58:14 +0000 Subject: [PATCH 398/816] push: "push_options" are now "remote_push_options" Since we use `git_push_options` as the options structure to our `git_push` command, much like we do everywhere else, "push_options" becomes ambiguous. "remote_options" isn't much better for us. Call them "remote_push_options", which is still quite bad, and not particularly insightful for end users, but at least something that we can discuss unambiguously. --- include/git2/remote.h | 4 +- src/libgit2/push.c | 11 +- src/libgit2/push.h | 2 +- src/libgit2/remote.c | 10 +- src/libgit2/transports/smart_protocol.c | 8 +- tests/libgit2/online/push.c | 167 +++++++++++++++--------- 6 files changed, 123 insertions(+), 79 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 1f41f8c787f..7ad820ad3c3 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -848,9 +848,9 @@ typedef struct { git_strarray custom_headers; /** - * Push options + * "Push options" to deliver to the remote. */ - git_strarray push_options; + git_strarray remote_push_options; } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 diff --git a/src/libgit2/push.c b/src/libgit2/push.c index d718170c82a..e065858826a 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -68,7 +68,7 @@ int git_push_new(git_push **out, git_remote *remote, const git_push_options *opt return -1; } - if (git_vector_init(&p->push_options, 0, git__strcmp_cb) < 0) { + if (git_vector_init(&p->remote_push_options, 0, git__strcmp_cb) < 0) { git_vector_free(&p->status); git_vector_free(&p->specs); git_vector_free(&p->updates); @@ -505,12 +505,13 @@ int git_push_finish(git_push *push) return -1; } - if ((error = git_remote_capabilities(&remote_caps, push->remote)) < 0){ + if ((error = git_remote_capabilities(&remote_caps, push->remote)) < 0) { git_error_set(GIT_ERROR_INVALID, "remote capabilities not available"); return -1; } - if (git_vector_length(&push->push_options) > 0 && !(remote_caps & GIT_REMOTE_CAPABILITY_PUSH_OPTIONS)) { + if (git_vector_length(&push->remote_push_options) > 0 && + !(remote_caps & GIT_REMOTE_CAPABILITY_PUSH_OPTIONS)) { git_error_set(GIT_ERROR_INVALID, "push-options not supported by remote"); return -1; } @@ -581,10 +582,10 @@ void git_push_free(git_push *push) } git_vector_free(&push->updates); - git_vector_foreach(&push->push_options, i, option) { + git_vector_foreach(&push->remote_push_options, i, option) { git__free(option); } - git_vector_free(&push->push_options); + git_vector_free(&push->remote_push_options); git__free(push); } diff --git a/src/libgit2/push.h b/src/libgit2/push.h index 17c3e2f6845..40a1823e45b 100644 --- a/src/libgit2/push.h +++ b/src/libgit2/push.h @@ -34,7 +34,7 @@ struct git_push { git_vector specs; git_vector updates; bool report_status; - git_vector push_options; + git_vector remote_push_options; /* report-status */ bool unpack_ok; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 4adc57c4d09..9eb4bac8b2f 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2982,11 +2982,13 @@ int git_remote_upload( } } - if (opts && opts->push_options.count > 0) - for (i = 0; i < opts->push_options.count; ++i) { - if ((error = git_vector_insert(&push->push_options, git__strdup(opts->push_options.strings[i]))) < 0) { + if (opts && opts->remote_push_options.count > 0) + for (i = 0; i < opts->remote_push_options.count; ++i) { + char *optstr = git__strdup(opts->remote_push_options.strings[i]); + GIT_ERROR_CHECK_ALLOC(optstr); + + if ((error = git_vector_insert(&push->remote_push_options, optstr)) < 0) goto cleanup; - } } if ((error = git_push_finish(push)) < 0) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 85ad65c6227..13f97b7274f 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -797,7 +797,7 @@ static int gen_pktline(git_str *buf, git_push *push) ++len; /* '\0' */ if (push->report_status) len += strlen(GIT_CAP_REPORT_STATUS) + 1; - if (git_vector_length(&push->push_options) > 0) + if (git_vector_length(&push->remote_push_options) > 0) len += strlen(GIT_CAP_PUSH_OPTIONS) + 1; len += strlen(GIT_CAP_SIDE_BAND_64K) + 1; } @@ -814,7 +814,7 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_REPORT_STATUS); } - if (git_vector_length(&push->push_options) > 0) { + if (git_vector_length(&push->remote_push_options) > 0) { git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_PUSH_OPTIONS); } @@ -825,9 +825,9 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, '\n'); } - if (git_vector_length(&push->push_options) > 0) { + if (git_vector_length(&push->remote_push_options) > 0) { git_str_printf(buf, "0000"); - git_vector_foreach(&push->push_options, i, option) { + git_vector_foreach(&push->remote_push_options, i, option) { git_str_printf(buf, "%04"PRIxZ"%s", strlen(option) + 4 , option); } } diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index 1f5f141f53b..cfd43209da4 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -26,7 +26,7 @@ static char *_ssh_cmd = NULL; static char *_remote_push_options_result = NULL; -static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); +static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); static git_remote *_remote; static record_callbacks_data _record_cbs_data = {{ 0 }}; @@ -492,7 +492,7 @@ static void do_push( push_status expected_statuses[], size_t expected_statuses_len, expected_ref expected_refs[], size_t expected_refs_len, int expected_ret, int check_progress_cb, int check_update_tips_cb, - git_strarray push_options) + git_strarray *remote_push_options) { git_push_options opts = GIT_PUSH_OPTIONS_INIT; size_t i; @@ -504,8 +504,8 @@ static void do_push( /* Auto-detect the number of threads to use */ opts.pb_parallelism = 0; - if(push_options.count != 0) - opts.push_options = push_options; + if (remote_push_options) + memcpy(&opts.remote_push_options, remote_push_options, sizeof(git_strarray)); memcpy(&opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks)); data = opts.callbacks.payload; @@ -550,14 +550,12 @@ static void do_push( verify_update_tips_callback(_remote, expected_refs, expected_refs_len); } - } /* Call push_finish() without ever calling git_push_add_refspec() */ void test_online_push__noop(void) { - git_strarray push_options = { 0 }; - do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1, push_options); + do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1, NULL); } void test_online_push__b1(void) @@ -565,10 +563,11 @@ void test_online_push__b1(void) const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats[] = { { "refs/heads/b1", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b2(void) @@ -576,10 +575,11 @@ void test_online_push__b2(void) const char *specs[] = { "refs/heads/b2:refs/heads/b2" }; push_status exp_stats[] = { { "refs/heads/b2", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b2", &_oid_b2 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b3(void) @@ -587,10 +587,11 @@ void test_online_push__b3(void) const char *specs[] = { "refs/heads/b3:refs/heads/b3" }; push_status exp_stats[] = { { "refs/heads/b3", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b3", &_oid_b3 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b4(void) @@ -598,10 +599,11 @@ void test_online_push__b4(void) const char *specs[] = { "refs/heads/b4:refs/heads/b4" }; push_status exp_stats[] = { { "refs/heads/b4", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b4", &_oid_b4 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b5(void) @@ -609,17 +611,17 @@ void test_online_push__b5(void) const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; push_status exp_stats[] = { { "refs/heads/b5", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b5", &_oid_b5 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b5_cancel(void) { const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; - git_strarray push_options = { 0 }; - do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1, push_options); + do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1, NULL); } void test_online_push__multi(void) @@ -648,10 +650,11 @@ void test_online_push__multi(void) { "refs/heads/b4", &_oid_b4 }, { "refs/heads/b5", &_oid_b5 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); cl_git_pass(git_reflog_read(&log, _repo, "refs/remotes/test/b1")); entry = git_reflog_entry_byindex(log, 0); @@ -672,18 +675,21 @@ void test_online_push__implicit_tgt(void) const char *specs2[] = { "refs/heads/b2" }; push_status exp_stats2[] = { { "refs/heads/b2", 1 } }; expected_ref exp_refs2[] = { - { "refs/heads/b1", &_oid_b1 }, - { "refs/heads/b2", &_oid_b2 } + { "refs/heads/b1", &_oid_b1 }, + { "refs/heads/b2", &_oid_b2 } }; - git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 1, 1, + NULL); do_push(specs2, ARRAY_SIZE(specs2), exp_stats2, ARRAY_SIZE(exp_stats2), - exp_refs2, ARRAY_SIZE(exp_refs2), 0, 0, 0, push_options); + exp_refs2, ARRAY_SIZE(exp_refs2), + 0, 0, 0, + NULL); } void test_online_push__fast_fwd(void) @@ -703,22 +709,29 @@ void test_online_push__fast_fwd(void) /* Force should have no effect on a fast forward push */ const char *specs_ff_force[] = { "+refs/heads/b6:refs/heads/b1" }; - git_strarray push_options = { 0 }; do_push(specs_init, ARRAY_SIZE(specs_init), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 1, 1, push_options); + exp_refs_init, ARRAY_SIZE(exp_refs_init), + 0, 1, 1, + NULL); do_push(specs_ff, ARRAY_SIZE(specs_ff), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), + 0, 0, 0, + NULL); do_push(specs_reset, ARRAY_SIZE(specs_reset), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 0, 0, push_options); + exp_refs_init, ARRAY_SIZE(exp_refs_init), + 0, 0, 0, + NULL); do_push(specs_ff_force, ARRAY_SIZE(specs_ff_force), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), + 0, 0, 0, + NULL); } void test_online_push__tag_commit(void) @@ -726,10 +739,11 @@ void test_online_push__tag_commit(void) const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" }; push_status exp_stats[] = { { "refs/tags/tag-commit", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-commit", &_tag_commit } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_tree(void) @@ -737,10 +751,11 @@ void test_online_push__tag_tree(void) const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" }; push_status exp_stats[] = { { "refs/tags/tag-tree", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tree", &_tag_tree } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_blob(void) @@ -748,10 +763,11 @@ void test_online_push__tag_blob(void) const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" }; push_status exp_stats[] = { { "refs/tags/tag-blob", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-blob", &_tag_blob } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_lightweight(void) @@ -759,10 +775,11 @@ void test_online_push__tag_lightweight(void) const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" }; push_status exp_stats[] = { { "refs/tags/tag-lightweight", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-lightweight", &_tag_lightweight } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_to_tag(void) @@ -770,10 +787,11 @@ void test_online_push__tag_to_tag(void) const char *specs[] = { "refs/tags/tag-tag:refs/tags/tag-tag" }; push_status exp_stats[] = { { "refs/tags/tag-tag", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tag", &_tag_tag } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 0, 0, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 0, 0, + NULL); } void test_online_push__force(void) @@ -788,20 +806,25 @@ void test_online_push__force(void) push_status exp_stats2_force[] = { { "refs/heads/tgt", 1 } }; expected_ref exp_refs2_force[] = { { "refs/heads/tgt", &_oid_b4 } }; - git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 1, 1, + NULL); do_push(specs2, ARRAY_SIZE(specs2), NULL, 0, - exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + GIT_ENONFASTFORWARD, 0, 0, + NULL); /* Non-fast-forward update with force should pass. */ record_callbacks_data_clear(&_record_cbs_data); do_push(specs2_force, ARRAY_SIZE(specs2_force), exp_stats2_force, ARRAY_SIZE(exp_stats2_force), - exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0, 1, 1, push_options); + exp_refs2_force, ARRAY_SIZE(exp_refs2_force), + 0, 1, 1, + NULL); } static void push_option_test(git_strarray push_options, const char *expected_option) @@ -817,7 +840,9 @@ static void push_option_test(git_strarray push_options, const char *expected_opt do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + &push_options); if (git_futils_readbuffer(&push_options_result, _remote_push_options_result) < 0) cl_fail("Failed to read push options result file"); @@ -874,10 +899,11 @@ void test_online_push__delete(void) /* Force has no effect for delete. */ const char *specs_delete_force[] = { "+:refs/heads/tgt1" }; - git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 1, 1, + NULL); /* When deleting a non-existent branch, the git client sends zero for both * the old and new commit id. This should succeed on the server with the @@ -887,25 +913,35 @@ void test_online_push__delete(void) */ do_push(specs_del_fake, ARRAY_SIZE(specs_del_fake), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 0, 0, + NULL); do_push(specs_del_fake_force, ARRAY_SIZE(specs_del_fake_force), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 0, 0, + NULL); /* Delete one of the pushed branches. */ do_push(specs_delete, ARRAY_SIZE(specs_delete), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), + 0, 0, 0, + NULL); /* Re-push branches and retry delete with force. */ do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 0, 0, + NULL); do_push(specs_delete_force, ARRAY_SIZE(specs_delete_force), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), + 0, 0, 0, + NULL); } void test_online_push__bad_refspecs(void) @@ -947,19 +983,17 @@ void test_online_push__expressions(void) { "refs/heads/b6", &_oid_b6 } }; - git_strarray push_options = { 0 }; - do_push(specs_left_expr, ARRAY_SIZE(specs_left_expr), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, - push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__notes(void) { git_oid note_oid, *target_oid, expected_oid; git_signature *signature; - git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -975,13 +1009,17 @@ void test_online_push__notes(void) do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0, push_options); + NULL, 0, + 0, 0, 0, + NULL); git_signature_free(signature); } @@ -991,7 +1029,6 @@ void test_online_push__configured(void) git_oid note_oid, *target_oid, expected_oid; git_signature *signature; git_remote *old_remote; - git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -1012,13 +1049,17 @@ void test_online_push__configured(void) do_push(NULL, 0, exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0, push_options); + NULL, 0, + 0, 0, 0, + NULL); git_signature_free(signature); } From 85279f06aae1796d1551609041c5e0cf691bb297 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 5 Feb 2024 11:48:19 +0000 Subject: [PATCH 399/816] ci: update push options tests Keep the push options tests more constrained to our CI environment; writing files within the test sandbox instead of outside of it. Provide the path to the output file in the test data. In addition, add the repository to the test resources instead of recreating the hooks every time. --- ci/hooks/pre-receive | 2 - ci/test.sh | 60 +++++-------------- tests/libgit2/online/push.c | 34 +++++++---- tests/resources/pushoptions.git/HEAD | 1 + .../pushoptions.git/branches/.gitignore | 0 tests/resources/pushoptions.git/config | 8 +++ tests/resources/pushoptions.git/description | 1 + .../pushoptions.git/hooks/pre-receive | 3 + tests/resources/pushoptions.git/info/exclude | 6 ++ .../pushoptions.git/objects/info/.gitignore | 0 .../pushoptions.git/objects/pack/.gitignore | 0 .../pushoptions.git/refs/heads/.gitignore | 0 .../pushoptions.git/refs/tags/.gitignore | 0 13 files changed, 57 insertions(+), 58 deletions(-) delete mode 100755 ci/hooks/pre-receive create mode 100644 tests/resources/pushoptions.git/HEAD create mode 100644 tests/resources/pushoptions.git/branches/.gitignore create mode 100644 tests/resources/pushoptions.git/config create mode 100644 tests/resources/pushoptions.git/description create mode 100755 tests/resources/pushoptions.git/hooks/pre-receive create mode 100644 tests/resources/pushoptions.git/info/exclude create mode 100644 tests/resources/pushoptions.git/objects/info/.gitignore create mode 100644 tests/resources/pushoptions.git/objects/pack/.gitignore create mode 100644 tests/resources/pushoptions.git/refs/heads/.gitignore create mode 100644 tests/resources/pushoptions.git/refs/tags/.gitignore diff --git a/ci/hooks/pre-receive b/ci/hooks/pre-receive deleted file mode 100755 index 92be65ce01f..00000000000 --- a/ci/hooks/pre-receive +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -printf "$GIT_PUSH_OPTION_0$GIT_PUSH_OPTION_1$GIT_PUSH_OPTION_2" > %file% diff --git a/ci/test.sh b/ci/test.sh index 8543169ce5c..4217568226a 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -ex +set -e if [ -n "$SKIP_TESTS" ]; then if [ -z "$SKIP_OFFLINE_TESTS" ]; then SKIP_OFFLINE_TESTS=1; fi @@ -162,14 +162,7 @@ echo "" if should_run "GITDAEMON_TESTS"; then echo "Starting git daemon (standard)..." GIT_STANDARD_DIR=`mktemp -d ${TMPDIR}/git_standard.XXXXXXXX` - git init --bare "${GIT_STANDARD_DIR}/test.git" >/dev/null - git config --file "${GIT_STANDARD_DIR}/test.git/config" receive.advertisePushOptions true - for f in $(ls ${SOURCE_DIR}/ci/hooks) - do - sed "s=%file%=${TMPDIR}/push-option-result-git-daemon=g" "${SOURCE_DIR}/ci/hooks/$f" > "${GIT_STANDARD_DIR}/test.git/hooks/${f}" - chmod +x "$GIT_STANDARD_DIR/test.git/hooks/${f}" - done - + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${GIT_STANDARD_DIR}/test.git" git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GIT_STANDARD_DIR}" "${GIT_STANDARD_DIR}" 2>/dev/null & GIT_STANDARD_PID=$! @@ -204,14 +197,7 @@ if should_run "NTLM_TESTS" || should_run "ONLINE_TESTS"; then echo "Starting HTTP server..." HTTP_DIR=`mktemp -d ${TMPDIR}/http.XXXXXXXX` - git init --bare "${HTTP_DIR}/test.git" - git config --file "${HTTP_DIR}/test.git/config" receive.advertisePushOptions true - - for f in $(ls ${SOURCE_DIR}/ci/hooks) - do - sed "s=%file%=${TMPDIR}/push-option-result-git-ntlm=g" "${SOURCE_DIR}/ci/hooks/$f" > "${HTTP_DIR}/test.git/hooks/${f}" - chmod +x "$HTTP_DIR/test.git/hooks/${f}" - done + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${HTTP_DIR}/test.git" java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${HTTP_DIR}" & HTTP_PID=$! @@ -220,14 +206,8 @@ fi if should_run "SSH_TESTS"; then echo "Starting SSH server..." SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX` - git init --bare "${SSHD_DIR}/test.git" >/dev/null - git config --file "${SSHD_DIR}/test.git/config" receive.advertisePushOptions true - - for f in $(ls ${SOURCE_DIR}/ci/hooks) - do - sed "s=%file%=${TMPDIR}/push-option-result-git-ssh=g" "${SOURCE_DIR}/ci/hooks/$f" > "${SSHD_DIR}/test.git/hooks/${f}" - chmod +x "$SSHD_DIR/test.git/hooks/${f}" - done + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${SSHD_DIR}/test.git" + ls -FlasR "${SSHD_DIR}" cat >"${SSHD_DIR}/sshd_config" <<-EOF Port 2222 @@ -344,13 +324,11 @@ if should_run "GITDAEMON_TESTS"; then echo "Running gitdaemon (standard) tests" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-daemon" - fi export GITTEST_REMOTE_URL="git://localhost/test.git" + export GITTEST_PUSH_OPTIONS=true run_test gitdaemon - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL + unset GITTEST_PUSH_OPTIONS echo "" echo "Running gitdaemon (namespace) tests" @@ -402,33 +380,29 @@ if should_run "NTLM_TESTS"; then echo "Running NTLM tests (IIS emulation)" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" - fi export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" + export GITTEST_PUSH_OPTIONS=true run_test auth_clone_and_push - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS + unset GITTEST_PUSH_OPTIONS echo "" echo "Running NTLM tests (Apache emulation)" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" - fi export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" + export GITTEST_PUSH_OPTIONS=true run_test auth_clone_and_push - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS + unset GITTEST_PUSH_OPTIONS fi if should_run "NEGOTIATE_TESTS" && -n "$GITTEST_NEGOTIATE_PASSWORD" ; then @@ -477,25 +451,21 @@ if should_run "SSH_TESTS"; then echo "Running ssh tests" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" - fi export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git" + export GITTEST_PUSH_OPTIONS=true run_test ssh - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL + unset GITTEST_PUSH_OPTIONS echo "" echo "Running ssh tests (scp-style paths)" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" - fi export GITTEST_REMOTE_URL="[localhost:2222]:$SSHD_DIR/test.git" + export GITTEST_PUSH_OPTIONS=true run_test ssh - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL + unset GITTEST_PUSH_OPTIONS unset GITTEST_SSH_CMD diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index cfd43209da4..e5693bf346c 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -21,11 +21,11 @@ static char *_remote_ssh_passphrase = NULL; static char *_remote_default = NULL; static char *_remote_expectcontinue = NULL; +static char *_remote_push_options = NULL; + static char *_orig_ssh_cmd = NULL; static char *_ssh_cmd = NULL; -static char *_remote_push_options_result = NULL; - static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); static git_remote *_remote; @@ -373,7 +373,7 @@ void test_online_push__initialize(void) _remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE"); _remote_default = cl_getenv("GITTEST_REMOTE_DEFAULT"); _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE"); - _remote_push_options_result = cl_getenv("GITTEST_PUSH_OPTION_RESULT"); + _remote_push_options = cl_getenv("GITTEST_PUSH_OPTIONS"); _remote = NULL; _orig_ssh_cmd = cl_getenv("GIT_SSH"); @@ -437,7 +437,7 @@ void test_online_push__cleanup(void) git__free(_remote_ssh_passphrase); git__free(_remote_default); git__free(_remote_expectcontinue); - git__free(_remote_push_options_result); + git__free(_remote_push_options); git__free(_orig_ssh_cmd); git__free(_ssh_cmd); @@ -449,6 +449,7 @@ void test_online_push__cleanup(void) record_callbacks_data_clear(&_record_cbs_data); + cl_fixture_cleanup("push-options-result"); cl_fixture_cleanup("testrepo.git"); cl_git_sandbox_cleanup(); } @@ -827,30 +828,41 @@ void test_online_push__force(void) NULL); } -static void push_option_test(git_strarray push_options, const char *expected_option) +static void push_option_test(git_strarray given_options, const char *expected_option) { const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats[] = { { "refs/heads/b1", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; + git_str push_options_path = GIT_STR_INIT; git_str push_options_result = GIT_STR_INIT; + char *options[16]; + git_strarray push_options = { options, given_options.count + 1 }; + size_t i; /* Skip the test if we're missing the push options result file */ - if (!_remote_push_options_result) + if (!_remote_push_options) cl_skip(); + cl_assert(given_options.count < 16); + + cl_git_pass(git_str_joinpath(&push_options_path, clar_sandbox_path(), "push-options-result")); + + options[0] = push_options_path.ptr; + for (i = 0; i < given_options.count; i++) + options[i + 1] = given_options.strings[i]; + do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, &push_options); - if (git_futils_readbuffer(&push_options_result, _remote_push_options_result) < 0) - cl_fail("Failed to read push options result file"); - - cl_assert_equal_strn(expected_option, git_str_cstr(&push_options_result), - strlen(expected_option)); + cl_assert(git_fs_path_exists(push_options_path.ptr)); + cl_git_pass(git_futils_readbuffer(&push_options_result, push_options_path.ptr)); + cl_assert_equal_s(expected_option, git_str_cstr(&push_options_result)); git_str_dispose(&push_options_result); + git_str_dispose(&push_options_path); } void test_online_push__options(void) diff --git a/tests/resources/pushoptions.git/HEAD b/tests/resources/pushoptions.git/HEAD new file mode 100644 index 00000000000..b870d82622c --- /dev/null +++ b/tests/resources/pushoptions.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/tests/resources/pushoptions.git/branches/.gitignore b/tests/resources/pushoptions.git/branches/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/config b/tests/resources/pushoptions.git/config new file mode 100644 index 00000000000..23d39788fa7 --- /dev/null +++ b/tests/resources/pushoptions.git/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true +[receive] + advertisePushOptions = true diff --git a/tests/resources/pushoptions.git/description b/tests/resources/pushoptions.git/description new file mode 100644 index 00000000000..498b267a8c7 --- /dev/null +++ b/tests/resources/pushoptions.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests/resources/pushoptions.git/hooks/pre-receive b/tests/resources/pushoptions.git/hooks/pre-receive new file mode 100755 index 00000000000..24f48d34c54 --- /dev/null +++ b/tests/resources/pushoptions.git/hooks/pre-receive @@ -0,0 +1,3 @@ +#!/bin/sh +printf "${GIT_PUSH_OPTION_1}${GIT_PUSH_OPTION_2}${GIT_PUSH_OPTION_3}" > "${GIT_PUSH_OPTION_0}" +exit 0 diff --git a/tests/resources/pushoptions.git/info/exclude b/tests/resources/pushoptions.git/info/exclude new file mode 100644 index 00000000000..a5196d1be8f --- /dev/null +++ b/tests/resources/pushoptions.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/resources/pushoptions.git/objects/info/.gitignore b/tests/resources/pushoptions.git/objects/info/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/objects/pack/.gitignore b/tests/resources/pushoptions.git/objects/pack/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/refs/heads/.gitignore b/tests/resources/pushoptions.git/refs/heads/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/refs/tags/.gitignore b/tests/resources/pushoptions.git/refs/tags/.gitignore new file mode 100644 index 00000000000..e69de29bb2d From 00eb3470682e25e9362e207790914c5e2688c71a Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Tue, 16 Jan 2024 09:46:01 +0000 Subject: [PATCH 400/816] ci: add fedora container and build So that we can test a build with llhttp instead of http-parser. Co-authored-by: Stephen Gallagher Signed-off-by: Sergio Correia Signed-off-by: Stephen Gallagher --- .github/workflows/build-containers.yml | 1 + .github/workflows/main.yml | 9 ++++ ci/docker/fedora | 61 ++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 ci/docker/fedora diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 56ac66a9016..84bc4da0e64 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -40,6 +40,7 @@ jobs: qemu: true - name: centos7 - name: centos8 + - name: fedora runs-on: ubuntu-latest name: "Create container: ${{ matrix.container.name }}" steps: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index accb042e463..aca6b0ee359 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -62,6 +62,15 @@ jobs: CC: clang CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 + - name: "Linux (Fedora, GCC, llhttp, SHA-256, OpenSSL, libssh2" + id: fedora-gcc-openssl-llhttp + os: ubuntu-latest + container: + name: fedora + env: + CC: gcc + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=pcre2 -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_NTLMCLIENT=OFF -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON -DEXPERIMENTAL_SHA256=ON - name: "macOS" id: macos os: macos-12 diff --git a/ci/docker/fedora b/ci/docker/fedora new file mode 100644 index 00000000000..d6339bc8512 --- /dev/null +++ b/ci/docker/fedora @@ -0,0 +1,61 @@ +ARG BASE=fedora:rawhide + +FROM ${BASE} AS stream +RUN dnf -y distro-sync + +FROM stream AS yum +RUN yum install -y \ + which \ + bzip2 \ + git \ + libarchive \ + cmake \ + gcc \ + make \ + openssl-devel \ + openssh-server \ + git-daemon \ + java-1.8.0-openjdk-headless \ + sudo \ + python3 \ + krb5-workstation \ + krb5-libs \ + krb5-devel \ + pcre2-devel \ + ninja-build \ + llhttp-devel + +FROM yum AS libssh2 +RUN cd /tmp && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + ./configure && \ + make && \ + make install && \ + cd .. && \ + rm -rf libssh2-1.11.0 + +FROM libssh2 AS valgrind +RUN cd /tmp && \ + curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \ + tar -xj && \ + cd valgrind-3.15.0 && \ + ./configure && \ + make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \ + make install && \ + cd .. && \ + rm -rf valgrind-3.15.0 + +FROM valgrind AS adduser +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 + +FROM adduser AS configure +ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig +RUN mkdir /var/run/sshd +RUN echo "/usr/local/lib" > /etc/ld.so.conf.d/local && \ + ldconfig From 06e384a0a44a7ab33e24b0e2123dc1edbf86becc Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Wed, 10 Jan 2024 17:07:45 -0500 Subject: [PATCH 401/816] Enable llhttp for HTTP parsing Fixes: https://github.com/libgit2/libgit2/issues/6074 We now try to use llhttp by default, falling back to http-parser if the former is not available. As a last resort, we use the bundled http-parser. Co-authored-by: Sergio Correia Signed-off-by: Stephen Gallagher Signed-off-by: Sergio Correia --- cmake/FindLLHTTP.cmake | 39 +++++++++ cmake/SelectHTTPParser.cmake | 44 +++++++--- src/libgit2/transports/http.c | 1 - src/libgit2/transports/httpclient.c | 122 ++++++++++++++++++++++------ src/util/net.c | 1 - 5 files changed, 169 insertions(+), 38 deletions(-) create mode 100644 cmake/FindLLHTTP.cmake diff --git a/cmake/FindLLHTTP.cmake b/cmake/FindLLHTTP.cmake new file mode 100644 index 00000000000..a87d335d048 --- /dev/null +++ b/cmake/FindLLHTTP.cmake @@ -0,0 +1,39 @@ +# - Try to find llhttp +# +# Defines the following variables: +# +# LLHTTP_FOUND - system has llhttp +# LLHTTP_INCLUDE_DIR - the llhttp include directory +# LLHTTP_LIBRARIES - Link these to use llhttp +# LLHTTP_VERSION_MAJOR - major version +# LLHTTP_VERSION_MINOR - minor version +# LLHTTP_VERSION_STRING - the version of llhttp found + +# Find the header and library +find_path(LLHTTP_INCLUDE_DIR NAMES llhttp.h) +find_library(LLHTTP_LIBRARY NAMES llhttp libllhttp) + +# Found the header, read version +if(LLHTTP_INCLUDE_DIR AND EXISTS "${LLHTTP_INCLUDE_DIR}/llhttp.h") + file(READ "${LLHTTP_INCLUDE_DIR}/llhttp.h" LLHTTP_H) + if(LLHTTP_H) + string(REGEX REPLACE ".*#define[\t ]+LLHTTP_VERSION_MAJOR[\t ]+([0-9]+).*" "\\1" LLHTTP_VERSION_MAJOR "${LLHTTP_H}") + string(REGEX REPLACE ".*#define[\t ]+LLHTTP_VERSION_MINOR[\t ]+([0-9]+).*" "\\1" LLHTTP_VERSION_MINOR "${LLHTTP_H}") + set(LLHTTP_VERSION_STRING "${LLHTTP_VERSION_MAJOR}.${LLHTTP_VERSION_MINOR}") + endif() + unset(LLHTTP_H) +endif() + +# Handle the QUIETLY and REQUIRED arguments and set LLHTTP_FOUND +# to TRUE if all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LLHTTP REQUIRED_VARS LLHTTP_INCLUDE_DIR LLHTTP_LIBRARY) + +# Hide advanced variables +mark_as_advanced(LLHTTP_INCLUDE_DIR LLHTTP_LIBRARY) + +# Set standard variables +if(LLHTTP_FOUND) + set(LLHTTP_LIBRARIES ${LLHTTP_LIBRARY}) + set(LLHTTP_INCLUDE_DIRS ${LLHTTP_INCLUDE_DIR}) +endif() diff --git a/cmake/SelectHTTPParser.cmake b/cmake/SelectHTTPParser.cmake index 955aea3308c..aa6711d9607 100644 --- a/cmake/SelectHTTPParser.cmake +++ b/cmake/SelectHTTPParser.cmake @@ -1,19 +1,39 @@ # Optional external dependency: http-parser -if(USE_HTTP_PARSER STREQUAL "system") - find_package(HTTPParser) +if(USE_HTTP_PARSER STREQUAL "builtin") + message(STATUS "support for bundled (legacy) http-parser explicitly requested") - if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) - list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS}) - list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES}) - list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") - add_feature_info(http-parser ON "http-parser support (system)") - else() - message(FATAL_ERROR "http-parser support was requested but not found") - endif() -else() - message(STATUS "http-parser version 2 was not found or disabled; using bundled 3rd-party sources.") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") add_feature_info(http-parser ON "http-parser support (bundled)") +else() + # By default, try to use system LLHTTP. Fall back to + # system http-parser, and even to bundled http-parser + # as a last resort. + find_package(LLHTTP) + + if(LLHTTP_FOUND AND LLHTTP_VERSION_MAJOR EQUAL 9) + add_compile_definitions(USE_LLHTTP) + list(APPEND LIBGIT2_SYSTEM_INCLUDES ${LLHTTP_INCLUDE_DIRS}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${LLHTTP_LIBRARIES}) + list(APPEND LIBGIT2_PC_LIBS "-lllhttp") + add_feature_info(llhttp ON "llhttp support (system)") + else() + message(STATUS "llhttp support was requested but not found; checking (legacy) http-parser support") + find_package(HTTPParser) + + if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) + list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES}) + list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") + add_feature_info(http-parser ON "http-parser support (system)") + else() + message(STATUS "neither llhttp nor http-parser support was found; proceeding with bundled (legacy) http-parser") + + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") + add_feature_info(http-parser ON "http-parser support (bundled)") + endif() + endif() endif() diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index 8437674fcc9..fc2161b6076 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -9,7 +9,6 @@ #ifndef GIT_WINHTTP -#include "http_parser.h" #include "net.h" #include "remote.h" #include "smart.h" diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index e22a07ba1a0..6e3491ed2b3 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -7,7 +7,32 @@ #include "common.h" #include "git2.h" -#include "http_parser.h" + +#ifdef USE_LLHTTP +#include +typedef llhttp_settings_t http_settings_t; +typedef llhttp_t http_parser_t; +GIT_INLINE(http_settings_t *) http_client_parser_settings(void); +#define git_http_parser_init(parser) llhttp_init(parser, HTTP_RESPONSE, http_client_parser_settings()) +#define git_http_parser_pause(parser) llhttp_pause(parser) +#define git_http_parser_resume(parser) llhttp_resume(parser) +#define git_http_parser_errno(parser) parser.error +#define git_http_should_keep_alive(parser) llhttp_should_keep_alive(parser) +#define git_http_errno_description(parser, errno) llhttp_get_error_reason(parser) +#else +#include +/* Legacy http-parser. */ +typedef http_parser_settings http_settings_t; +typedef struct http_parser http_parser_t; +GIT_INLINE(http_settings_t *) http_client_parser_settings(void); +#define git_http_parser_init(parser) http_parser_init(parser, HTTP_RESPONSE) +#define git_http_parser_pause(parser) http_parser_pause(parser, 1) +#define git_http_parser_resume(parser) http_parser_pause(parser, 0) +#define git_http_parser_errno(parser) parser.http_errno +#define git_http_should_keep_alive(parser) http_should_keep_alive(parser) +#define git_http_errno_description(parser, errno) http_errno_description(errno) +#endif /* USE_LLHTTP */ + #include "vector.h" #include "trace.h" #include "httpclient.h" @@ -108,7 +133,7 @@ struct git_http_client { git_http_server_t current_server; http_client_state state; - http_parser parser; + http_parser_t parser; git_http_server server; git_http_server proxy; @@ -154,7 +179,7 @@ void git_http_response_dispose(git_http_response *response) memset(response, 0, sizeof(git_http_response)); } -static int on_header_complete(http_parser *parser) +static int on_header_complete(http_parser_t *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; git_http_client *client = ctx->client; @@ -219,7 +244,7 @@ static int on_header_complete(http_parser *parser) return 0; } -static int on_header_field(http_parser *parser, const char *str, size_t len) +static int on_header_field(http_parser_t *parser, const char *str, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -254,7 +279,7 @@ static int on_header_field(http_parser *parser, const char *str, size_t len) return 0; } -static int on_header_value(http_parser *parser, const char *str, size_t len) +static int on_header_value(http_parser_t *parser, const char *str, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -342,7 +367,7 @@ static int resend_needed(git_http_client *client, git_http_response *response) return 0; } -static int on_headers_complete(http_parser *parser) +static int on_headers_complete(http_parser_t *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -365,7 +390,7 @@ static int on_headers_complete(http_parser *parser) } ctx->response->status = parser->status_code; - ctx->client->keepalive = http_should_keep_alive(parser); + ctx->client->keepalive = git_http_should_keep_alive(parser); /* Prepare for authentication */ collect_authinfo(&ctx->response->server_auth_schemetypes, @@ -378,18 +403,28 @@ static int on_headers_complete(http_parser *parser) ctx->response->resend_credentials = resend_needed(ctx->client, ctx->response); - /* Stop parsing. */ - http_parser_pause(parser, 1); +#ifndef USE_LLHTTP + /* Stop parsing. llhttp documentation says about llhttp_pause(): + * "Do not call this from user callbacks! User callbacks must + * return HPE_PAUSED if pausing is required", so that's what + * we will do, and call git_http_parser_pause() only for + * http-parser. */ + git_http_parser_pause(parser); +#endif if (ctx->response->content_type || ctx->response->chunked) ctx->client->state = READING_BODY; else ctx->client->state = DONE; +#ifdef USE_LLHTTP + return HPE_PAUSED; +#else return 0; +#endif } -static int on_body(http_parser *parser, const char *buf, size_t len) +static int on_body(http_parser_t *parser, const char *buf, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; size_t max_len; @@ -411,7 +446,7 @@ static int on_body(http_parser *parser, const char *buf, size_t len) return 0; } -static int on_message_complete(http_parser *parser) +static int on_message_complete(http_parser_t *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -878,7 +913,7 @@ GIT_INLINE(int) server_setup_from_url( static void reset_parser(git_http_client *client) { - http_parser_init(&client->parser, HTTP_RESPONSE); + git_http_parser_init(&client->parser); } static int setup_hosts( @@ -1122,9 +1157,46 @@ GIT_INLINE(int) client_read(git_http_client *client) } static bool parser_settings_initialized; -static http_parser_settings parser_settings; +static http_settings_t parser_settings; + +static size_t git_http_parser_execute(http_parser_t *parser, const char* data, size_t len) +{ +#ifdef USE_LLHTTP + llhttp_errno_t error; + size_t parsed_len; + + /* + * Unlike http_parser, which returns the number of parsed + * bytes in the _execute() call, llhttp returns an error + * code. + */ + + if (data == NULL || len == 0) { + error = llhttp_finish(parser); + } else { + error = llhttp_execute(parser, data, len); + } + + parsed_len = len; + /* + * Adjust number of parsed bytes in case of error. + */ + if (error != HPE_OK) { + parsed_len = llhttp_get_error_pos(parser) - data; + + /* This isn't a real pause, just a way to stop parsing early. */ + if (error == HPE_PAUSED_UPGRADE) { + llhttp_resume_after_upgrade(parser); + } + } + + return parsed_len; +#else + return http_parser_execute(parser, http_client_parser_settings(), data, len); +#endif +} -GIT_INLINE(http_parser_settings *) http_client_parser_settings(void) +GIT_INLINE(http_settings_t *) http_client_parser_settings(void) { if (!parser_settings_initialized) { parser_settings.on_header_field = on_header_field; @@ -1141,7 +1213,7 @@ GIT_INLINE(http_parser_settings *) http_client_parser_settings(void) GIT_INLINE(int) client_read_and_parse(git_http_client *client) { - http_parser *parser = &client->parser; + http_parser_t *parser = &client->parser; http_parser_context *ctx = (http_parser_context *) parser->data; unsigned char http_errno; int read_len; @@ -1155,11 +1227,10 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) if (!client->read_buf.size && (read_len = client_read(client)) < 0) return read_len; - parsed_len = http_parser_execute(parser, - http_client_parser_settings(), + parsed_len = git_http_parser_execute(parser, client->read_buf.ptr, client->read_buf.size); - http_errno = client->parser.http_errno; + http_errno = git_http_parser_errno(client->parser); if (parsed_len > INT_MAX) { git_error_set(GIT_ERROR_HTTP, "unexpectedly large parse"); @@ -1179,6 +1250,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) * where the server gives you a 100 and 200 simultaneously.) */ if (http_errno == HPE_PAUSED) { +#ifndef USE_LLHTTP /* * http-parser has a "feature" where it will not deliver the * final byte when paused in a callback. Consume that byte. @@ -1186,18 +1258,20 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) */ GIT_ASSERT(client->read_buf.size > parsed_len); - http_parser_pause(parser, 0); +#endif + git_http_parser_resume(parser); - parsed_len += http_parser_execute(parser, - http_client_parser_settings(), +#ifndef USE_LLHTTP + parsed_len += git_http_parser_execute(parser, client->read_buf.ptr + parsed_len, 1); +#endif } /* Most failures will be reported in http_errno */ - else if (parser->http_errno != HPE_OK) { + else if (git_http_parser_errno(client->parser) != HPE_OK) { git_error_set(GIT_ERROR_HTTP, "http parser error: %s", - http_errno_description(http_errno)); + git_http_errno_description(parser, http_errno)); return -1; } @@ -1205,7 +1279,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) else if (parsed_len != client->read_buf.size) { git_error_set(GIT_ERROR_HTTP, "http parser did not consume entire buffer: %s", - http_errno_description(http_errno)); + git_http_errno_description(parser, http_errno)); return -1; } diff --git a/src/util/net.c b/src/util/net.c index 4474564511b..dede784cc31 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -11,7 +11,6 @@ #include "posix.h" #include "str.h" -#include "http_parser.h" #include "runtime.h" #define DEFAULT_PORT_HTTP "80" From c95e91a280e58c4776b8f440c1bde5b9184827c5 Mon Sep 17 00:00:00 2001 From: Sebastien Marie Date: Mon, 12 Feb 2024 10:17:02 +0100 Subject: [PATCH 402/816] GIT_RAND_GETENTROPY: do not include sys/random.h CMakeLists.txt is looking for unistd.h (where the getentropy function is present for at least Linux and OpenBSD). It isn't necessary to include sys/random.h (which is Linux only). It unbreak the build on OpenBSD. --- src/util/rand.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/util/rand.c b/src/util/rand.c index 2ed0605738b..a02853519b2 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -10,10 +10,6 @@ See . */ #include "rand.h" #include "runtime.h" -#if defined(GIT_RAND_GETENTROPY) -# include -#endif - #if defined(GIT_WIN32) # include #endif From 38a062ddca5d95d8e308894886567d2c49a0fac2 Mon Sep 17 00:00:00 2001 From: Parnic Date: Fri, 16 Feb 2024 09:09:32 -0600 Subject: [PATCH 403/816] Support index.skipHash true config When this is set, the checksum at the end of the index is zero. Fixes #6531 --- src/libgit2/index.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 5074e3e1fa4..86f14fdfc41 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -2760,6 +2760,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) unsigned int i; struct index_header header = { 0 }; unsigned char checksum[GIT_HASH_MAX_SIZE]; + unsigned char zero_checksum[GIT_HASH_MAX_SIZE] = { 0 }; size_t checksum_size = git_hash_size(git_oid_algorithm(index->oid_type)); const char *last = NULL; const char *empty = ""; @@ -2849,8 +2850,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) /* * SHA-1 or SHA-256 (depending on the repository's object format) * over the content of the index file before this checksum. + * Note: checksum may be 0 if index.skipHash is set to true. */ - if (memcmp(checksum, buffer, checksum_size) != 0) { + if (memcmp(zero_checksum, buffer, checksum_size) != 0 && memcmp(checksum, buffer, checksum_size) != 0) { error = index_error_invalid( "calculated checksum does not match expected"); goto done; From 9ed014775ee47e0b59ce2fc3b12a79344596f05b Mon Sep 17 00:00:00 2001 From: Parnic Date: Fri, 16 Feb 2024 09:29:21 -0600 Subject: [PATCH 404/816] Add index.skipHash test --- tests/libgit2/status/worktree.c | 9 + .../status_skipHash/.gitted/COMMIT_EDITMSG | 1 + tests/resources/status_skipHash/.gitted/HEAD | 1 + .../status_skipHash/.gitted/MERGE_RR | 0 .../resources/status_skipHash/.gitted/config | 9 + .../status_skipHash/.gitted/description | 1 + .../.gitted/hooks/applypatch-msg.sample | 15 ++ .../.gitted/hooks/commit-msg.sample | 24 +++ .../.gitted/hooks/fsmonitor-watchman.sample | 174 ++++++++++++++++++ .../.gitted/hooks/post-update.sample | 8 + .../.gitted/hooks/pre-applypatch.sample | 14 ++ .../.gitted/hooks/pre-commit.sample | 49 +++++ .../.gitted/hooks/pre-merge-commit.sample | 13 ++ .../.gitted/hooks/pre-push.sample | 53 ++++++ .../.gitted/hooks/pre-rebase.sample | 169 +++++++++++++++++ .../.gitted/hooks/pre-receive.sample | 24 +++ .../.gitted/hooks/prepare-commit-msg.sample | 42 +++++ .../.gitted/hooks/push-to-checkout.sample | 78 ++++++++ .../.gitted/hooks/sendemail-validate.sample | 77 ++++++++ .../.gitted/hooks/update.sample | 128 +++++++++++++ tests/resources/status_skipHash/.gitted/index | Bin 0 -> 137 bytes .../status_skipHash/.gitted/info/exclude | 6 + .../status_skipHash/.gitted/logs/HEAD | 1 + .../.gitted/logs/refs/heads/main | 1 + .../34/f4c90b237fcb4c677772a6093f3cba239c41a5 | Bin 0 -> 510 bytes .../71/a21e67674e9717aa7380e5782ec5e070a8d7e0 | Bin 0 -> 53 bytes .../d7/c1f165e51adbbfd7760162b7a5802d4117740c | Bin 0 -> 26 bytes .../status_skipHash/.gitted/refs/heads/main | 1 + tests/resources/status_skipHash/new_file | 1 + 29 files changed, 899 insertions(+) create mode 100644 tests/resources/status_skipHash/.gitted/COMMIT_EDITMSG create mode 100644 tests/resources/status_skipHash/.gitted/HEAD create mode 100644 tests/resources/status_skipHash/.gitted/MERGE_RR create mode 100644 tests/resources/status_skipHash/.gitted/config create mode 100644 tests/resources/status_skipHash/.gitted/description create mode 100644 tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/post-update.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-push.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/sendemail-validate.sample create mode 100644 tests/resources/status_skipHash/.gitted/hooks/update.sample create mode 100644 tests/resources/status_skipHash/.gitted/index create mode 100644 tests/resources/status_skipHash/.gitted/info/exclude create mode 100644 tests/resources/status_skipHash/.gitted/logs/HEAD create mode 100644 tests/resources/status_skipHash/.gitted/logs/refs/heads/main create mode 100644 tests/resources/status_skipHash/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 create mode 100644 tests/resources/status_skipHash/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 create mode 100644 tests/resources/status_skipHash/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c create mode 100644 tests/resources/status_skipHash/.gitted/refs/heads/main create mode 100644 tests/resources/status_skipHash/new_file diff --git a/tests/libgit2/status/worktree.c b/tests/libgit2/status/worktree.c index efbf597a723..bd3cdb9e7d3 100644 --- a/tests/libgit2/status/worktree.c +++ b/tests/libgit2/status/worktree.c @@ -1360,3 +1360,12 @@ void test_status_worktree__at_head_parent(void) git_tree_free(parent_tree); git_status_list_free(statuslist); } + +void test_status_worktree__skip_hash(void) +{ + git_repository *repo = cl_git_sandbox_init("status_skipHash"); + git_index *index; + + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_read(index, true)); +} diff --git a/tests/resources/status_skipHash/.gitted/COMMIT_EDITMSG b/tests/resources/status_skipHash/.gitted/COMMIT_EDITMSG new file mode 100644 index 00000000000..ea450f959b9 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/COMMIT_EDITMSG @@ -0,0 +1 @@ +New file diff --git a/tests/resources/status_skipHash/.gitted/HEAD b/tests/resources/status_skipHash/.gitted/HEAD new file mode 100644 index 00000000000..b870d82622c --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/tests/resources/status_skipHash/.gitted/MERGE_RR b/tests/resources/status_skipHash/.gitted/MERGE_RR new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/status_skipHash/.gitted/config b/tests/resources/status_skipHash/.gitted/config new file mode 100644 index 00000000000..16aebb686c2 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = false + logallrefupdates = true + symlinks = false + ignorecase = true +[index] + skipHash = true diff --git a/tests/resources/status_skipHash/.gitted/description b/tests/resources/status_skipHash/.gitted/description new file mode 100644 index 00000000000..498b267a8c7 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample b/tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample new file mode 100644 index 00000000000..a5d7b84a673 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample b/tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample new file mode 100644 index 00000000000..b58d1184a9d --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample b/tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample new file mode 100644 index 00000000000..23e856f5dee --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + my $last_update_line = ""; + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + $last_update_line = qq[\n"since": $last_update_token,]; + } + my $query = <<" END"; + ["query", "$git_work_tree", {$last_update_line + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/tests/resources/status_skipHash/.gitted/hooks/post-update.sample b/tests/resources/status_skipHash/.gitted/hooks/post-update.sample new file mode 100644 index 00000000000..ec17ec1939b --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample new file mode 100644 index 00000000000..4142082bcb9 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample new file mode 100644 index 00000000000..e144712c85c --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample new file mode 100644 index 00000000000..399eab1924e --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-push.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-push.sample new file mode 100644 index 00000000000..4ce688d32b7 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample new file mode 100644 index 00000000000..6cbef5c370d --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample new file mode 100644 index 00000000000..a1fd29ec148 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample b/tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample new file mode 100644 index 00000000000..10fa14c5ab0 --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample b/tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample new file mode 100644 index 00000000000..af5a0c0018b --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/tests/resources/status_skipHash/.gitted/hooks/update.sample b/tests/resources/status_skipHash/.gitted/hooks/update.sample new file mode 100644 index 00000000000..c4d426bc6ee --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/tests/resources/status_skipHash/.gitted/index b/tests/resources/status_skipHash/.gitted/index new file mode 100644 index 0000000000000000000000000000000000000000..1963fe0d3d48be4a53099966cbd14d342421a38a GIT binary patch literal 137 zcmZ?q402{*U|<4b#?Ef%38=h9^9eq%+;`#$5!{AH+ D>}4ak literal 0 HcmV?d00001 diff --git a/tests/resources/status_skipHash/.gitted/info/exclude b/tests/resources/status_skipHash/.gitted/info/exclude new file mode 100644 index 00000000000..a5196d1be8f --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/resources/status_skipHash/.gitted/logs/HEAD b/tests/resources/status_skipHash/.gitted/logs/HEAD new file mode 100644 index 00000000000..35e1a747dbe --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 34f4c90b237fcb4c677772a6093f3cba239c41a5 Parnic 1708097798 -0600 commit (initial): New file diff --git a/tests/resources/status_skipHash/.gitted/logs/refs/heads/main b/tests/resources/status_skipHash/.gitted/logs/refs/heads/main new file mode 100644 index 00000000000..35e1a747dbe --- /dev/null +++ b/tests/resources/status_skipHash/.gitted/logs/refs/heads/main @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 34f4c90b237fcb4c677772a6093f3cba239c41a5 Parnic 1708097798 -0600 commit (initial): New file diff --git a/tests/resources/status_skipHash/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 b/tests/resources/status_skipHash/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 new file mode 100644 index 0000000000000000000000000000000000000000..0513158cb21d4d3d77b30a4b5d80b8a70ec19815 GIT binary patch literal 510 zcmVF?TCrKxLpRo64Xg@&*}LnPe%?Rrx4dnBKoKJasTivY{EB3Rzz6-<8uosDLv3>U+IYv{No1t@=50=A(I9*4rMPHr0CYysM zBqAvR?045{MMp=l^}1vOV!>@84W3Zloph=PFU#%2^N9@_QUxS887mGu{rKo5TeSnj>BNUy684J0e*G-`Bg-LHWExDb$c2APdZYecO%TXM=DmWF&l$rj$z8I!|NtQK$ z+kUaG)XSopSp0lgbbWZ<38G_;#tZjHWn;(g95h8(yI8roj(1ljVIGZBTrKl+$Rq%* zhUPmbY*%sLAD^``KE}$-?}<0b^NZ!S+I~d*jSl@P>7v!jGxomMP7fxC`LsOlZvb-s zXlv)X@Io9LeI14AbqaZON2ag!!P66fPwBWlf|Fsj4~n1v@m*8e4Do Am;e9( literal 0 HcmV?d00001 diff --git a/tests/resources/status_skipHash/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 b/tests/resources/status_skipHash/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 new file mode 100644 index 0000000000000000000000000000000000000000..7c48fa4f43b779b3bbbc8a8c39fa596877c1e24f GIT binary patch literal 53 zcmV-50LuS(0V^p=O;s>9V=y!@Ff%bx$V)AcPs_|nWw?IuW9n0>+xxGVF(z$a+Mw$w LUcv(aTUZe49NQLZ literal 0 HcmV?d00001 diff --git a/tests/resources/status_skipHash/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c b/tests/resources/status_skipHash/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c new file mode 100644 index 0000000000000000000000000000000000000000..c685321ce69cedebf8744674d239c0e493b89cbb GIT binary patch literal 26 icmb Date: Fri, 16 Feb 2024 09:40:29 -0600 Subject: [PATCH 405/816] Remove unnecessary files --- .../.gitted/hooks/applypatch-msg.sample | 15 -- .../.gitted/hooks/commit-msg.sample | 24 --- .../.gitted/hooks/fsmonitor-watchman.sample | 174 ------------------ .../.gitted/hooks/post-update.sample | 8 - .../.gitted/hooks/pre-applypatch.sample | 14 -- .../.gitted/hooks/pre-commit.sample | 49 ----- .../.gitted/hooks/pre-merge-commit.sample | 13 -- .../.gitted/hooks/pre-push.sample | 53 ------ .../.gitted/hooks/pre-rebase.sample | 169 ----------------- .../.gitted/hooks/pre-receive.sample | 24 --- .../.gitted/hooks/prepare-commit-msg.sample | 42 ----- .../.gitted/hooks/push-to-checkout.sample | 78 -------- .../.gitted/hooks/sendemail-validate.sample | 77 -------- .../.gitted/hooks/update.sample | 128 ------------- 14 files changed, 868 deletions(-) delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/post-update.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-push.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/sendemail-validate.sample delete mode 100644 tests/resources/status_skipHash/.gitted/hooks/update.sample diff --git a/tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample b/tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample deleted file mode 100644 index a5d7b84a673..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/applypatch-msg.sample +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message taken by -# applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. The hook is -# allowed to edit the commit message file. -# -# To enable this hook, rename this file to "applypatch-msg". - -. git-sh-setup -commitmsg="$(git rev-parse --git-path hooks/commit-msg)" -test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} -: diff --git a/tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample b/tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample deleted file mode 100644 index b58d1184a9d..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/commit-msg.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message. -# Called by "git commit" with one argument, the name of the file -# that has the commit message. The hook should exit with non-zero -# status after issuing an appropriate message if it wants to stop the -# commit. The hook is allowed to edit the commit message file. -# -# To enable this hook, rename this file to "commit-msg". - -# Uncomment the below to add a Signed-off-by line to the message. -# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -# hook is more suited to it. -# -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" - -# This example catches duplicate Signed-off-by lines. - -test "" = "$(grep '^Signed-off-by: ' "$1" | - sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { - echo >&2 Duplicate Signed-off-by lines. - exit 1 -} diff --git a/tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample b/tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample deleted file mode 100644 index 23e856f5dee..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/fsmonitor-watchman.sample +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use IPC::Open2; - -# An example hook script to integrate Watchman -# (https://facebook.github.io/watchman/) with git to speed up detecting -# new and modified files. -# -# The hook is passed a version (currently 2) and last update token -# formatted as a string and outputs to stdout a new update token and -# all files that have been modified since the update token. Paths must -# be relative to the root of the working tree and separated by a single NUL. -# -# To enable this hook, rename this file to "query-watchman" and set -# 'git config core.fsmonitor .git/hooks/query-watchman' -# -my ($version, $last_update_token) = @ARGV; - -# Uncomment for debugging -# print STDERR "$0 $version $last_update_token\n"; - -# Check the hook interface version -if ($version ne 2) { - die "Unsupported query-fsmonitor hook version '$version'.\n" . - "Falling back to scanning...\n"; -} - -my $git_work_tree = get_working_dir(); - -my $retry = 1; - -my $json_pkg; -eval { - require JSON::XS; - $json_pkg = "JSON::XS"; - 1; -} or do { - require JSON::PP; - $json_pkg = "JSON::PP"; -}; - -launch_watchman(); - -sub launch_watchman { - my $o = watchman_query(); - if (is_work_tree_watched($o)) { - output_result($o->{clock}, @{$o->{files}}); - } -} - -sub output_result { - my ($clockid, @files) = @_; - - # Uncomment for debugging watchman output - # open (my $fh, ">", ".git/watchman-output.out"); - # binmode $fh, ":utf8"; - # print $fh "$clockid\n@files\n"; - # close $fh; - - binmode STDOUT, ":utf8"; - print $clockid; - print "\0"; - local $, = "\0"; - print @files; -} - -sub watchman_clock { - my $response = qx/watchman clock "$git_work_tree"/; - die "Failed to get clock id on '$git_work_tree'.\n" . - "Falling back to scanning...\n" if $? != 0; - - return $json_pkg->new->utf8->decode($response); -} - -sub watchman_query { - my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') - or die "open2() failed: $!\n" . - "Falling back to scanning...\n"; - - # In the query expression below we're asking for names of files that - # changed since $last_update_token but not from the .git folder. - # - # To accomplish this, we're using the "since" generator to use the - # recency index to select candidate nodes and "fields" to limit the - # output to file names only. Then we're using the "expression" term to - # further constrain the results. - my $last_update_line = ""; - if (substr($last_update_token, 0, 1) eq "c") { - $last_update_token = "\"$last_update_token\""; - $last_update_line = qq[\n"since": $last_update_token,]; - } - my $query = <<" END"; - ["query", "$git_work_tree", {$last_update_line - "fields": ["name"], - "expression": ["not", ["dirname", ".git"]] - }] - END - - # Uncomment for debugging the watchman query - # open (my $fh, ">", ".git/watchman-query.json"); - # print $fh $query; - # close $fh; - - print CHLD_IN $query; - close CHLD_IN; - my $response = do {local $/; }; - - # Uncomment for debugging the watch response - # open ($fh, ">", ".git/watchman-response.json"); - # print $fh $response; - # close $fh; - - die "Watchman: command returned no output.\n" . - "Falling back to scanning...\n" if $response eq ""; - die "Watchman: command returned invalid output: $response\n" . - "Falling back to scanning...\n" unless $response =~ /^\{/; - - return $json_pkg->new->utf8->decode($response); -} - -sub is_work_tree_watched { - my ($output) = @_; - my $error = $output->{error}; - if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { - $retry--; - my $response = qx/watchman watch "$git_work_tree"/; - die "Failed to make watchman watch '$git_work_tree'.\n" . - "Falling back to scanning...\n" if $? != 0; - $output = $json_pkg->new->utf8->decode($response); - $error = $output->{error}; - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - # Uncomment for debugging watchman output - # open (my $fh, ">", ".git/watchman-output.out"); - # close $fh; - - # Watchman will always return all files on the first query so - # return the fast "everything is dirty" flag to git and do the - # Watchman query just to get it over with now so we won't pay - # the cost in git to look up each individual file. - my $o = watchman_clock(); - $error = $output->{error}; - - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - output_result($o->{clock}, ("/")); - $last_update_token = $o->{clock}; - - eval { launch_watchman() }; - return 0; - } - - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - return 1; -} - -sub get_working_dir { - my $working_dir; - if ($^O =~ 'msys' || $^O =~ 'cygwin') { - $working_dir = Win32::GetCwd(); - $working_dir =~ tr/\\/\//; - } else { - require Cwd; - $working_dir = Cwd::cwd(); - } - - return $working_dir; -} diff --git a/tests/resources/status_skipHash/.gitted/hooks/post-update.sample b/tests/resources/status_skipHash/.gitted/hooks/post-update.sample deleted file mode 100644 index ec17ec1939b..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/post-update.sample +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare a packed repository for use over -# dumb transports. -# -# To enable this hook, rename this file to "post-update". - -exec git update-server-info diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample deleted file mode 100644 index 4142082bcb9..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/pre-applypatch.sample +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed -# by applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-applypatch". - -. git-sh-setup -precommit="$(git rev-parse --git-path hooks/pre-commit)" -test -x "$precommit" && exec "$precommit" ${1+"$@"} -: diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample deleted file mode 100644 index e144712c85c..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/pre-commit.sample +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=$(git hash-object -t tree /dev/null) -fi - -# If you want to allow non-ASCII filenames set this variable to true. -allownonascii=$(git config --type=bool hooks.allownonascii) - -# Redirect output to stderr. -exec 1>&2 - -# Cross platform projects tend to avoid non-ASCII filenames; prevent -# them from being added to the repository. We exploit the fact that the -# printable range starts at the space character and ends with tilde. -if [ "$allownonascii" != "true" ] && - # Note that the use of brackets around a tr range is ok here, (it's - # even required, for portability to Solaris 10's /usr/bin/tr), since - # the square bracket bytes happen to fall in the designated range. - test $(git diff --cached --name-only --diff-filter=A -z $against | - LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 -then - cat <<\EOF -Error: Attempt to add a non-ASCII file name. - -This can cause problems if you want to work with people on other platforms. - -To be portable it is advisable to rename the file. - -If you know what you are doing you can disable this check using: - - git config hooks.allownonascii true -EOF - exit 1 -fi - -# If there are whitespace errors, print the offending file names and fail. -exec git diff-index --check --cached $against -- diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample deleted file mode 100644 index 399eab1924e..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/pre-merge-commit.sample +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git merge" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message to -# stderr if it wants to stop the merge commit. -# -# To enable this hook, rename this file to "pre-merge-commit". - -. git-sh-setup -test -x "$GIT_DIR/hooks/pre-commit" && - exec "$GIT_DIR/hooks/pre-commit" -: diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-push.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-push.sample deleted file mode 100644 index 4ce688d32b7..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/pre-push.sample +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# An example hook script to verify what is about to be pushed. Called by "git -# push" after it has checked the remote status, but before anything has been -# pushed. If this script exits with a non-zero status nothing will be pushed. -# -# This hook is called with the following parameters: -# -# $1 -- Name of the remote to which the push is being done -# $2 -- URL to which the push is being done -# -# If pushing without using a named remote those arguments will be equal. -# -# Information about the commits which are being pushed is supplied as lines to -# the standard input in the form: -# -# -# -# This sample shows how to prevent push of commits where the log message starts -# with "WIP" (work in progress). - -remote="$1" -url="$2" - -zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" - exit 1 - fi - fi -done - -exit 0 diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample deleted file mode 100644 index 6cbef5c370d..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/pre-rebase.sample +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006, 2008 Junio C Hamano -# -# The "pre-rebase" hook is run just before "git rebase" starts doing -# its job, and can prevent the command from running by exiting with -# non-zero status. -# -# The hook is called with the following parameters: -# -# $1 -- the upstream the series was forked from. -# $2 -- the branch being rebased (or empty when rebasing the current branch). -# -# This sample shows how to prevent topic branches that are already -# merged to 'next' branch from getting rebased, because allowing it -# would result in rebasing already published history. - -publish=next -basebranch="$1" -if test "$#" = 2 -then - topic="refs/heads/$2" -else - topic=`git symbolic-ref HEAD` || - exit 0 ;# we do not interrupt rebasing detached HEAD -fi - -case "$topic" in -refs/heads/??/*) - ;; -*) - exit 0 ;# we do not interrupt others. - ;; -esac - -# Now we are dealing with a topic branch being rebased -# on top of master. Is it OK to rebase it? - -# Does the topic really exist? -git show-ref -q "$topic" || { - echo >&2 "No such branch $topic" - exit 1 -} - -# Is topic fully merged to master? -not_in_master=`git rev-list --pretty=oneline ^master "$topic"` -if test -z "$not_in_master" -then - echo >&2 "$topic is fully merged to master; better remove it." - exit 1 ;# we could allow it, but there is no point. -fi - -# Is topic ever merged to next? If so you should not be rebasing it. -only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` -only_next_2=`git rev-list ^master ${publish} | sort` -if test "$only_next_1" = "$only_next_2" -then - not_in_topic=`git rev-list "^$topic" master` - if test -z "$not_in_topic" - then - echo >&2 "$topic is already up to date with master" - exit 1 ;# we could allow it, but there is no point. - else - exit 0 - fi -else - not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` - /usr/bin/perl -e ' - my $topic = $ARGV[0]; - my $msg = "* $topic has commits already merged to public branch:\n"; - my (%not_in_next) = map { - /^([0-9a-f]+) /; - ($1 => 1); - } split(/\n/, $ARGV[1]); - for my $elem (map { - /^([0-9a-f]+) (.*)$/; - [$1 => $2]; - } split(/\n/, $ARGV[2])) { - if (!exists $not_in_next{$elem->[0]}) { - if ($msg) { - print STDERR $msg; - undef $msg; - } - print STDERR " $elem->[1]\n"; - } - } - ' "$topic" "$not_in_next" "$not_in_master" - exit 1 -fi - -<<\DOC_END - -This sample hook safeguards topic branches that have been -published from being rewound. - -The workflow assumed here is: - - * Once a topic branch forks from "master", "master" is never - merged into it again (either directly or indirectly). - - * Once a topic branch is fully cooked and merged into "master", - it is deleted. If you need to build on top of it to correct - earlier mistakes, a new topic branch is created by forking at - the tip of the "master". This is not strictly necessary, but - it makes it easier to keep your history simple. - - * Whenever you need to test or publish your changes to topic - branches, merge them into "next" branch. - -The script, being an example, hardcodes the publish branch name -to be "next", but it is trivial to make it configurable via -$GIT_DIR/config mechanism. - -With this workflow, you would want to know: - -(1) ... if a topic branch has ever been merged to "next". Young - topic branches can have stupid mistakes you would rather - clean up before publishing, and things that have not been - merged into other branches can be easily rebased without - affecting other people. But once it is published, you would - not want to rewind it. - -(2) ... if a topic branch has been fully merged to "master". - Then you can delete it. More importantly, you should not - build on top of it -- other people may already want to - change things related to the topic as patches against your - "master", so if you need further changes, it is better to - fork the topic (perhaps with the same name) afresh from the - tip of "master". - -Let's look at this example: - - o---o---o---o---o---o---o---o---o---o "next" - / / / / - / a---a---b A / / - / / / / - / / c---c---c---c B / - / / / \ / - / / / b---b C \ / - / / / / \ / - ---o---o---o---o---o---o---o---o---o---o---o "master" - - -A, B and C are topic branches. - - * A has one fix since it was merged up to "next". - - * B has finished. It has been fully merged up to "master" and "next", - and is ready to be deleted. - - * C has not merged to "next" at all. - -We would want to allow C to be rebased, refuse A, and encourage -B to be deleted. - -To compute (1): - - git rev-list ^master ^topic next - git rev-list ^master next - - if these match, topic has not merged in next at all. - -To compute (2): - - git rev-list master..topic - - if this is empty, it is fully merged to "master". - -DOC_END diff --git a/tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample b/tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample deleted file mode 100644 index a1fd29ec148..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/pre-receive.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to make use of push options. -# The example simply echoes all push options that start with 'echoback=' -# and rejects all pushes when the "reject" push option is used. -# -# To enable this hook, rename this file to "pre-receive". - -if test -n "$GIT_PUSH_OPTION_COUNT" -then - i=0 - while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" - do - eval "value=\$GIT_PUSH_OPTION_$i" - case "$value" in - echoback=*) - echo "echo from the pre-receive-hook: ${value#*=}" >&2 - ;; - reject) - exit 1 - esac - i=$((i + 1)) - done -fi diff --git a/tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample b/tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample deleted file mode 100644 index 10fa14c5ab0..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/prepare-commit-msg.sample +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare the commit log message. -# Called by "git commit" with the name of the file that has the -# commit message, followed by the description of the commit -# message's source. The hook's purpose is to edit the commit -# message file. If the hook fails with a non-zero status, -# the commit is aborted. -# -# To enable this hook, rename this file to "prepare-commit-msg". - -# This hook includes three examples. The first one removes the -# "# Please enter the commit message..." help message. -# -# The second includes the output of "git diff --name-status -r" -# into the message, just before the "git status" output. It is -# commented because it doesn't cope with --amend or with squashed -# commits. -# -# The third example adds a Signed-off-by line to the message, that can -# still be edited. This is rarely a good idea. - -COMMIT_MSG_FILE=$1 -COMMIT_SOURCE=$2 -SHA1=$3 - -/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" - -# case "$COMMIT_SOURCE,$SHA1" in -# ,|template,) -# /usr/bin/perl -i.bak -pe ' -# print "\n" . `git diff --cached --name-status -r` -# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; -# *) ;; -# esac - -# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" -# if test -z "$COMMIT_SOURCE" -# then -# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" -# fi diff --git a/tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample b/tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample deleted file mode 100644 index af5a0c0018b..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/push-to-checkout.sample +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -# An example hook script to update a checked-out tree on a git push. -# -# This hook is invoked by git-receive-pack(1) when it reacts to git -# push and updates reference(s) in its repository, and when the push -# tries to update the branch that is currently checked out and the -# receive.denyCurrentBranch configuration variable is set to -# updateInstead. -# -# By default, such a push is refused if the working tree and the index -# of the remote repository has any difference from the currently -# checked out commit; when both the working tree and the index match -# the current commit, they are updated to match the newly pushed tip -# of the branch. This hook is to be used to override the default -# behaviour; however the code below reimplements the default behaviour -# as a starting point for convenient modification. -# -# The hook receives the commit with which the tip of the current -# branch is going to be updated: -commit=$1 - -# It can exit with a non-zero status to refuse the push (when it does -# so, it must not modify the index or the working tree). -die () { - echo >&2 "$*" - exit 1 -} - -# Or it can make any necessary changes to the working tree and to the -# index to bring them to the desired state when the tip of the current -# branch is updated to the new commit, and exit with a zero status. -# -# For example, the hook can simply run git read-tree -u -m HEAD "$1" -# in order to emulate git fetch that is run in the reverse direction -# with git push, as the two-tree form of git read-tree -u -m is -# essentially the same as git switch or git checkout that switches -# branches while keeping the local changes in the working tree that do -# not interfere with the difference between the branches. - -# The below is a more-or-less exact translation to shell of the C code -# for the default behaviour for git's push-to-checkout hook defined in -# the push_to_deploy() function in builtin/receive-pack.c. -# -# Note that the hook will be executed from the repository directory, -# not from the working tree, so if you want to perform operations on -# the working tree, you will have to adapt your code accordingly, e.g. -# by adding "cd .." or using relative paths. - -if ! git update-index -q --ignore-submodules --refresh -then - die "Up-to-date check failed" -fi - -if ! git diff-files --quiet --ignore-submodules -- -then - die "Working directory has unstaged changes" -fi - -# This is a rough translation of: -# -# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX -if git cat-file -e HEAD 2>/dev/null -then - head=HEAD -else - head=$(git hash-object -t tree --stdin &2 - exit 1 -} - -unset GIT_DIR GIT_WORK_TREE -cd "$worktree" && - -if grep -q "^diff --git " "$1" -then - validate_patch "$1" -else - validate_cover_letter "$1" -fi && - -if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" -then - git config --unset-all sendemail.validateWorktree && - trap 'git worktree remove -ff "$worktree"' EXIT && - validate_series -fi diff --git a/tests/resources/status_skipHash/.gitted/hooks/update.sample b/tests/resources/status_skipHash/.gitted/hooks/update.sample deleted file mode 100644 index c4d426bc6ee..00000000000 --- a/tests/resources/status_skipHash/.gitted/hooks/update.sample +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/sh -# -# An example hook script to block unannotated tags from entering. -# Called by "git receive-pack" with arguments: refname sha1-old sha1-new -# -# To enable this hook, rename this file to "update". -# -# Config -# ------ -# hooks.allowunannotated -# This boolean sets whether unannotated tags will be allowed into the -# repository. By default they won't be. -# hooks.allowdeletetag -# This boolean sets whether deleting tags will be allowed in the -# repository. By default they won't be. -# hooks.allowmodifytag -# This boolean sets whether a tag may be modified after creation. By default -# it won't be. -# hooks.allowdeletebranch -# This boolean sets whether deleting branches will be allowed in the -# repository. By default they won't be. -# hooks.denycreatebranch -# This boolean sets whether remotely creating branches will be denied -# in the repository. By default this is allowed. -# - -# --- Command line -refname="$1" -oldrev="$2" -newrev="$3" - -# --- Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 )" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 " >&2 - exit 1 -fi - -# --- Config -allowunannotated=$(git config --type=bool hooks.allowunannotated) -allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) -denycreatebranch=$(git config --type=bool hooks.denycreatebranch) -allowdeletetag=$(git config --type=bool hooks.allowdeletetag) -allowmodifytag=$(git config --type=bool hooks.allowmodifytag) - -# check for no description -projectdesc=$(sed -e '1q' "$GIT_DIR/description") -case "$projectdesc" in -"Unnamed repository"* | "") - echo "*** Project description file hasn't been set" >&2 - exit 1 - ;; -esac - -# --- Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero=$(git hash-object --stdin &2 - echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 - exit 1 - fi - ;; - refs/tags/*,delete) - # delete tag - if [ "$allowdeletetag" != "true" ]; then - echo "*** Deleting a tag is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/tags/*,tag) - # annotated tag - if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 - then - echo "*** Tag '$refname' already exists." >&2 - echo "*** Modifying a tag is not allowed in this repository." >&2 - exit 1 - fi - ;; - refs/heads/*,commit) - # branch - if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then - echo "*** Creating a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/heads/*,delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/remotes/*,commit) - # tracking branch - ;; - refs/remotes/*,delete) - # delete tracking branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a tracking branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - # Anything else (is there anything else?) - echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 - exit 1 - ;; -esac - -# --- Finished -exit 0 From d73078773e8f68dd7bceb70d0887846ef6a9e201 Mon Sep 17 00:00:00 2001 From: parnic Date: Sat, 17 Feb 2024 08:13:46 -0600 Subject: [PATCH 406/816] Update src/libgit2/index.c Co-authored-by: Edward Thomson --- src/libgit2/index.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 86f14fdfc41..f4df9f64392 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -2850,7 +2850,8 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) /* * SHA-1 or SHA-256 (depending on the repository's object format) * over the content of the index file before this checksum. - * Note: checksum may be 0 if index.skipHash is set to true. + * Note: checksum may be 0 if the index was written by a client + * where index.skipHash was set to true. */ if (memcmp(zero_checksum, buffer, checksum_size) != 0 && memcmp(checksum, buffer, checksum_size) != 0) { error = index_error_invalid( From b69d927243e0137342fb093ec3c9203df6d201d5 Mon Sep 17 00:00:00 2001 From: parnic Date: Sat, 17 Feb 2024 08:13:54 -0600 Subject: [PATCH 407/816] Update src/libgit2/index.c Co-authored-by: Edward Thomson --- src/libgit2/index.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index f4df9f64392..670fbc5cf15 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -2853,7 +2853,8 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) * Note: checksum may be 0 if the index was written by a client * where index.skipHash was set to true. */ - if (memcmp(zero_checksum, buffer, checksum_size) != 0 && memcmp(checksum, buffer, checksum_size) != 0) { + if (memcmp(zero_checksum, buffer, checksum_size) != 0 && + memcmp(checksum, buffer, checksum_size) != 0) { error = index_error_invalid( "calculated checksum does not match expected"); goto done; From 6a218c2dc14f8989616b62e441ac161c820fa4f2 Mon Sep 17 00:00:00 2001 From: parnic Date: Sat, 17 Feb 2024 08:14:09 -0600 Subject: [PATCH 408/816] Update tests/libgit2/status/worktree.c Co-authored-by: Edward Thomson --- tests/libgit2/status/worktree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libgit2/status/worktree.c b/tests/libgit2/status/worktree.c index bd3cdb9e7d3..bf99461871c 100644 --- a/tests/libgit2/status/worktree.c +++ b/tests/libgit2/status/worktree.c @@ -1363,7 +1363,7 @@ void test_status_worktree__at_head_parent(void) void test_status_worktree__skip_hash(void) { - git_repository *repo = cl_git_sandbox_init("status_skipHash"); + git_repository *repo = cl_git_sandbox_init("status_skiphash"); git_index *index; cl_git_pass(git_repository_index(&index, repo)); From a0dbf6044785a914b0c2c1b4f6601b54a153374e Mon Sep 17 00:00:00 2001 From: Parnic Date: Sat, 17 Feb 2024 08:15:42 -0600 Subject: [PATCH 409/816] Change capitalization per PR feedback --- .../.gitted/COMMIT_EDITMSG | 0 .../.gitted/HEAD | 0 .../.gitted/MERGE_RR | 0 .../.gitted/config | 0 .../.gitted/description | 0 .../.gitted/index | Bin .../.gitted/info/exclude | 0 .../.gitted/logs/HEAD | 0 .../.gitted/logs/refs/heads/main | 0 .../34/f4c90b237fcb4c677772a6093f3cba239c41a5 | Bin .../71/a21e67674e9717aa7380e5782ec5e070a8d7e0 | Bin .../d7/c1f165e51adbbfd7760162b7a5802d4117740c | Bin .../.gitted/refs/heads/main | 0 .../{status_skipHash => status_skiphash}/new_file | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/COMMIT_EDITMSG (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/HEAD (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/MERGE_RR (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/config (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/description (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/index (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/info/exclude (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/logs/HEAD (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/logs/refs/heads/main (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c (100%) rename tests/resources/{status_skipHash => status_skiphash}/.gitted/refs/heads/main (100%) rename tests/resources/{status_skipHash => status_skiphash}/new_file (100%) diff --git a/tests/resources/status_skipHash/.gitted/COMMIT_EDITMSG b/tests/resources/status_skiphash/.gitted/COMMIT_EDITMSG similarity index 100% rename from tests/resources/status_skipHash/.gitted/COMMIT_EDITMSG rename to tests/resources/status_skiphash/.gitted/COMMIT_EDITMSG diff --git a/tests/resources/status_skipHash/.gitted/HEAD b/tests/resources/status_skiphash/.gitted/HEAD similarity index 100% rename from tests/resources/status_skipHash/.gitted/HEAD rename to tests/resources/status_skiphash/.gitted/HEAD diff --git a/tests/resources/status_skipHash/.gitted/MERGE_RR b/tests/resources/status_skiphash/.gitted/MERGE_RR similarity index 100% rename from tests/resources/status_skipHash/.gitted/MERGE_RR rename to tests/resources/status_skiphash/.gitted/MERGE_RR diff --git a/tests/resources/status_skipHash/.gitted/config b/tests/resources/status_skiphash/.gitted/config similarity index 100% rename from tests/resources/status_skipHash/.gitted/config rename to tests/resources/status_skiphash/.gitted/config diff --git a/tests/resources/status_skipHash/.gitted/description b/tests/resources/status_skiphash/.gitted/description similarity index 100% rename from tests/resources/status_skipHash/.gitted/description rename to tests/resources/status_skiphash/.gitted/description diff --git a/tests/resources/status_skipHash/.gitted/index b/tests/resources/status_skiphash/.gitted/index similarity index 100% rename from tests/resources/status_skipHash/.gitted/index rename to tests/resources/status_skiphash/.gitted/index diff --git a/tests/resources/status_skipHash/.gitted/info/exclude b/tests/resources/status_skiphash/.gitted/info/exclude similarity index 100% rename from tests/resources/status_skipHash/.gitted/info/exclude rename to tests/resources/status_skiphash/.gitted/info/exclude diff --git a/tests/resources/status_skipHash/.gitted/logs/HEAD b/tests/resources/status_skiphash/.gitted/logs/HEAD similarity index 100% rename from tests/resources/status_skipHash/.gitted/logs/HEAD rename to tests/resources/status_skiphash/.gitted/logs/HEAD diff --git a/tests/resources/status_skipHash/.gitted/logs/refs/heads/main b/tests/resources/status_skiphash/.gitted/logs/refs/heads/main similarity index 100% rename from tests/resources/status_skipHash/.gitted/logs/refs/heads/main rename to tests/resources/status_skiphash/.gitted/logs/refs/heads/main diff --git a/tests/resources/status_skipHash/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 b/tests/resources/status_skiphash/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 similarity index 100% rename from tests/resources/status_skipHash/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 rename to tests/resources/status_skiphash/.gitted/objects/34/f4c90b237fcb4c677772a6093f3cba239c41a5 diff --git a/tests/resources/status_skipHash/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 b/tests/resources/status_skiphash/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 similarity index 100% rename from tests/resources/status_skipHash/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 rename to tests/resources/status_skiphash/.gitted/objects/71/a21e67674e9717aa7380e5782ec5e070a8d7e0 diff --git a/tests/resources/status_skipHash/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c b/tests/resources/status_skiphash/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c similarity index 100% rename from tests/resources/status_skipHash/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c rename to tests/resources/status_skiphash/.gitted/objects/d7/c1f165e51adbbfd7760162b7a5802d4117740c diff --git a/tests/resources/status_skipHash/.gitted/refs/heads/main b/tests/resources/status_skiphash/.gitted/refs/heads/main similarity index 100% rename from tests/resources/status_skipHash/.gitted/refs/heads/main rename to tests/resources/status_skiphash/.gitted/refs/heads/main diff --git a/tests/resources/status_skipHash/new_file b/tests/resources/status_skiphash/new_file similarity index 100% rename from tests/resources/status_skipHash/new_file rename to tests/resources/status_skiphash/new_file From e696528aa849a3911b756b0e5d32abaca5370358 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 17 Feb 2024 14:27:19 +0000 Subject: [PATCH 410/816] Update cmake/SelectHTTPSBackend.cmake --- cmake/SelectHTTPSBackend.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index fbc2adc147f..d293001f567 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -55,6 +55,7 @@ if(USE_HTTPS) set(GIT_OPENSSL 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES}) + # Static OpenSSL (lib crypto.a) requires libdl, include it explicitly if(LINK_WITH_STATIC_LIBRARIES STREQUAL ON) list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_DL_LIBS}) endif() From 8422a6386ea7458799a080ce073b530b663aa0cc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 17 Feb 2024 15:07:53 +0000 Subject: [PATCH 411/816] config: avoid unnecessary copy in rename_section We can just append the escaped regex to the value buffer, we don't need create a new value buffer and then append _that_. --- src/libgit2/config.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index d11e76d9577..04f3ec2fee2 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -1509,35 +1509,31 @@ static int rename_config_entries_cb( int error = 0; struct rename_data *data = (struct rename_data *)payload; size_t base_len = git_str_len(data->name); - git_str raw_value = GIT_STR_INIT, value = GIT_STR_INIT; - - if (base_len > 0 && - !(error = git_str_puts(data->name, entry->name + data->old_len))) - { - error = git_config_set_multivar( - data->config, git_str_cstr(data->name), "^$", - entry->value); + git_str value = GIT_STR_INIT; + + if (base_len > 0) { + if ((error = git_str_puts(data->name, + entry->name + data->old_len)) < 0 || + (error = git_config_set_multivar( + data->config, git_str_cstr(data->name), "^$", + entry->value)) < 0) + goto cleanup; } - if (!error) { - if ((error = git_str_puts_escape_regex( - &raw_value, entry->value))) - goto cleanup; - git_str_grow(&value, git_str_len(&raw_value) + 2); - git_str_putc(&value, '^'); - git_str_puts(&value, git_str_cstr(&raw_value)); - git_str_putc(&value, '$'); - if (git_str_oom(&value)) { - error = -1; - goto cleanup; - } - error = git_config_delete_multivar( - data->config, entry->name, git_str_cstr(&value)); + git_str_putc(&value, '^'); + git_str_puts_escape_regex(&value, entry->value); + git_str_putc(&value, '$'); + + if (git_str_oom(&value)) { + error = -1; + goto cleanup; } + error = git_config_delete_multivar( + data->config, entry->name, git_str_cstr(&value)); + cleanup: git_str_truncate(data->name, base_len); - git_str_dispose(&raw_value); git_str_dispose(&value); return error; } From 913d4ea251366f006a5ced6ed1804acf973a6ce6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 17 Feb 2024 15:20:12 +0000 Subject: [PATCH 412/816] skiphash: free the index --- tests/libgit2/status/worktree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/libgit2/status/worktree.c b/tests/libgit2/status/worktree.c index bf99461871c..8a2ea9cb674 100644 --- a/tests/libgit2/status/worktree.c +++ b/tests/libgit2/status/worktree.c @@ -1368,4 +1368,5 @@ void test_status_worktree__skip_hash(void) cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_read(index, true)); + git_index_free(index); } From 928ac176f4949481b9eea4a172af5bc4a2be2779 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 00:55:46 +0000 Subject: [PATCH 413/816] meta: add dependency tag to release.yml --- .github/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/release.yml b/.github/release.yml index 099e3803fa6..4d4e31860c2 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -27,6 +27,9 @@ changelog: - title: Git compatibility fixes labels: - git compatibility + - title: Dependency updates + labels: + - dependency - title: Other changes labels: - '*' From 49487b5e39a4895085450897e9335f60c252b811 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 19 Feb 2024 08:38:34 -0800 Subject: [PATCH 414/816] clar: canonicalize temp sandbox directory everywhere We currently only canonicalize the temp sandbox directory on macOS, which is critical since `/tmp` is really `/private/tmp`. However, we should do it everywhere, so that tests can actually expect a consistent outcome by looking at `clar_sandbox_path()`. --- tests/clar/clar/sandbox.h | 45 ++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/tests/clar/clar/sandbox.h b/tests/clar/clar/sandbox.h index 0ba1479620a..0688374f8d6 100644 --- a/tests/clar/clar/sandbox.h +++ b/tests/clar/clar/sandbox.h @@ -2,7 +2,8 @@ #include #endif -static char _clar_path[4096 + 1]; +#define CLAR_PATH_MAX 4096 +static char _clar_path[CLAR_PATH_MAX]; static int is_valid_tmp_path(const char *path) @@ -35,10 +36,9 @@ find_tmp_path(char *buffer, size_t length) continue; if (is_valid_tmp_path(env)) { -#ifdef __APPLE__ - if (length >= PATH_MAX && realpath(env, buffer) != NULL) - return 0; -#endif + if (strlen(env) + 1 > CLAR_PATH_MAX) + return -1; + strncpy(buffer, env, length - 1); buffer[length - 1] = '\0'; return 0; @@ -47,10 +47,6 @@ find_tmp_path(char *buffer, size_t length) /* If the environment doesn't say anything, try to use /tmp */ if (is_valid_tmp_path("/tmp")) { -#ifdef __APPLE__ - if (length >= PATH_MAX && realpath("/tmp", buffer) != NULL) - return 0; -#endif strncpy(buffer, "/tmp", length - 1); buffer[length - 1] = '\0'; return 0; @@ -75,6 +71,34 @@ find_tmp_path(char *buffer, size_t length) return -1; } +static int canonicalize_tmp_path(char *buffer) +{ +#ifdef _WIN32 + char tmp[CLAR_PATH_MAX]; + DWORD ret; + + ret = GetFullPathName(buffer, CLAR_PATH_MAX, tmp, NULL); + + if (ret == 0 || ret > CLAR_PATH_MAX) + return -1; + + ret = GetLongPathName(tmp, buffer, CLAR_PATH_MAX); + + if (ret == 0 || ret > CLAR_PATH_MAX) + return -1; + + return 0; +#else + char tmp[CLAR_PATH_MAX]; + + if (realpath(buffer, tmp) == NULL) + return -1; + + strcpy(buffer, tmp); + return 0; +#endif +} + static void clar_unsandbox(void) { if (_clar_path[0] == '\0') @@ -95,7 +119,8 @@ static int build_sandbox_path(void) size_t len; - if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0) + if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0 || + canonicalize_tmp_path(_clar_path) < 0) return -1; len = strlen(_clar_path); From bec1d7b7b073758549d1d7484fab753b889acbfc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 00:02:47 +0000 Subject: [PATCH 415/816] path: provide a helper to compute len with trailing slashes We may need to strip multiple slashes at the end of a path; provide a method to do so. --- src/util/fs_path.c | 10 ++++++++++ src/util/fs_path.h | 6 ++++++ tests/util/path.c | 12 ++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/util/fs_path.c b/src/util/fs_path.c index ab64778c23e..9d5c99eab81 100644 --- a/src/util/fs_path.c +++ b/src/util/fs_path.c @@ -419,6 +419,16 @@ int git_fs_path_to_dir(git_str *path) return git_str_oom(path) ? -1 : 0; } +size_t git_fs_path_dirlen(const char *path) +{ + size_t len = strlen(path); + + while (len > 1 && path[len - 1] == '/') + len--; + + return len; +} + void git_fs_path_string_to_dir(char *path, size_t size) { size_t end = strlen(path); diff --git a/src/util/fs_path.h b/src/util/fs_path.h index e5ca6737818..34e491eb919 100644 --- a/src/util/fs_path.h +++ b/src/util/fs_path.h @@ -86,6 +86,12 @@ extern int git_fs_path_to_dir(git_str *path); */ extern void git_fs_path_string_to_dir(char *path, size_t size); +/** + * Provides the length of the given path string with no trailing + * slashes. + */ +size_t git_fs_path_dirlen(const char *path); + /** * Taken from git.git; returns nonzero if the given path is "." or "..". */ diff --git a/tests/util/path.c b/tests/util/path.c index 02ec42fcea2..38a59392521 100644 --- a/tests/util/path.c +++ b/tests/util/path.c @@ -766,3 +766,15 @@ void test_path__validate_current_user_ownership(void) cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "/path/does/not/exist")); #endif } + +void test_path__dirlen(void) +{ + cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf")); + cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf/")); + cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf//")); + cl_assert_equal_sz(3, git_fs_path_dirlen("foo////")); + cl_assert_equal_sz(3, git_fs_path_dirlen("foo")); + cl_assert_equal_sz(1, git_fs_path_dirlen("/")); + cl_assert_equal_sz(1, git_fs_path_dirlen("////")); + cl_assert_equal_sz(0, git_fs_path_dirlen("")); +} From beea99b08234a7e0de3a3c7f739260527d38a6f1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 07:46:19 -0800 Subject: [PATCH 416/816] path: provide an is_root helper method We may quickly want to determine if the given path is the root path ('/') on POSIX, or the root of a drive letter (eg, 'A:/', 'C:\') on Windows. --- src/util/fs_path.h | 17 +++++++++++++++++ tests/util/path/core.c | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/util/fs_path.h b/src/util/fs_path.h index 34e491eb919..43f7951adde 100644 --- a/src/util/fs_path.h +++ b/src/util/fs_path.h @@ -92,6 +92,23 @@ extern void git_fs_path_string_to_dir(char *path, size_t size); */ size_t git_fs_path_dirlen(const char *path); +/** + * Returns nonzero if the given path is a filesystem root; on Windows, this + * means a drive letter (eg `A:/`, `C:\`). On POSIX this is `/`. + */ +GIT_INLINE(int) git_fs_path_is_root(const char *name) +{ +#ifdef GIT_WIN32 + if (((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z')) && + name[1] == ':' && + (name[2] == '/' || name[2] == '\\') && + name[3] == '\0') + return 1; +#endif + + return (name[0] == '/' && name[1] == '\0'); +} + /** * Taken from git.git; returns nonzero if the given path is "." or "..". */ diff --git a/tests/util/path/core.c b/tests/util/path/core.c index f30f6c01b0d..41d9b02040f 100644 --- a/tests/util/path/core.c +++ b/tests/util/path/core.c @@ -341,3 +341,29 @@ void test_path_core__join_unrooted_respects_funny_windows_roots(void) test_join_unrooted("💩:/foo/bar/foobar", 13, "💩:/foo/bar/foobar", "💩:/foo/bar"); test_join_unrooted("💩:/foo/bar/foobar", 9, "💩:/foo/bar/foobar", "💩:/foo/"); } + +void test_path_core__is_root(void) +{ + cl_assert_equal_b(true, git_fs_path_is_root("/")); + cl_assert_equal_b(false, git_fs_path_is_root("//")); + cl_assert_equal_b(false, git_fs_path_is_root("foo/")); + cl_assert_equal_b(false, git_fs_path_is_root("/foo/")); + cl_assert_equal_b(false, git_fs_path_is_root("/foo")); + cl_assert_equal_b(false, git_fs_path_is_root("\\")); + +#ifdef GIT_WIN32 + cl_assert_equal_b(true, git_fs_path_is_root("A:\\")); + cl_assert_equal_b(false, git_fs_path_is_root("B:\\foo")); + cl_assert_equal_b(false, git_fs_path_is_root("B:\\foo\\")); + cl_assert_equal_b(true, git_fs_path_is_root("C:\\")); + cl_assert_equal_b(true, git_fs_path_is_root("c:\\")); + cl_assert_equal_b(true, git_fs_path_is_root("z:\\")); + cl_assert_equal_b(false, git_fs_path_is_root("z:\\\\")); + cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost")); + cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\")); + cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\c$\\")); + cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\c$\\Foo")); + cl_assert_equal_b(false, git_fs_path_is_root("\\\\localhost\\c$\\Foo\\")); + cl_assert_equal_b(false, git_fs_path_is_root("\\\\Volume\\12345\\Foo\\Bar.txt")); +#endif +} From f43aa1adb50666e258d2412230cf93f6a493ae05 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 19 Feb 2024 07:05:41 -0800 Subject: [PATCH 417/816] util: move path tests to path::core Clar handles multiple levels of hierarchy in a test name _but_ it does so assuming that there are not tests at a parent folder level. In other words, if you have some tests at path/core.c and path/win32.c, then you cannot have tests in path.c. If you have tests in path.c, then the things in path/*.c will be ignored. Move the tests in path.c into path/core.c. --- tests/util/path.c | 780 ----------------------------------------- tests/util/path/core.c | 778 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 778 insertions(+), 780 deletions(-) delete mode 100644 tests/util/path.c diff --git a/tests/util/path.c b/tests/util/path.c deleted file mode 100644 index 38a59392521..00000000000 --- a/tests/util/path.c +++ /dev/null @@ -1,780 +0,0 @@ -#include "clar_libgit2.h" -#include "futils.h" -#include "fs_path.h" - -#ifndef GIT_WIN32 -# include -#endif - -static char *path_save; - -void test_path__initialize(void) -{ - path_save = cl_getenv("PATH"); -} - -void test_path__cleanup(void) -{ - cl_setenv("PATH", path_save); - git__free(path_save); - path_save = NULL; -} - -static void -check_dirname(const char *A, const char *B) -{ - git_str dir = GIT_STR_INIT; - char *dir2; - - cl_assert(git_fs_path_dirname_r(&dir, A) >= 0); - cl_assert_equal_s(B, dir.ptr); - git_str_dispose(&dir); - - cl_assert((dir2 = git_fs_path_dirname(A)) != NULL); - cl_assert_equal_s(B, dir2); - git__free(dir2); -} - -static void -check_basename(const char *A, const char *B) -{ - git_str base = GIT_STR_INIT; - char *base2; - - cl_assert(git_fs_path_basename_r(&base, A) >= 0); - cl_assert_equal_s(B, base.ptr); - git_str_dispose(&base); - - cl_assert((base2 = git_fs_path_basename(A)) != NULL); - cl_assert_equal_s(B, base2); - git__free(base2); -} - -static void -check_joinpath(const char *path_a, const char *path_b, const char *expected_path) -{ - git_str joined_path = GIT_STR_INIT; - - cl_git_pass(git_str_joinpath(&joined_path, path_a, path_b)); - cl_assert_equal_s(expected_path, joined_path.ptr); - - git_str_dispose(&joined_path); -} - -static void -check_joinpath_n( - const char *path_a, - const char *path_b, - const char *path_c, - const char *path_d, - const char *expected_path) -{ - git_str joined_path = GIT_STR_INIT; - - cl_git_pass(git_str_join_n(&joined_path, '/', 4, - path_a, path_b, path_c, path_d)); - cl_assert_equal_s(expected_path, joined_path.ptr); - - git_str_dispose(&joined_path); -} - -static void check_setenv(const char* name, const char* value) -{ - char* check; - - cl_git_pass(cl_setenv(name, value)); - check = cl_getenv(name); - - if (value) - cl_assert_equal_s(value, check); - else - cl_assert(check == NULL); - - git__free(check); -} - -/* get the dirname of a path */ -void test_path__00_dirname(void) -{ - check_dirname(NULL, "."); - check_dirname("", "."); - check_dirname("a", "."); - check_dirname("/", "/"); - check_dirname("/usr", "/"); - check_dirname("/usr/", "/"); - check_dirname("/usr/lib", "/usr"); - check_dirname("/usr/lib/", "/usr"); - check_dirname("/usr/lib//", "/usr"); - check_dirname("usr/lib", "usr"); - check_dirname("usr/lib/", "usr"); - check_dirname("usr/lib//", "usr"); - check_dirname(".git/", "."); - - check_dirname(REP16("/abc"), REP15("/abc")); - -#ifdef GIT_WIN32 - check_dirname("C:/", "C:/"); - check_dirname("C:", "C:/"); - check_dirname("C:/path/", "C:/"); - check_dirname("C:/path", "C:/"); - check_dirname("//computername/", "//computername/"); - check_dirname("//computername", "//computername/"); - check_dirname("//computername/path/", "//computername/"); - check_dirname("//computername/path", "//computername/"); - check_dirname("//computername/sub/path/", "//computername/sub"); - check_dirname("//computername/sub/path", "//computername/sub"); -#endif -} - -/* get the base name of a path */ -void test_path__01_basename(void) -{ - check_basename(NULL, "."); - check_basename("", "."); - check_basename("a", "a"); - check_basename("/", "/"); - check_basename("/usr", "usr"); - check_basename("/usr/", "usr"); - check_basename("/usr/lib", "lib"); - check_basename("/usr/lib//", "lib"); - check_basename("usr/lib", "lib"); - - check_basename(REP16("/abc"), "abc"); - check_basename(REP1024("/abc"), "abc"); -} - -/* properly join path components */ -void test_path__05_joins(void) -{ - check_joinpath("", "", ""); - check_joinpath("", "a", "a"); - check_joinpath("", "/a", "/a"); - check_joinpath("a", "", "a/"); - check_joinpath("a", "/", "a/"); - check_joinpath("a", "b", "a/b"); - check_joinpath("/", "a", "/a"); - check_joinpath("/", "", "/"); - check_joinpath("/a", "/b", "/a/b"); - check_joinpath("/a", "/b/", "/a/b/"); - check_joinpath("/a/", "b/", "/a/b/"); - check_joinpath("/a/", "/b/", "/a/b/"); - - check_joinpath("/abcd", "/defg", "/abcd/defg"); - check_joinpath("/abcd", "/defg/", "/abcd/defg/"); - check_joinpath("/abcd/", "defg/", "/abcd/defg/"); - check_joinpath("/abcd/", "/defg/", "/abcd/defg/"); - - check_joinpath("/abcdefgh", "/12345678", "/abcdefgh/12345678"); - check_joinpath("/abcdefgh", "/12345678/", "/abcdefgh/12345678/"); - check_joinpath("/abcdefgh/", "12345678/", "/abcdefgh/12345678/"); - - check_joinpath(REP1024("aaaa"), "", REP1024("aaaa") "/"); - check_joinpath(REP1024("aaaa/"), "", REP1024("aaaa/")); - check_joinpath(REP1024("/aaaa"), "", REP1024("/aaaa") "/"); - - check_joinpath(REP1024("aaaa"), REP1024("bbbb"), - REP1024("aaaa") "/" REP1024("bbbb")); - check_joinpath(REP1024("/aaaa"), REP1024("/bbbb"), - REP1024("/aaaa") REP1024("/bbbb")); -} - -/* properly join path components for more than one path */ -void test_path__06_long_joins(void) -{ - check_joinpath_n("", "", "", "", ""); - check_joinpath_n("", "a", "", "", "a/"); - check_joinpath_n("a", "", "", "", "a/"); - check_joinpath_n("", "", "", "a", "a"); - check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/"); - check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"); - check_joinpath_n("abcd", "efgh", "ijkl", "mnop", "abcd/efgh/ijkl/mnop"); - check_joinpath_n("abcd/", "efgh/", "ijkl/", "mnop/", "abcd/efgh/ijkl/mnop/"); - check_joinpath_n("/abcd/", "/efgh/", "/ijkl/", "/mnop/", "/abcd/efgh/ijkl/mnop/"); - - check_joinpath_n(REP1024("a"), REP1024("b"), REP1024("c"), REP1024("d"), - REP1024("a") "/" REP1024("b") "/" - REP1024("c") "/" REP1024("d")); - check_joinpath_n(REP1024("/a"), REP1024("/b"), REP1024("/c"), REP1024("/d"), - REP1024("/a") REP1024("/b") - REP1024("/c") REP1024("/d")); -} - - -static void -check_path_to_dir( - const char* path, - const char* expected) -{ - git_str tgt = GIT_STR_INIT; - - git_str_sets(&tgt, path); - cl_git_pass(git_fs_path_to_dir(&tgt)); - cl_assert_equal_s(expected, tgt.ptr); - - git_str_dispose(&tgt); -} - -static void -check_string_to_dir( - const char* path, - size_t maxlen, - const char* expected) -{ - size_t len = strlen(path); - char *buf = git__malloc(len + 2); - cl_assert(buf); - - strncpy(buf, path, len + 2); - - git_fs_path_string_to_dir(buf, maxlen); - - cl_assert_equal_s(expected, buf); - - git__free(buf); -} - -/* convert paths to dirs */ -void test_path__07_path_to_dir(void) -{ - check_path_to_dir("", ""); - check_path_to_dir(".", "./"); - check_path_to_dir("./", "./"); - check_path_to_dir("a/", "a/"); - check_path_to_dir("ab", "ab/"); - /* make sure we try just under and just over an expansion that will - * require a realloc - */ - check_path_to_dir("abcdef", "abcdef/"); - check_path_to_dir("abcdefg", "abcdefg/"); - check_path_to_dir("abcdefgh", "abcdefgh/"); - check_path_to_dir("abcdefghi", "abcdefghi/"); - check_path_to_dir(REP1024("abcd") "/", REP1024("abcd") "/"); - check_path_to_dir(REP1024("abcd"), REP1024("abcd") "/"); - - check_string_to_dir("", 1, ""); - check_string_to_dir(".", 1, "."); - check_string_to_dir(".", 2, "./"); - check_string_to_dir(".", 3, "./"); - check_string_to_dir("abcd", 3, "abcd"); - check_string_to_dir("abcd", 4, "abcd"); - check_string_to_dir("abcd", 5, "abcd/"); - check_string_to_dir("abcd", 6, "abcd/"); -} - -/* join path to itself */ -void test_path__08_self_join(void) -{ - git_str path = GIT_STR_INIT; - size_t asize = 0; - - asize = path.asize; - cl_git_pass(git_str_sets(&path, "/foo")); - cl_assert_equal_s(path.ptr, "/foo"); - cl_assert(asize < path.asize); - - asize = path.asize; - cl_git_pass(git_str_joinpath(&path, path.ptr, "this is a new string")); - cl_assert_equal_s(path.ptr, "/foo/this is a new string"); - cl_assert(asize < path.asize); - - asize = path.asize; - cl_git_pass(git_str_joinpath(&path, path.ptr, "/grow the buffer, grow the buffer, grow the buffer")); - cl_assert_equal_s(path.ptr, "/foo/this is a new string/grow the buffer, grow the buffer, grow the buffer"); - cl_assert(asize < path.asize); - - git_str_dispose(&path); - cl_git_pass(git_str_sets(&path, "/foo/bar")); - - cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "baz")); - cl_assert_equal_s(path.ptr, "/bar/baz"); - - asize = path.asize; - cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc")); - cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc"); - cl_assert(asize < path.asize); - - git_str_dispose(&path); -} - -static void check_percent_decoding(const char *expected_result, const char *input) -{ - git_str buf = GIT_STR_INIT; - - cl_git_pass(git__percent_decode(&buf, input)); - cl_assert_equal_s(expected_result, git_str_cstr(&buf)); - - git_str_dispose(&buf); -} - -void test_path__09_percent_decode(void) -{ - check_percent_decoding("abcd", "abcd"); - check_percent_decoding("a2%", "a2%"); - check_percent_decoding("a2%3", "a2%3"); - check_percent_decoding("a2%%3", "a2%%3"); - check_percent_decoding("a2%3z", "a2%3z"); - check_percent_decoding("a,", "a%2c"); - check_percent_decoding("a21", "a2%31"); - check_percent_decoding("a2%1", "a2%%31"); - check_percent_decoding("a bc ", "a%20bc%20"); - check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED"); -} - -static void check_fromurl(const char *expected_result, const char *input, int should_fail) -{ - git_str buf = GIT_STR_INIT; - - assert(should_fail || expected_result); - - if (!should_fail) { - cl_git_pass(git_fs_path_fromurl(&buf, input)); - cl_assert_equal_s(expected_result, git_str_cstr(&buf)); - } else - cl_git_fail(git_fs_path_fromurl(&buf, input)); - - git_str_dispose(&buf); -} - -#ifdef GIT_WIN32 -#define ABS_PATH_MARKER "" -#else -#define ABS_PATH_MARKER "/" -#endif - -void test_path__10_fromurl(void) -{ - /* Failing cases */ - check_fromurl(NULL, "a", 1); - check_fromurl(NULL, "http:///c:/Temp%20folder/note.txt", 1); - check_fromurl(NULL, "file://c:/Temp%20folder/note.txt", 1); - check_fromurl(NULL, "file:////c:/Temp%20folder/note.txt", 1); - check_fromurl(NULL, "file:///", 1); - check_fromurl(NULL, "file:////", 1); - check_fromurl(NULL, "file://servername/c:/Temp%20folder/note.txt", 1); - - /* Passing cases */ - check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file:///c:/Temp%20folder/note.txt", 0); - check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file://localhost/c:/Temp%20folder/note.txt", 0); - check_fromurl(ABS_PATH_MARKER "c:/Temp+folder/note.txt", "file:///c:/Temp+folder/note.txt", 0); - check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0); -} - -typedef struct { - int expect_idx; - int cancel_after; - char **expect; -} check_walkup_info; - -#define CANCEL_VALUE 1234 - -static int check_one_walkup_step(void *ref, const char *path) -{ - check_walkup_info *info = (check_walkup_info *)ref; - - if (!info->cancel_after) { - cl_assert_equal_s(info->expect[info->expect_idx], "[CANCEL]"); - return CANCEL_VALUE; - } - info->cancel_after--; - - cl_assert(info->expect[info->expect_idx] != NULL); - cl_assert_equal_s(info->expect[info->expect_idx], path); - info->expect_idx++; - - return 0; -} - -void test_path__11_walkup(void) -{ - git_str p = GIT_STR_INIT; - - char *expect[] = { - /* 1 */ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - /* 2 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - /* 3 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - /* 4 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - /* 5 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, - /* 6 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, - /* 7 */ "this_is_a_path", "", NULL, - /* 8 */ "this_is_a_path/", "", NULL, - /* 9 */ "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL, - /* 10 */ "a/b/c/", "a/b/", "a/", "", NULL, - /* 11 */ "a/b/c", "a/b/", "a/", "", NULL, - /* 12 */ "a/b/c/", "a/b/", "a/", NULL, - /* 13 */ "", NULL, - /* 14 */ "/", NULL, - /* 15 */ NULL - }; - - char *root[] = { - /* 1 */ NULL, - /* 2 */ NULL, - /* 3 */ "/", - /* 4 */ "", - /* 5 */ "/a/b", - /* 6 */ "/a/b/", - /* 7 */ NULL, - /* 8 */ NULL, - /* 9 */ NULL, - /* 10 */ NULL, - /* 11 */ NULL, - /* 12 */ "a/", - /* 13 */ NULL, - /* 14 */ NULL, - }; - - int i, j; - check_walkup_info info; - - info.expect = expect; - info.cancel_after = -1; - - for (i = 0, j = 0; expect[i] != NULL; i++, j++) { - - git_str_sets(&p, expect[i]); - - info.expect_idx = i; - cl_git_pass( - git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info) - ); - - cl_assert_equal_s(p.ptr, expect[i]); - cl_assert(expect[info.expect_idx] == NULL); - i = info.expect_idx; - } - - git_str_dispose(&p); -} - -void test_path__11a_walkup_cancel(void) -{ - git_str p = GIT_STR_INIT; - int cancel[] = { 3, 2, 1, 0 }; - char *expect[] = { - "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "[CANCEL]", NULL, - "/a/b/c/d/e", "/a/b/c/d/", "[CANCEL]", NULL, - "/a/b/c/d/e", "[CANCEL]", NULL, - "[CANCEL]", NULL, - NULL - }; - char *root[] = { NULL, NULL, "/", "", NULL }; - int i, j; - check_walkup_info info; - - info.expect = expect; - - for (i = 0, j = 0; expect[i] != NULL; i++, j++) { - - git_str_sets(&p, expect[i]); - - info.cancel_after = cancel[j]; - info.expect_idx = i; - - cl_assert_equal_i( - CANCEL_VALUE, - git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info) - ); - - /* skip to next run of expectations */ - while (expect[i] != NULL) i++; - } - - git_str_dispose(&p); -} - -void test_path__12_offset_to_path_root(void) -{ - cl_assert(git_fs_path_root("non/rooted/path") == -1); - cl_assert(git_fs_path_root("/rooted/path") == 0); - -#ifdef GIT_WIN32 - /* Windows specific tests */ - cl_assert(git_fs_path_root("C:non/rooted/path") == -1); - cl_assert(git_fs_path_root("C:/rooted/path") == 2); - cl_assert(git_fs_path_root("//computername/sharefolder/resource") == 14); - cl_assert(git_fs_path_root("//computername/sharefolder") == 14); - cl_assert(git_fs_path_root("//computername") == -1); -#endif -} - -#define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist" - -void test_path__13_cannot_prettify_a_non_existing_file(void) -{ - git_str p = GIT_STR_INIT; - - cl_assert_equal_b(git_fs_path_exists(NON_EXISTING_FILEPATH), false); - cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH, NULL)); - cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL)); - - git_str_dispose(&p); -} - -void test_path__14_apply_relative(void) -{ - git_str p = GIT_STR_INIT; - - cl_git_pass(git_str_sets(&p, "/this/is/a/base")); - - cl_git_pass(git_fs_path_apply_relative(&p, "../test")); - cl_assert_equal_s("/this/is/a/test", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "../../the/./end")); - cl_assert_equal_s("/this/is/the/end", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "./of/this/../the/string")); - cl_assert_equal_s("/this/is/the/end/of/the/string", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "../../../../../..")); - cl_assert_equal_s("/this/", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "../")); - cl_assert_equal_s("/", p.ptr); - - cl_git_fail(git_fs_path_apply_relative(&p, "../../..")); - - - cl_git_pass(git_str_sets(&p, "d:/another/test")); - - cl_git_pass(git_fs_path_apply_relative(&p, "../..")); - cl_assert_equal_s("d:/", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "from/here/to/../and/./back/.")); - cl_assert_equal_s("d:/from/here/and/back/", p.ptr); - - - cl_git_pass(git_str_sets(&p, "https://my.url.com/test.git")); - - cl_git_pass(git_fs_path_apply_relative(&p, "../another.git")); - cl_assert_equal_s("https://my.url.com/another.git", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "../full/path/url.patch")); - cl_assert_equal_s("https://my.url.com/full/path/url.patch", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "..")); - cl_assert_equal_s("https://my.url.com/full/path/", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "../../../")); - cl_assert_equal_s("https://", p.ptr); - - - cl_git_pass(git_str_sets(&p, "../../this/is/relative")); - - cl_git_pass(git_fs_path_apply_relative(&p, "../../preserves/the/prefix")); - cl_assert_equal_s("../../this/preserves/the/prefix", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "../../../../that")); - cl_assert_equal_s("../../that", p.ptr); - - cl_git_pass(git_fs_path_apply_relative(&p, "../there")); - cl_assert_equal_s("../../there", p.ptr); - git_str_dispose(&p); -} - -static void assert_resolve_relative( - git_str *buf, const char *expected, const char *path) -{ - cl_git_pass(git_str_sets(buf, path)); - cl_git_pass(git_fs_path_resolve_relative(buf, 0)); - cl_assert_equal_s(expected, buf->ptr); -} - -void test_path__15_resolve_relative(void) -{ - git_str buf = GIT_STR_INIT; - - assert_resolve_relative(&buf, "", ""); - assert_resolve_relative(&buf, "", "."); - assert_resolve_relative(&buf, "", "./"); - assert_resolve_relative(&buf, "..", ".."); - assert_resolve_relative(&buf, "../", "../"); - assert_resolve_relative(&buf, "..", "./.."); - assert_resolve_relative(&buf, "../", "./../"); - assert_resolve_relative(&buf, "../", "../."); - assert_resolve_relative(&buf, "../", ".././"); - assert_resolve_relative(&buf, "../..", "../.."); - assert_resolve_relative(&buf, "../../", "../../"); - - assert_resolve_relative(&buf, "/", "/"); - assert_resolve_relative(&buf, "/", "/."); - - assert_resolve_relative(&buf, "", "a/.."); - assert_resolve_relative(&buf, "", "a/../"); - assert_resolve_relative(&buf, "", "a/../."); - - assert_resolve_relative(&buf, "/a", "/a"); - assert_resolve_relative(&buf, "/a/", "/a/."); - assert_resolve_relative(&buf, "/", "/a/../"); - assert_resolve_relative(&buf, "/", "/a/../."); - assert_resolve_relative(&buf, "/", "/a/.././"); - - assert_resolve_relative(&buf, "a", "a"); - assert_resolve_relative(&buf, "a/", "a/"); - assert_resolve_relative(&buf, "a/", "a/."); - assert_resolve_relative(&buf, "a/", "a/./"); - - assert_resolve_relative(&buf, "a/b", "a//b"); - assert_resolve_relative(&buf, "a/b/c", "a/b/c"); - assert_resolve_relative(&buf, "b/c", "./b/c"); - assert_resolve_relative(&buf, "a/c", "a/./c"); - assert_resolve_relative(&buf, "a/b/", "a/b/."); - - assert_resolve_relative(&buf, "/a/b/c", "///a/b/c"); - assert_resolve_relative(&buf, "/", "////"); - assert_resolve_relative(&buf, "/a", "///a"); - assert_resolve_relative(&buf, "/", "///."); - assert_resolve_relative(&buf, "/", "///a/.."); - - assert_resolve_relative(&buf, "../../path", "../../test//../././path"); - assert_resolve_relative(&buf, "../d", "a/b/../../../c/../d"); - - cl_git_pass(git_str_sets(&buf, "/..")); - cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); - - cl_git_pass(git_str_sets(&buf, "/./..")); - cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); - - cl_git_pass(git_str_sets(&buf, "/.//..")); - cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); - - cl_git_pass(git_str_sets(&buf, "/../.")); - cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); - - cl_git_pass(git_str_sets(&buf, "/../.././../a")); - cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); - - cl_git_pass(git_str_sets(&buf, "////..")); - cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); - - /* things that start with Windows network paths */ -#ifdef GIT_WIN32 - assert_resolve_relative(&buf, "//a/b/c", "//a/b/c"); - assert_resolve_relative(&buf, "//a/", "//a/b/.."); - assert_resolve_relative(&buf, "//a/b/c", "//a/Q/../b/x/y/../../c"); - - cl_git_pass(git_str_sets(&buf, "//a/b/../..")); - cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); -#else - assert_resolve_relative(&buf, "/a/b/c", "//a/b/c"); - assert_resolve_relative(&buf, "/a/", "//a/b/.."); - assert_resolve_relative(&buf, "/a/b/c", "//a/Q/../b/x/y/../../c"); - assert_resolve_relative(&buf, "/", "//a/b/../.."); -#endif - - git_str_dispose(&buf); -} - -#define assert_common_dirlen(i, p, q) \ - cl_assert_equal_i((i), git_fs_path_common_dirlen((p), (q))); - -void test_path__16_resolve_relative(void) -{ - assert_common_dirlen(0, "", ""); - assert_common_dirlen(0, "", "bar.txt"); - assert_common_dirlen(0, "foo.txt", "bar.txt"); - assert_common_dirlen(0, "foo.txt", ""); - assert_common_dirlen(0, "foo/bar.txt", "bar/foo.txt"); - assert_common_dirlen(0, "foo/bar.txt", "../foo.txt"); - - assert_common_dirlen(1, "/one.txt", "/two.txt"); - assert_common_dirlen(4, "foo/one.txt", "foo/two.txt"); - assert_common_dirlen(5, "/foo/one.txt", "/foo/two.txt"); - - assert_common_dirlen(6, "a/b/c/foo.txt", "a/b/c/d/e/bar.txt"); - assert_common_dirlen(7, "/a/b/c/foo.txt", "/a/b/c/d/e/bar.txt"); -} - -static void fix_path(git_str *s) -{ -#ifndef GIT_WIN32 - GIT_UNUSED(s); -#else - char* c; - - for (c = s->ptr; *c; c++) { - if (*c == '/') - *c = '\\'; - } -#endif -} - -void test_path__find_exe_in_path(void) -{ - char *orig_path; - git_str sandbox_path = GIT_STR_INIT; - git_str new_path = GIT_STR_INIT, full_path = GIT_STR_INIT, - dummy_path = GIT_STR_INIT; - -#ifdef GIT_WIN32 - static const char *bogus_path_1 = "c:\\does\\not\\exist\\"; - static const char *bogus_path_2 = "e:\\non\\existent"; -#else - static const char *bogus_path_1 = "/this/path/does/not/exist/"; - static const char *bogus_path_2 = "/non/existent"; -#endif - - orig_path = cl_getenv("PATH"); - - git_str_puts(&sandbox_path, clar_sandbox_path()); - git_str_joinpath(&dummy_path, sandbox_path.ptr, "dummmmmmmy_libgit2_file"); - cl_git_rewritefile(dummy_path.ptr, "this is a dummy file"); - - fix_path(&sandbox_path); - fix_path(&dummy_path); - - cl_git_pass(git_str_printf(&new_path, "%s%c%s%c%s%c%s", - bogus_path_1, GIT_PATH_LIST_SEPARATOR, - orig_path, GIT_PATH_LIST_SEPARATOR, - sandbox_path.ptr, GIT_PATH_LIST_SEPARATOR, - bogus_path_2)); - - check_setenv("PATH", new_path.ptr); - - cl_git_fail_with(GIT_ENOTFOUND, git_fs_path_find_executable(&full_path, "this_file_does_not_exist")); - cl_git_pass(git_fs_path_find_executable(&full_path, "dummmmmmmy_libgit2_file")); - - cl_assert_equal_s(full_path.ptr, dummy_path.ptr); - - git_str_dispose(&full_path); - git_str_dispose(&new_path); - git_str_dispose(&dummy_path); - git_str_dispose(&sandbox_path); - git__free(orig_path); -} - -void test_path__validate_current_user_ownership(void) -{ - bool is_cur; - - cl_must_pass(p_mkdir("testdir", 0777)); - cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testdir")); - cl_assert_equal_i(is_cur, 1); - - cl_git_rewritefile("testfile", "This is a test file."); - cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testfile")); - cl_assert_equal_i(is_cur, 1); - -#ifdef GIT_WIN32 - cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "C:\\")); - cl_assert_equal_i(is_cur, 0); - - cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "c:\\path\\does\\not\\exist")); -#else - cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "/")); - cl_assert_equal_i(is_cur, (geteuid() == 0)); - - cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "/path/does/not/exist")); -#endif -} - -void test_path__dirlen(void) -{ - cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf")); - cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf/")); - cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf//")); - cl_assert_equal_sz(3, git_fs_path_dirlen("foo////")); - cl_assert_equal_sz(3, git_fs_path_dirlen("foo")); - cl_assert_equal_sz(1, git_fs_path_dirlen("/")); - cl_assert_equal_sz(1, git_fs_path_dirlen("////")); - cl_assert_equal_sz(0, git_fs_path_dirlen("")); -} diff --git a/tests/util/path/core.c b/tests/util/path/core.c index 41d9b02040f..d1935a816a9 100644 --- a/tests/util/path/core.c +++ b/tests/util/path/core.c @@ -1,6 +1,784 @@ #include "clar_libgit2.h" +#include "futils.h" #include "fs_path.h" +#ifndef GIT_WIN32 +# include +#endif + +static char *path_save; + +void test_path_core__initialize(void) +{ + path_save = cl_getenv("PATH"); +} + +void test_path_core__cleanup(void) +{ + cl_setenv("PATH", path_save); + git__free(path_save); + path_save = NULL; +} + +static void +check_dirname(const char *A, const char *B) +{ + git_str dir = GIT_STR_INIT; + char *dir2; + + cl_assert(git_fs_path_dirname_r(&dir, A) >= 0); + cl_assert_equal_s(B, dir.ptr); + git_str_dispose(&dir); + + cl_assert((dir2 = git_fs_path_dirname(A)) != NULL); + cl_assert_equal_s(B, dir2); + git__free(dir2); +} + +static void +check_basename(const char *A, const char *B) +{ + git_str base = GIT_STR_INIT; + char *base2; + + cl_assert(git_fs_path_basename_r(&base, A) >= 0); + cl_assert_equal_s(B, base.ptr); + git_str_dispose(&base); + + cl_assert((base2 = git_fs_path_basename(A)) != NULL); + cl_assert_equal_s(B, base2); + git__free(base2); +} + +static void +check_joinpath(const char *path_a, const char *path_b, const char *expected_path) +{ + git_str joined_path = GIT_STR_INIT; + + cl_git_pass(git_str_joinpath(&joined_path, path_a, path_b)); + cl_assert_equal_s(expected_path, joined_path.ptr); + + git_str_dispose(&joined_path); +} + +static void +check_joinpath_n( + const char *path_a, + const char *path_b, + const char *path_c, + const char *path_d, + const char *expected_path) +{ + git_str joined_path = GIT_STR_INIT; + + cl_git_pass(git_str_join_n(&joined_path, '/', 4, + path_a, path_b, path_c, path_d)); + cl_assert_equal_s(expected_path, joined_path.ptr); + + git_str_dispose(&joined_path); +} + +static void check_setenv(const char* name, const char* value) +{ + char* check; + + cl_git_pass(cl_setenv(name, value)); + check = cl_getenv(name); + + if (value) + cl_assert_equal_s(value, check); + else + cl_assert(check == NULL); + + git__free(check); +} + +/* get the dirname of a path */ +void test_path_core__00_dirname(void) +{ + check_dirname(NULL, "."); + check_dirname("", "."); + check_dirname("a", "."); + check_dirname("/", "/"); + check_dirname("/usr", "/"); + check_dirname("/usr/", "/"); + check_dirname("/usr/lib", "/usr"); + check_dirname("/usr/lib/", "/usr"); + check_dirname("/usr/lib//", "/usr"); + check_dirname("usr/lib", "usr"); + check_dirname("usr/lib/", "usr"); + check_dirname("usr/lib//", "usr"); + check_dirname(".git/", "."); + + check_dirname(REP16("/abc"), REP15("/abc")); + +#ifdef GIT_WIN32 + check_dirname("C:/", "C:/"); + check_dirname("C:", "C:/"); + check_dirname("C:/path/", "C:/"); + check_dirname("C:/path", "C:/"); + check_dirname("//computername/", "//computername/"); + check_dirname("//computername", "//computername/"); + check_dirname("//computername/path/", "//computername/"); + check_dirname("//computername/path", "//computername/"); + check_dirname("//computername/sub/path/", "//computername/sub"); + check_dirname("//computername/sub/path", "//computername/sub"); +#endif +} + +/* get the base name of a path */ +void test_path_core__01_basename(void) +{ + check_basename(NULL, "."); + check_basename("", "."); + check_basename("a", "a"); + check_basename("/", "/"); + check_basename("/usr", "usr"); + check_basename("/usr/", "usr"); + check_basename("/usr/lib", "lib"); + check_basename("/usr/lib//", "lib"); + check_basename("usr/lib", "lib"); + + check_basename(REP16("/abc"), "abc"); + check_basename(REP1024("/abc"), "abc"); +} + +/* properly join path components */ +void test_path_core__05_joins(void) +{ + check_joinpath("", "", ""); + check_joinpath("", "a", "a"); + check_joinpath("", "/a", "/a"); + check_joinpath("a", "", "a/"); + check_joinpath("a", "/", "a/"); + check_joinpath("a", "b", "a/b"); + check_joinpath("/", "a", "/a"); + check_joinpath("/", "", "/"); + check_joinpath("/a", "/b", "/a/b"); + check_joinpath("/a", "/b/", "/a/b/"); + check_joinpath("/a/", "b/", "/a/b/"); + check_joinpath("/a/", "/b/", "/a/b/"); + + check_joinpath("/abcd", "/defg", "/abcd/defg"); + check_joinpath("/abcd", "/defg/", "/abcd/defg/"); + check_joinpath("/abcd/", "defg/", "/abcd/defg/"); + check_joinpath("/abcd/", "/defg/", "/abcd/defg/"); + + check_joinpath("/abcdefgh", "/12345678", "/abcdefgh/12345678"); + check_joinpath("/abcdefgh", "/12345678/", "/abcdefgh/12345678/"); + check_joinpath("/abcdefgh/", "12345678/", "/abcdefgh/12345678/"); + + check_joinpath(REP1024("aaaa"), "", REP1024("aaaa") "/"); + check_joinpath(REP1024("aaaa/"), "", REP1024("aaaa/")); + check_joinpath(REP1024("/aaaa"), "", REP1024("/aaaa") "/"); + + check_joinpath(REP1024("aaaa"), REP1024("bbbb"), + REP1024("aaaa") "/" REP1024("bbbb")); + check_joinpath(REP1024("/aaaa"), REP1024("/bbbb"), + REP1024("/aaaa") REP1024("/bbbb")); +} + +/* properly join path components for more than one path */ +void test_path_core__06_long_joins(void) +{ + check_joinpath_n("", "", "", "", ""); + check_joinpath_n("", "a", "", "", "a/"); + check_joinpath_n("a", "", "", "", "a/"); + check_joinpath_n("", "", "", "a", "a"); + check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/"); + check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"); + check_joinpath_n("abcd", "efgh", "ijkl", "mnop", "abcd/efgh/ijkl/mnop"); + check_joinpath_n("abcd/", "efgh/", "ijkl/", "mnop/", "abcd/efgh/ijkl/mnop/"); + check_joinpath_n("/abcd/", "/efgh/", "/ijkl/", "/mnop/", "/abcd/efgh/ijkl/mnop/"); + + check_joinpath_n(REP1024("a"), REP1024("b"), REP1024("c"), REP1024("d"), + REP1024("a") "/" REP1024("b") "/" + REP1024("c") "/" REP1024("d")); + check_joinpath_n(REP1024("/a"), REP1024("/b"), REP1024("/c"), REP1024("/d"), + REP1024("/a") REP1024("/b") + REP1024("/c") REP1024("/d")); +} + + +static void +check_path_to_dir( + const char* path, + const char* expected) +{ + git_str tgt = GIT_STR_INIT; + + git_str_sets(&tgt, path); + cl_git_pass(git_fs_path_to_dir(&tgt)); + cl_assert_equal_s(expected, tgt.ptr); + + git_str_dispose(&tgt); +} + +static void +check_string_to_dir( + const char* path, + size_t maxlen, + const char* expected) +{ + size_t len = strlen(path); + char *buf = git__malloc(len + 2); + cl_assert(buf); + + strncpy(buf, path, len + 2); + + git_fs_path_string_to_dir(buf, maxlen); + + cl_assert_equal_s(expected, buf); + + git__free(buf); +} + +/* convert paths to dirs */ +void test_path_core__07_path_to_dir(void) +{ + check_path_to_dir("", ""); + check_path_to_dir(".", "./"); + check_path_to_dir("./", "./"); + check_path_to_dir("a/", "a/"); + check_path_to_dir("ab", "ab/"); + /* make sure we try just under and just over an expansion that will + * require a realloc + */ + check_path_to_dir("abcdef", "abcdef/"); + check_path_to_dir("abcdefg", "abcdefg/"); + check_path_to_dir("abcdefgh", "abcdefgh/"); + check_path_to_dir("abcdefghi", "abcdefghi/"); + check_path_to_dir(REP1024("abcd") "/", REP1024("abcd") "/"); + check_path_to_dir(REP1024("abcd"), REP1024("abcd") "/"); + + check_string_to_dir("", 1, ""); + check_string_to_dir(".", 1, "."); + check_string_to_dir(".", 2, "./"); + check_string_to_dir(".", 3, "./"); + check_string_to_dir("abcd", 3, "abcd"); + check_string_to_dir("abcd", 4, "abcd"); + check_string_to_dir("abcd", 5, "abcd/"); + check_string_to_dir("abcd", 6, "abcd/"); +} + +/* join path to itself */ +void test_path_core__08_self_join(void) +{ + git_str path = GIT_STR_INIT; + size_t asize = 0; + + asize = path.asize; + cl_git_pass(git_str_sets(&path, "/foo")); + cl_assert_equal_s(path.ptr, "/foo"); + cl_assert(asize < path.asize); + + asize = path.asize; + cl_git_pass(git_str_joinpath(&path, path.ptr, "this is a new string")); + cl_assert_equal_s(path.ptr, "/foo/this is a new string"); + cl_assert(asize < path.asize); + + asize = path.asize; + cl_git_pass(git_str_joinpath(&path, path.ptr, "/grow the buffer, grow the buffer, grow the buffer")); + cl_assert_equal_s(path.ptr, "/foo/this is a new string/grow the buffer, grow the buffer, grow the buffer"); + cl_assert(asize < path.asize); + + git_str_dispose(&path); + cl_git_pass(git_str_sets(&path, "/foo/bar")); + + cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "baz")); + cl_assert_equal_s(path.ptr, "/bar/baz"); + + asize = path.asize; + cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc")); + cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc"); + cl_assert(asize < path.asize); + + git_str_dispose(&path); +} + +static void check_percent_decoding(const char *expected_result, const char *input) +{ + git_str buf = GIT_STR_INIT; + + cl_git_pass(git__percent_decode(&buf, input)); + cl_assert_equal_s(expected_result, git_str_cstr(&buf)); + + git_str_dispose(&buf); +} + +void test_path_core__09_percent_decode(void) +{ + check_percent_decoding("abcd", "abcd"); + check_percent_decoding("a2%", "a2%"); + check_percent_decoding("a2%3", "a2%3"); + check_percent_decoding("a2%%3", "a2%%3"); + check_percent_decoding("a2%3z", "a2%3z"); + check_percent_decoding("a,", "a%2c"); + check_percent_decoding("a21", "a2%31"); + check_percent_decoding("a2%1", "a2%%31"); + check_percent_decoding("a bc ", "a%20bc%20"); + check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED"); +} + +static void check_fromurl(const char *expected_result, const char *input, int should_fail) +{ + git_str buf = GIT_STR_INIT; + + assert(should_fail || expected_result); + + if (!should_fail) { + cl_git_pass(git_fs_path_fromurl(&buf, input)); + cl_assert_equal_s(expected_result, git_str_cstr(&buf)); + } else + cl_git_fail(git_fs_path_fromurl(&buf, input)); + + git_str_dispose(&buf); +} + +#ifdef GIT_WIN32 +#define ABS_PATH_MARKER "" +#else +#define ABS_PATH_MARKER "/" +#endif + +void test_path_core__10_fromurl(void) +{ + /* Failing cases */ + check_fromurl(NULL, "a", 1); + check_fromurl(NULL, "http:///c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file://c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file:////c:/Temp%20folder/note.txt", 1); + check_fromurl(NULL, "file:///", 1); + check_fromurl(NULL, "file:////", 1); + check_fromurl(NULL, "file://servername/c:/Temp%20folder/note.txt", 1); + + /* Passing cases */ + check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file:///c:/Temp%20folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file://localhost/c:/Temp%20folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "c:/Temp+folder/note.txt", "file:///c:/Temp+folder/note.txt", 0); + check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0); +} + +typedef struct { + int expect_idx; + int cancel_after; + char **expect; +} check_walkup_info; + +#define CANCEL_VALUE 1234 + +static int check_one_walkup_step(void *ref, const char *path) +{ + check_walkup_info *info = (check_walkup_info *)ref; + + if (!info->cancel_after) { + cl_assert_equal_s(info->expect[info->expect_idx], "[CANCEL]"); + return CANCEL_VALUE; + } + info->cancel_after--; + + cl_assert(info->expect[info->expect_idx] != NULL); + cl_assert_equal_s(info->expect[info->expect_idx], path); + info->expect_idx++; + + return 0; +} + +void test_path_core__11_walkup(void) +{ + git_str p = GIT_STR_INIT; + + char *expect[] = { + /* 1 */ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 2 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 3 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 4 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 5 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, + /* 6 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, + /* 7 */ "this_is_a_path", "", NULL, + /* 8 */ "this_is_a_path/", "", NULL, + /* 9 */ "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL, + /* 10 */ "a/b/c/", "a/b/", "a/", "", NULL, + /* 11 */ "a/b/c", "a/b/", "a/", "", NULL, + /* 12 */ "a/b/c/", "a/b/", "a/", NULL, + /* 13 */ "", NULL, + /* 14 */ "/", NULL, + /* 15 */ NULL + }; + + char *root[] = { + /* 1 */ NULL, + /* 2 */ NULL, + /* 3 */ "/", + /* 4 */ "", + /* 5 */ "/a/b", + /* 6 */ "/a/b/", + /* 7 */ NULL, + /* 8 */ NULL, + /* 9 */ NULL, + /* 10 */ NULL, + /* 11 */ NULL, + /* 12 */ "a/", + /* 13 */ NULL, + /* 14 */ NULL, + }; + + int i, j; + check_walkup_info info; + + info.expect = expect; + info.cancel_after = -1; + + for (i = 0, j = 0; expect[i] != NULL; i++, j++) { + + git_str_sets(&p, expect[i]); + + info.expect_idx = i; + cl_git_pass( + git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info) + ); + + cl_assert_equal_s(p.ptr, expect[i]); + cl_assert(expect[info.expect_idx] == NULL); + i = info.expect_idx; + } + + git_str_dispose(&p); +} + +void test_path_core__11a_walkup_cancel(void) +{ + git_str p = GIT_STR_INIT; + int cancel[] = { 3, 2, 1, 0 }; + char *expect[] = { + "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "[CANCEL]", NULL, + "/a/b/c/d/e", "/a/b/c/d/", "[CANCEL]", NULL, + "/a/b/c/d/e", "[CANCEL]", NULL, + "[CANCEL]", NULL, + NULL + }; + char *root[] = { NULL, NULL, "/", "", NULL }; + int i, j; + check_walkup_info info; + + info.expect = expect; + + for (i = 0, j = 0; expect[i] != NULL; i++, j++) { + + git_str_sets(&p, expect[i]); + + info.cancel_after = cancel[j]; + info.expect_idx = i; + + cl_assert_equal_i( + CANCEL_VALUE, + git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info) + ); + + /* skip to next run of expectations */ + while (expect[i] != NULL) i++; + } + + git_str_dispose(&p); +} + +void test_path_core__12_offset_to_path_root(void) +{ + cl_assert(git_fs_path_root("non/rooted/path") == -1); + cl_assert(git_fs_path_root("/rooted/path") == 0); + +#ifdef GIT_WIN32 + /* Windows specific tests */ + cl_assert(git_fs_path_root("C:non/rooted/path") == -1); + cl_assert(git_fs_path_root("C:/rooted/path") == 2); + cl_assert(git_fs_path_root("//computername/sharefolder/resource") == 14); + cl_assert(git_fs_path_root("//computername/sharefolder") == 14); + cl_assert(git_fs_path_root("//computername") == -1); +#endif +} + +#define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist" + +void test_path_core__13_cannot_prettify_a_non_existing_file(void) +{ + git_str p = GIT_STR_INIT; + + cl_assert_equal_b(git_fs_path_exists(NON_EXISTING_FILEPATH), false); + cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH, NULL)); + cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL)); + + git_str_dispose(&p); +} + +void test_path_core__14_apply_relative(void) +{ + git_str p = GIT_STR_INIT; + + cl_git_pass(git_str_sets(&p, "/this/is/a/base")); + + cl_git_pass(git_fs_path_apply_relative(&p, "../test")); + cl_assert_equal_s("/this/is/a/test", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "../../the/./end")); + cl_assert_equal_s("/this/is/the/end", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "./of/this/../the/string")); + cl_assert_equal_s("/this/is/the/end/of/the/string", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "../../../../../..")); + cl_assert_equal_s("/this/", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "../")); + cl_assert_equal_s("/", p.ptr); + + cl_git_fail(git_fs_path_apply_relative(&p, "../../..")); + + + cl_git_pass(git_str_sets(&p, "d:/another/test")); + + cl_git_pass(git_fs_path_apply_relative(&p, "../..")); + cl_assert_equal_s("d:/", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "from/here/to/../and/./back/.")); + cl_assert_equal_s("d:/from/here/and/back/", p.ptr); + + + cl_git_pass(git_str_sets(&p, "https://my.url.com/test.git")); + + cl_git_pass(git_fs_path_apply_relative(&p, "../another.git")); + cl_assert_equal_s("https://my.url.com/another.git", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "../full/path/url.patch")); + cl_assert_equal_s("https://my.url.com/full/path/url.patch", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "..")); + cl_assert_equal_s("https://my.url.com/full/path/", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "../../../")); + cl_assert_equal_s("https://", p.ptr); + + + cl_git_pass(git_str_sets(&p, "../../this/is/relative")); + + cl_git_pass(git_fs_path_apply_relative(&p, "../../preserves/the/prefix")); + cl_assert_equal_s("../../this/preserves/the/prefix", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "../../../../that")); + cl_assert_equal_s("../../that", p.ptr); + + cl_git_pass(git_fs_path_apply_relative(&p, "../there")); + cl_assert_equal_s("../../there", p.ptr); + git_str_dispose(&p); +} + +static void assert_resolve_relative( + git_str *buf, const char *expected, const char *path) +{ + cl_git_pass(git_str_sets(buf, path)); + cl_git_pass(git_fs_path_resolve_relative(buf, 0)); + cl_assert_equal_s(expected, buf->ptr); +} + +void test_path_core__15_resolve_relative(void) +{ + git_str buf = GIT_STR_INIT; + + assert_resolve_relative(&buf, "", ""); + assert_resolve_relative(&buf, "", "."); + assert_resolve_relative(&buf, "", "./"); + assert_resolve_relative(&buf, "..", ".."); + assert_resolve_relative(&buf, "../", "../"); + assert_resolve_relative(&buf, "..", "./.."); + assert_resolve_relative(&buf, "../", "./../"); + assert_resolve_relative(&buf, "../", "../."); + assert_resolve_relative(&buf, "../", ".././"); + assert_resolve_relative(&buf, "../..", "../.."); + assert_resolve_relative(&buf, "../../", "../../"); + + assert_resolve_relative(&buf, "/", "/"); + assert_resolve_relative(&buf, "/", "/."); + + assert_resolve_relative(&buf, "", "a/.."); + assert_resolve_relative(&buf, "", "a/../"); + assert_resolve_relative(&buf, "", "a/../."); + + assert_resolve_relative(&buf, "/a", "/a"); + assert_resolve_relative(&buf, "/a/", "/a/."); + assert_resolve_relative(&buf, "/", "/a/../"); + assert_resolve_relative(&buf, "/", "/a/../."); + assert_resolve_relative(&buf, "/", "/a/.././"); + + assert_resolve_relative(&buf, "a", "a"); + assert_resolve_relative(&buf, "a/", "a/"); + assert_resolve_relative(&buf, "a/", "a/."); + assert_resolve_relative(&buf, "a/", "a/./"); + + assert_resolve_relative(&buf, "a/b", "a//b"); + assert_resolve_relative(&buf, "a/b/c", "a/b/c"); + assert_resolve_relative(&buf, "b/c", "./b/c"); + assert_resolve_relative(&buf, "a/c", "a/./c"); + assert_resolve_relative(&buf, "a/b/", "a/b/."); + + assert_resolve_relative(&buf, "/a/b/c", "///a/b/c"); + assert_resolve_relative(&buf, "/", "////"); + assert_resolve_relative(&buf, "/a", "///a"); + assert_resolve_relative(&buf, "/", "///."); + assert_resolve_relative(&buf, "/", "///a/.."); + + assert_resolve_relative(&buf, "../../path", "../../test//../././path"); + assert_resolve_relative(&buf, "../d", "a/b/../../../c/../d"); + + cl_git_pass(git_str_sets(&buf, "/..")); + cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_str_sets(&buf, "/./..")); + cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_str_sets(&buf, "/.//..")); + cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_str_sets(&buf, "/../.")); + cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_str_sets(&buf, "/../.././../a")); + cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); + + cl_git_pass(git_str_sets(&buf, "////..")); + cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); + + /* things that start with Windows network paths */ +#ifdef GIT_WIN32 + assert_resolve_relative(&buf, "//a/b/c", "//a/b/c"); + assert_resolve_relative(&buf, "//a/", "//a/b/.."); + assert_resolve_relative(&buf, "//a/b/c", "//a/Q/../b/x/y/../../c"); + + cl_git_pass(git_str_sets(&buf, "//a/b/../..")); + cl_git_fail(git_fs_path_resolve_relative(&buf, 0)); +#else + assert_resolve_relative(&buf, "/a/b/c", "//a/b/c"); + assert_resolve_relative(&buf, "/a/", "//a/b/.."); + assert_resolve_relative(&buf, "/a/b/c", "//a/Q/../b/x/y/../../c"); + assert_resolve_relative(&buf, "/", "//a/b/../.."); +#endif + + git_str_dispose(&buf); +} + +#define assert_common_dirlen(i, p, q) \ + cl_assert_equal_i((i), git_fs_path_common_dirlen((p), (q))); + +void test_path_core__16_resolve_relative(void) +{ + assert_common_dirlen(0, "", ""); + assert_common_dirlen(0, "", "bar.txt"); + assert_common_dirlen(0, "foo.txt", "bar.txt"); + assert_common_dirlen(0, "foo.txt", ""); + assert_common_dirlen(0, "foo/bar.txt", "bar/foo.txt"); + assert_common_dirlen(0, "foo/bar.txt", "../foo.txt"); + + assert_common_dirlen(1, "/one.txt", "/two.txt"); + assert_common_dirlen(4, "foo/one.txt", "foo/two.txt"); + assert_common_dirlen(5, "/foo/one.txt", "/foo/two.txt"); + + assert_common_dirlen(6, "a/b/c/foo.txt", "a/b/c/d/e/bar.txt"); + assert_common_dirlen(7, "/a/b/c/foo.txt", "/a/b/c/d/e/bar.txt"); +} + +static void fix_path(git_str *s) +{ +#ifndef GIT_WIN32 + GIT_UNUSED(s); +#else + char* c; + + for (c = s->ptr; *c; c++) { + if (*c == '/') + *c = '\\'; + } +#endif +} + +void test_path_core__find_exe_in_path(void) +{ + char *orig_path; + git_str sandbox_path = GIT_STR_INIT; + git_str new_path = GIT_STR_INIT, full_path = GIT_STR_INIT, + dummy_path = GIT_STR_INIT; + +#ifdef GIT_WIN32 + static const char *bogus_path_1 = "c:\\does\\not\\exist\\"; + static const char *bogus_path_2 = "e:\\non\\existent"; +#else + static const char *bogus_path_1 = "/this/path/does/not/exist/"; + static const char *bogus_path_2 = "/non/existent"; +#endif + + orig_path = cl_getenv("PATH"); + + git_str_puts(&sandbox_path, clar_sandbox_path()); + git_str_joinpath(&dummy_path, sandbox_path.ptr, "dummmmmmmy_libgit2_file"); + cl_git_rewritefile(dummy_path.ptr, "this is a dummy file"); + + fix_path(&sandbox_path); + fix_path(&dummy_path); + + cl_git_pass(git_str_printf(&new_path, "%s%c%s%c%s%c%s", + bogus_path_1, GIT_PATH_LIST_SEPARATOR, + orig_path, GIT_PATH_LIST_SEPARATOR, + sandbox_path.ptr, GIT_PATH_LIST_SEPARATOR, + bogus_path_2)); + + check_setenv("PATH", new_path.ptr); + + cl_git_fail_with(GIT_ENOTFOUND, git_fs_path_find_executable(&full_path, "this_file_does_not_exist")); + cl_git_pass(git_fs_path_find_executable(&full_path, "dummmmmmmy_libgit2_file")); + + cl_assert_equal_s(full_path.ptr, dummy_path.ptr); + + git_str_dispose(&full_path); + git_str_dispose(&new_path); + git_str_dispose(&dummy_path); + git_str_dispose(&sandbox_path); + git__free(orig_path); +} + +void test_path_core__validate_current_user_ownership(void) +{ + bool is_cur; + + cl_must_pass(p_mkdir("testdir", 0777)); + cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testdir")); + cl_assert_equal_i(is_cur, 1); + + cl_git_rewritefile("testfile", "This is a test file."); + cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "testfile")); + cl_assert_equal_i(is_cur, 1); + +#ifdef GIT_WIN32 + cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "C:\\")); + cl_assert_equal_i(is_cur, 0); + + cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "c:\\path\\does\\not\\exist")); +#else + cl_git_pass(git_fs_path_owner_is_current_user(&is_cur, "/")); + cl_assert_equal_i(is_cur, (geteuid() == 0)); + + cl_git_fail(git_fs_path_owner_is_current_user(&is_cur, "/path/does/not/exist")); +#endif +} + +void test_path_core__dirlen(void) +{ + cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf")); + cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf/")); + cl_assert_equal_sz(13, git_fs_path_dirlen("/foo/bar/asdf//")); + cl_assert_equal_sz(3, git_fs_path_dirlen("foo////")); + cl_assert_equal_sz(3, git_fs_path_dirlen("foo")); + cl_assert_equal_sz(1, git_fs_path_dirlen("/")); + cl_assert_equal_sz(1, git_fs_path_dirlen("////")); + cl_assert_equal_sz(0, git_fs_path_dirlen("")); +} + static void test_make_relative( const char *expected_path, const char *path, From bdf4d70a1333bed0de1728e4725b7620f8bf74f8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 19 Feb 2024 07:08:39 -0800 Subject: [PATCH 418/816] util: update win32 p_realpath to canonicalize case The POSIX `realpath` function canonicalizes relative paths, symbolic links, and case (on case-insensitive filesystems). For example, on macOS, if you create some file `/private/tmp/FOO`, and you call `realpath("/tmp/foo")`, you get _the real path_ returned of `/private/tmp/FOO`. To emulate this behavior on win32, we call `GetFullPathName` to handle the relative to absolute path conversion, then call `GetLongPathName` to handle the case canonicalization. --- src/util/win32/posix_w32.c | 34 ++++++++++++++++++++++++++++------ tests/util/path/win32.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/util/win32/posix_w32.c b/src/util/win32/posix_w32.c index 3fec469a648..ace23200f59 100644 --- a/src/util/win32/posix_w32.c +++ b/src/util/win32/posix_w32.c @@ -787,13 +787,19 @@ int p_rmdir(const char *path) char *p_realpath(const char *orig_path, char *buffer) { git_win32_path orig_path_w, buffer_w; + DWORD long_len; if (git_win32_path_from_utf8(orig_path_w, orig_path) < 0) return NULL; - /* Note that if the path provided is a relative path, then the current directory + /* + * POSIX realpath performs two functions: first, it turns relative + * paths into absolute paths. For this, we need GetFullPathName. + * + * Note that if the path provided is a relative path, then the current directory * is used to resolve the path -- which is a concurrency issue because the current - * directory is a process-wide variable. */ + * directory is a process-wide variable. + */ if (!GetFullPathNameW(orig_path_w, GIT_WIN_PATH_UTF16, buffer_w, NULL)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) errno = ENAMETOOLONG; @@ -803,9 +809,26 @@ char *p_realpath(const char *orig_path, char *buffer) return NULL; } - /* The path must exist. */ - if (GetFileAttributesW(buffer_w) == INVALID_FILE_ATTRIBUTES) { - errno = ENOENT; + /* + * Then, the path is canonicalized. eg, on macOS, + * "/TMP" -> "/private/tmp". For this, we need GetLongPathName. + */ + if ((long_len = GetLongPathNameW(buffer_w, buffer_w, GIT_WIN_PATH_UTF16)) == 0) { + DWORD error = GetLastError(); + + if (error == ERROR_FILE_NOT_FOUND || + error == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else if (error == ERROR_ACCESS_DENIED) + errno = EPERM; + else + errno = EINVAL; + + return NULL; + } + + if (long_len > GIT_WIN_PATH_UTF16) { + errno = ENAMETOOLONG; return NULL; } @@ -821,7 +844,6 @@ char *p_realpath(const char *orig_path, char *buffer) return NULL; git_fs_path_mkposix(buffer); - return buffer; } diff --git a/tests/util/path/win32.c b/tests/util/path/win32.c index 1aaf6867a26..09a5a8ba881 100644 --- a/tests/util/path/win32.c +++ b/tests/util/path/win32.c @@ -280,3 +280,32 @@ void test_path_win32__8dot3_name(void) git__free(shortname); #endif } + +void test_path_win32__realpath(void) +{ +#ifdef GIT_WIN32 + git_str expected = GIT_STR_INIT; + char result[GIT_PATH_MAX]; + + /* Ensure relative paths become absolute */ + cl_must_pass(git_str_joinpath(&expected, clar_sandbox_path(), "abcdef")); + cl_must_pass(p_mkdir("abcdef", 0777)); + cl_assert(p_realpath("./abcdef", result) != NULL); + cl_assert_equal_s(expected.ptr, result); + + /* Ensure case is canonicalized */ + git_str_clear(&expected); + cl_must_pass(git_str_joinpath(&expected, clar_sandbox_path(), "FOO")); + cl_must_pass(p_mkdir("FOO", 0777)); + cl_assert(p_realpath("foo", result) != NULL); + cl_assert_equal_s(expected.ptr, result); + + cl_assert(p_realpath("nonexistent", result) == NULL); + cl_assert_equal_i(ENOENT, errno); + + git_str_dispose(&expected); + + p_rmdir("abcdef"); + p_rmdir("FOO"); +#endif +} From 57870e9f4d21791d3b62166f5b9b0a67641de942 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 19 Feb 2024 09:04:39 -0800 Subject: [PATCH 419/816] util: clean up test resources in the sandbox Ensure that we clean up cruft that we create for testing, so that future tests don't have troubles. --- tests/util/path/win32.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/util/path/win32.c b/tests/util/path/win32.c index 09a5a8ba881..6f90b447dda 100644 --- a/tests/util/path/win32.c +++ b/tests/util/path/win32.c @@ -278,6 +278,10 @@ void test_path_win32__8dot3_name(void) cl_must_pass(p_mkdir(".bar", 0777)); cl_assert_equal_s("BAR~2", (shortname = git_win32_path_8dot3_name(".bar"))); git__free(shortname); + + p_rmdir(".foo"); + p_rmdir(".bar"); + p_unlink("bar~1"); #endif } From 19d52837e4b879f8cfd903dcfa8e1459f0f92cc6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 00:06:35 +0000 Subject: [PATCH 420/816] repo: trim trailing slashes from safedir error message Our error messages should provide the literal path that users should add to their safe directory allowlist, which means it should not have a trailing slash. --- src/libgit2/repository.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index b2afc4f59d2..0a39e07c084 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -705,9 +705,12 @@ static int validate_ownership(git_repository *repo) goto done; if (!is_safe) { + size_t path_len = git_fs_path_is_root(path) ? + strlen(path) : git_fs_path_dirlen(path); + git_error_set(GIT_ERROR_CONFIG, - "repository path '%s' is not owned by current user", - path); + "repository path '%.*s' is not owned by current user", + (int)min(path_len, INT_MAX), path); error = GIT_EOWNER; } From d970934b29ebad813de9b378f246015df6801da8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 00:39:26 +0000 Subject: [PATCH 421/816] repo: test that '%(prefix)/' safe.directory succeeds Ensure that we can support safe.directory entries that are prefixed with '%(prefix)/'. --- tests/libgit2/repo/open.c | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index 9c0bfde7b57..595440a68dd 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -779,3 +779,69 @@ void test_repo_open__can_reset_safe_directory_list(void) git_str_dispose(&config_filename); git_str_dispose(&config_data); } + +void test_repo_open__can_handle_prefixed_safe_paths(void) +{ + git_repository *repo; + git_str config_path = GIT_STR_INIT, + config_filename = GIT_STR_INIT, + config_data = GIT_STR_INIT; + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); + + cl_fixture_sandbox("empty_standard_repo"); + cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); + + git_fs_path__set_owner(GIT_FS_PATH_OWNER_OTHER); + cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); + + /* Add safe.directory options to the global configuration */ + git_str_joinpath(&config_path, clar_sandbox_path(), "__global_config"); + cl_must_pass(p_mkdir(config_path.ptr, 0777)); + git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, config_path.ptr); + + git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); + + /* + * Using "%(prefix)/" becomes "%(prefix)//tmp/foo" - so + * "%(prefix)/" is stripped and means the literal path + * follows. + */ + git_str_clear(&config_data); + git_str_printf(&config_data, + "[foo]\n" \ + "\tbar = Foobar\n" \ + "\tbaz = Baz!\n" \ + "[safe]\n" \ + "\tdirectory = %%(prefix)/%s/%s\n" \ + "[bar]\n" \ + "\tfoo = barfoo\n", + clar_sandbox_path(), "empty_standard_repo"); + cl_git_rewritefile(config_filename.ptr, config_data.ptr); + + cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); + git_repository_free(repo); + + /* + * Using "%(prefix)" becomes "%(prefix)/tmp/foo" - so it's + * actually trying to look in the git prefix, for example, + * "/usr/local/tmp/foo", which we don't actually support. + */ + git_str_clear(&config_data); + git_str_printf(&config_data, + "[foo]\n" \ + "\tbar = Foobar\n" \ + "\tbaz = Baz!\n" \ + "[safe]\n" \ + "\tdirectory = %%(prefix)%s/%s\n" \ + "[bar]\n" \ + "\tfoo = barfoo\n", + clar_sandbox_path(), "empty_standard_repo"); + cl_git_rewritefile(config_filename.ptr, config_data.ptr); + + cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); + + git_str_dispose(&config_path); + git_str_dispose(&config_filename); + git_str_dispose(&config_data); +} From 71309547ec602a9bd1a2c36d0bfc2b24f3a43cd8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 00:40:44 +0000 Subject: [PATCH 422/816] repo: trim '%(prefix)/' from safedir on all platforms '%(prefix)/' as a leading path name is safe to strip on all platforms. It doesn't make sense to use on non-Windows, but supporting it there does allow us to easily dev/test. --- src/libgit2/repository.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 0a39e07c084..372c43f5ea6 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -558,15 +558,14 @@ typedef struct { static int validate_ownership_cb(const git_config_entry *entry, void *payload) { validate_ownership_data *data = payload; + const char *test_path; if (strcmp(entry->value, "") == 0) { *data->is_safe = false; } else if (strcmp(entry->value, "*") == 0) { *data->is_safe = true; } else { - const char *test_path = entry->value; - - if (git_str_sets(&data->tmp, test_path) < 0 || + if (git_str_sets(&data->tmp, entry->value) < 0 || git_fs_path_to_dir(&data->tmp) < 0) return -1; @@ -575,20 +574,22 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) * input path by adding a trailing backslash. * A trailing backslash on the input is not allowed. */ - if (strcmp(data->tmp.ptr, test_path) == 0) + if (strcmp(data->tmp.ptr, entry->value) == 0) return 0; -#ifdef GIT_WIN32 + test_path = data->tmp.ptr; + /* - * Git for Windows does some truly bizarre things with - * paths that start with a forward slash; and expects you - * to escape that with `%(prefix)`. This syntax generally - * means to add the prefix that Git was installed to -- eg - * `/usr/local` -- unless it's an absolute path, in which - * case the leading `%(prefix)/` is just removed. And Git - * for Windows expects you to use this syntax for absolute - * Unix-style paths (in "Git Bash" or Windows Subsystem for - * Linux). + * Git - and especially, Git for Windows - does some + * truly bizarre things with paths that start with a + * forward slash; and expects you to escape that with + * `%(prefix)`. This syntax generally means to add the + * prefix that Git was installed to (eg `/usr/local`) + * unless it's an absolute path, in which case the + * leading `%(prefix)/` is just removed. And Git for + * Windows expects you to use this syntax for absolute + * Unix-style paths (in "Git Bash" or Windows Subsystem + * for Linux). * * Worse, the behavior used to be that a leading `/` was * not absolute. It would indicate that Git for Windows @@ -603,12 +604,13 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) */ if (strncmp(test_path, "%(prefix)//", strlen("%(prefix)//")) == 0) test_path += strlen("%(prefix)/"); +#ifdef GIT_WIN32 else if (strncmp(test_path, "//", 2) == 0 && strncmp(test_path, "//wsl.localhost/", strlen("//wsl.localhost/")) != 0) test_path++; #endif - if (strcmp(data->tmp.ptr, data->repo_path) == 0) + if (strcmp(test_path, data->repo_path) == 0) *data->is_safe = true; } From b19a6a1582c626a2253ad232b087542f10c3cb62 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 14:40:26 +0000 Subject: [PATCH 423/816] repo: refactor safe directory tests Provide a helper method in the tests to set up the safe.directory configuration for a normal and bare repository to avoid some copy/pasta. (Some copypasta will remain, since there's customizations to the file that are not trivially abstractable.) --- tests/libgit2/repo/open.c | 260 +++++++++++++++----------------------- 1 file changed, 100 insertions(+), 160 deletions(-) diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index 595440a68dd..7719bbd1b82 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -533,15 +533,21 @@ void test_repo_open__validates_bare_repo_ownership(void) cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "testrepo.git")); } -void test_repo_open__can_allowlist_dirs_with_problematic_ownership(void) +static int test_safe_path(const char *path) { git_repository *repo; git_str config_path = GIT_STR_INIT, config_filename = GIT_STR_INIT, config_data = GIT_STR_INIT; + int error; cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); + /* + * Sandbox the fixture, and ensure that when we fake an owner + * of "other" that the repository cannot be opened (and fails + * with `GIT_EOWNER`). + */ cl_fixture_sandbox("empty_standard_repo"); cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); @@ -555,93 +561,35 @@ void test_repo_open__can_allowlist_dirs_with_problematic_ownership(void) git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); - /* Test with incorrect exception (slash at the end) */ - git_str_printf(&config_data, - "[foo]\n" \ - "\tbar = Foobar\n" \ - "\tbaz = Baz!\n" \ - "[safe]\n" \ - "\tdirectory = /non/existent/path\n" \ - "\tdirectory = /\n" \ - "\tdirectory = c:\\\\temp\n" \ - "\tdirectory = %s/%s/\n" \ - "\tdirectory = /tmp\n" \ - "[bar]\n" \ - "\tfoo = barfoo\n", - clar_sandbox_path(), "empty_standard_repo"); - cl_git_rewritefile(config_filename.ptr, config_data.ptr); - cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); - - /* Test with correct exception */ git_str_clear(&config_data); git_str_printf(&config_data, "[foo]\n" \ "\tbar = Foobar\n" \ "\tbaz = Baz!\n" \ "[safe]\n" \ - "\tdirectory = /non/existent/path\n" \ - "\tdirectory = /\n" \ - "\tdirectory = c:\\\\temp\n" \ - "\tdirectory = %s/%s\n" \ - "\tdirectory = /tmp\n" \ + "\tdirectory = %s\n" \ "[bar]\n" \ "\tfoo = barfoo\n", - clar_sandbox_path(), "empty_standard_repo"); + path); cl_git_rewritefile(config_filename.ptr, config_data.ptr); - cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); + error = git_repository_open(&repo, "empty_standard_repo"); git_repository_free(repo); git_str_dispose(&config_path); git_str_dispose(&config_filename); git_str_dispose(&config_data); -} - -void test_repo_open__can_wildcard_allowlist_with_problematic_ownership(void) -{ - git_repository *repo; - git_str config_path = GIT_STR_INIT, config_filename = GIT_STR_INIT; - - cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); - - cl_fixture_sandbox("empty_standard_repo"); - cl_git_pass(cl_rename( - "empty_standard_repo/.gitted", "empty_standard_repo/.git")); - - git_fs_path__set_owner(GIT_FS_PATH_OWNER_OTHER); - cl_git_fail_with( - GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); - - /* Add safe.directory options to the global configuration */ - git_str_joinpath(&config_path, clar_sandbox_path(), "__global_config"); - cl_must_pass(p_mkdir(config_path.ptr, 0777)); - git_libgit2_opts( - GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, - config_path.ptr); - - git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); - - cl_git_rewritefile(config_filename.ptr, "[foo]\n" - "\tbar = Foobar\n" - "\tbaz = Baz!\n" - "[safe]\n" - "\tdirectory = *\n" - "[bar]\n" - "\tfoo = barfoo\n"); - - cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); - git_repository_free(repo); - git_str_dispose(&config_path); - git_str_dispose(&config_filename); + return error; } -void test_repo_open__can_allowlist_bare_gitdir(void) +static int test_bare_safe_path(const char *path) { git_repository *repo; git_str config_path = GIT_STR_INIT, config_filename = GIT_STR_INIT, config_data = GIT_STR_INIT; + int error; cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); @@ -665,56 +613,114 @@ void test_repo_open__can_allowlist_bare_gitdir(void) "\tdirectory = /non/existent/path\n" \ "\tdirectory = /\n" \ "\tdirectory = c:\\\\temp\n" \ - "\tdirectory = %s/%s\n" \ + "\tdirectory = %s\n" \ "\tdirectory = /tmp\n" \ "[bar]\n" \ "\tfoo = barfoo\n", - clar_sandbox_path(), "testrepo.git"); + path); cl_git_rewritefile(config_filename.ptr, config_data.ptr); - cl_git_pass(git_repository_open(&repo, "testrepo.git")); + error = git_repository_open(&repo, "testrepo.git"); git_repository_free(repo); git_str_dispose(&config_path); git_str_dispose(&config_filename); git_str_dispose(&config_data); + + return error; } -void test_repo_open__can_wildcard_allowlist_bare_gitdir(void) +void test_repo_open__can_allowlist_dirs_with_problematic_ownership(void) { - git_repository *repo; - git_str config_path = GIT_STR_INIT, config_filename = GIT_STR_INIT; + git_str path = GIT_STR_INIT; - cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); + cl_git_pass(git_str_printf(&path, "%s/%s", + clar_sandbox_path(), "empty_standard_repo")); + cl_git_pass(test_safe_path(path.ptr)); + git_str_dispose(&path); +} - cl_fixture_sandbox("testrepo.git"); +void test_repo_open__safe_directory_fails_with_trailing_slash(void) +{ + git_str path = GIT_STR_INIT; - git_fs_path__set_owner(GIT_FS_PATH_OWNER_OTHER); - cl_git_fail_with( - GIT_EOWNER, git_repository_open(&repo, "testrepo.git")); + /* + * "/tmp/foo/" is not permitted; safe path must be specified + * as "/tmp/foo" + */ + cl_git_pass(git_str_printf(&path, "%s/%s/", + clar_sandbox_path(), "empty_standard_repo")); + cl_git_fail_with(GIT_EOWNER, test_safe_path(path.ptr)); + git_str_dispose(&path); +} - /* Add safe.directory options to the global configuration */ - git_str_joinpath(&config_path, clar_sandbox_path(), "__global_config"); - cl_must_pass(p_mkdir(config_path.ptr, 0777)); - git_libgit2_opts( - GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, - config_path.ptr); +void test_repo_open__can_wildcard_allowlist_with_problematic_ownership(void) +{ + cl_git_pass(test_safe_path("*")); +} - git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); +void test_repo_open__can_allowlist_bare_gitdir(void) +{ + git_str path = GIT_STR_INIT; - cl_git_rewritefile(config_filename.ptr, "[foo]\n" - "\tbar = Foobar\n" - "\tbaz = Baz!\n" - "[safe]\n" - "\tdirectory = *\n" - "[bar]\n" - "\tfoo = barfoo\n"); + cl_git_pass(git_str_printf(&path, "%s/%s", + clar_sandbox_path(), "testrepo.git")); + cl_git_pass(test_bare_safe_path(path.ptr)); + git_str_dispose(&path); +} - cl_git_pass(git_repository_open(&repo, "testrepo.git")); - git_repository_free(repo); +void test_repo_open__can_wildcard_allowlist_bare_gitdir(void) +{ + cl_git_pass(test_bare_safe_path("*")); +} - git_str_dispose(&config_path); - git_str_dispose(&config_filename); +void test_repo_open__can_handle_prefixed_safe_paths(void) +{ +#ifndef GIT_WIN32 + git_str path = GIT_STR_INIT; + + /* + * Using "%(prefix)/" becomes "%(prefix)//tmp/foo" - so + * "%(prefix)/" is stripped and means the literal path + * follows. + */ + cl_git_pass(git_str_printf(&path, "%%(prefix)/%s/%s", + clar_sandbox_path(), "empty_standard_repo")); + cl_git_pass(test_safe_path(path.ptr)); + git_str_dispose(&path); +#endif +} + +void test_repo_open__prefixed_safe_paths_must_have_two_slashes(void) +{ + git_str path = GIT_STR_INIT; + + /* + * Using "%(prefix)" becomes "%(prefix)/tmp/foo" - so it's + * actually trying to look in the git prefix, for example, + * "/usr/local/tmp/foo", which we don't actually support. + */ + cl_git_pass(git_str_printf(&path, "%%(prefix)%s/%s", + clar_sandbox_path(), "empty_standard_repo")); + cl_git_fail_with(GIT_EOWNER, test_safe_path(path.ptr)); + git_str_dispose(&path); +} + +void test_repo_open__can_handle_win32_prefixed_safe_paths(void) +{ +#ifdef GIT_WIN32 + git_str path = GIT_STR_INIT; + + /* + * On Windows, we need %(prefix)///wsl.localhost/C:/foo/bar/... + * because we can't have nice things. + */ + cl_git_pass(git_str_printf(&path, + "%%(prefix)///localhost/%s/%s", + clar_sandbox_path(), "empty_standard_repo")); + cl_git_pass(test_safe_path(path.ptr)); + git_str_dispose(&path); +#endif } void test_repo_open__can_reset_safe_directory_list(void) @@ -779,69 +785,3 @@ void test_repo_open__can_reset_safe_directory_list(void) git_str_dispose(&config_filename); git_str_dispose(&config_data); } - -void test_repo_open__can_handle_prefixed_safe_paths(void) -{ - git_repository *repo; - git_str config_path = GIT_STR_INIT, - config_filename = GIT_STR_INIT, - config_data = GIT_STR_INIT; - - cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); - - cl_fixture_sandbox("empty_standard_repo"); - cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); - - git_fs_path__set_owner(GIT_FS_PATH_OWNER_OTHER); - cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); - - /* Add safe.directory options to the global configuration */ - git_str_joinpath(&config_path, clar_sandbox_path(), "__global_config"); - cl_must_pass(p_mkdir(config_path.ptr, 0777)); - git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, config_path.ptr); - - git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); - - /* - * Using "%(prefix)/" becomes "%(prefix)//tmp/foo" - so - * "%(prefix)/" is stripped and means the literal path - * follows. - */ - git_str_clear(&config_data); - git_str_printf(&config_data, - "[foo]\n" \ - "\tbar = Foobar\n" \ - "\tbaz = Baz!\n" \ - "[safe]\n" \ - "\tdirectory = %%(prefix)/%s/%s\n" \ - "[bar]\n" \ - "\tfoo = barfoo\n", - clar_sandbox_path(), "empty_standard_repo"); - cl_git_rewritefile(config_filename.ptr, config_data.ptr); - - cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); - git_repository_free(repo); - - /* - * Using "%(prefix)" becomes "%(prefix)/tmp/foo" - so it's - * actually trying to look in the git prefix, for example, - * "/usr/local/tmp/foo", which we don't actually support. - */ - git_str_clear(&config_data); - git_str_printf(&config_data, - "[foo]\n" \ - "\tbar = Foobar\n" \ - "\tbaz = Baz!\n" \ - "[safe]\n" \ - "\tdirectory = %%(prefix)%s/%s\n" \ - "[bar]\n" \ - "\tfoo = barfoo\n", - clar_sandbox_path(), "empty_standard_repo"); - cl_git_rewritefile(config_filename.ptr, config_data.ptr); - - cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, "empty_standard_repo")); - - git_str_dispose(&config_path); - git_str_dispose(&config_filename); - git_str_dispose(&config_data); -} From c1734b5ae42809a322977f9fe0dd26ccebd19a94 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 07:04:00 -0800 Subject: [PATCH 424/816] repo: test for safe.directory with unc paths On Windows, you may open a repo with UNC path format -- for example \\share\foo\bar, or as a git-style path, //share/foo/bar. In this world, Git for Windows expects you to translate this to $(prefix)//share/foo/bar. We can test for that by using the fact that local drives are exposed as hidden shares. For example, C:\Foo is //localhost/C$/Foo/. --- tests/libgit2/repo/open.c | 50 +++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index 7719bbd1b82..f859838aeb3 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -709,17 +709,53 @@ void test_repo_open__prefixed_safe_paths_must_have_two_slashes(void) void test_repo_open__can_handle_win32_prefixed_safe_paths(void) { #ifdef GIT_WIN32 - git_str path = GIT_STR_INIT; + git_repository *repo; + git_str unc_path = GIT_STR_INIT, + config_path = GIT_STR_INIT, + config_filename = GIT_STR_INIT, + config_data = GIT_STR_INIT; + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); + + cl_fixture_sandbox("empty_standard_repo"); + cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); /* - * On Windows, we need %(prefix)///wsl.localhost/C:/foo/bar/... - * because we can't have nice things. + * On Windows, we can generally map a local drive to a UNC path; + * for example C:\Foo\Bar becomes //localhost/C$/Foo/bar */ - cl_git_pass(git_str_printf(&path, - "%%(prefix)///localhost/%s/%s", + cl_git_pass(git_str_printf(&unc_path, "//localhost/%s/%s", clar_sandbox_path(), "empty_standard_repo")); - cl_git_pass(test_safe_path(path.ptr)); - git_str_dispose(&path); + + if (unc_path.ptr[13] != ':' || unc_path.ptr[14] != '/') + cl_skip(); + + unc_path.ptr[13] = '$'; + + git_fs_path__set_owner(GIT_FS_PATH_OWNER_OTHER); + cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, unc_path.ptr)); + + /* Add safe.directory options to the global configuration */ + git_str_joinpath(&config_path, clar_sandbox_path(), "__global_config"); + cl_must_pass(p_mkdir(config_path.ptr, 0777)); + git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, config_path.ptr); + + git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); + + /* The blank resets our sandbox directory and opening fails */ + + git_str_printf(&config_data, + "[safe]\n\tdirectory = %%(prefix)/%s\n", + unc_path.ptr); + cl_git_rewritefile(config_filename.ptr, config_data.ptr); + + cl_git_pass(git_repository_open(&repo, unc_path.ptr)); + git_repository_free(repo); + + git_str_dispose(&config_path); + git_str_dispose(&config_filename); + git_str_dispose(&config_data); + git_str_dispose(&unc_path); #endif } From e9d55212890ed0cb695485aadac0a2cc4e89ecb3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 18 Feb 2024 07:47:26 -0800 Subject: [PATCH 425/816] repo: handle root paths properly for safe directories When doing directory name munging to remove trailing slashes, ensure that we do not remove the trailing slash from the path root, whether that's '/' or 'C:\'. --- src/libgit2/repository.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 372c43f5ea6..6df9e63f2bb 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -565,17 +565,18 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) } else if (strcmp(entry->value, "*") == 0) { *data->is_safe = true; } else { - if (git_str_sets(&data->tmp, entry->value) < 0 || - git_fs_path_to_dir(&data->tmp) < 0) + if (git_str_sets(&data->tmp, entry->value) < 0) return -1; - /* - * Ensure that `git_fs_path_to_dir` mutated the - * input path by adding a trailing backslash. - * A trailing backslash on the input is not allowed. - */ - if (strcmp(data->tmp.ptr, entry->value) == 0) - return 0; + if (!git_fs_path_is_root(data->tmp.ptr)) { + /* Input must not have trailing backslash. */ + if (!data->tmp.size || + data->tmp.ptr[data->tmp.size - 1] == '/') + return 0; + + if (git_fs_path_to_dir(&data->tmp) < 0) + return -1; + } test_path = data->tmp.ptr; From 9c31bd0358acfcafe45bb6a2fe5da6ce5d0d1f01 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 19 Feb 2024 07:23:33 -0800 Subject: [PATCH 426/816] repo: allow safe.directory to be a UNC path Recent versions of Git for Windows allow a sane UNC style path to be used directly in `safe.directory` (without needing the `%(prefix)` silliness). Match that behavior. --- src/libgit2/repository.c | 5 ---- tests/libgit2/repo/open.c | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 6df9e63f2bb..2c16808c7fc 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -605,11 +605,6 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) */ if (strncmp(test_path, "%(prefix)//", strlen("%(prefix)//")) == 0) test_path += strlen("%(prefix)/"); -#ifdef GIT_WIN32 - else if (strncmp(test_path, "//", 2) == 0 && - strncmp(test_path, "//wsl.localhost/", strlen("//wsl.localhost/")) != 0) - test_path++; -#endif if (strcmp(test_path, data->repo_path) == 0) *data->is_safe = true; diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index f859838aeb3..a1acfae9022 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -759,6 +759,59 @@ void test_repo_open__can_handle_win32_prefixed_safe_paths(void) #endif } +void test_repo_open__can_handle_win32_unc_safe_paths(void) +{ +#ifdef GIT_WIN32 + git_repository *repo; + git_str unc_path = GIT_STR_INIT, + config_path = GIT_STR_INIT, + config_filename = GIT_STR_INIT, + config_data = GIT_STR_INIT; + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 1)); + + cl_fixture_sandbox("empty_standard_repo"); + cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); + + /* + * On Windows, we can generally map a local drive to a UNC path; + * for example C:\Foo\Bar becomes //localhost/C$/Foo/bar + */ + cl_git_pass(git_str_printf(&unc_path, "//localhost/%s/%s", + clar_sandbox_path(), "empty_standard_repo")); + + if (unc_path.ptr[13] != ':' || unc_path.ptr[14] != '/') + cl_skip(); + + unc_path.ptr[13] = '$'; + + git_fs_path__set_owner(GIT_FS_PATH_OWNER_OTHER); + cl_git_fail_with(GIT_EOWNER, git_repository_open(&repo, unc_path.ptr)); + + /* Add safe.directory options to the global configuration */ + git_str_joinpath(&config_path, clar_sandbox_path(), "__global_config"); + cl_must_pass(p_mkdir(config_path.ptr, 0777)); + git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, config_path.ptr); + + git_str_joinpath(&config_filename, config_path.ptr, ".gitconfig"); + + /* The blank resets our sandbox directory and opening fails */ + + git_str_printf(&config_data, + "[safe]\n\tdirectory = %s\n", + unc_path.ptr); + cl_git_rewritefile(config_filename.ptr, config_data.ptr); + + cl_git_pass(git_repository_open(&repo, unc_path.ptr)); + git_repository_free(repo); + + git_str_dispose(&config_path); + git_str_dispose(&config_filename); + git_str_dispose(&config_data); + git_str_dispose(&unc_path); +#endif +} + void test_repo_open__can_reset_safe_directory_list(void) { git_repository *repo; From c63eccc3e5d2fe4481270431c9fb3377f2949595 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 09:56:26 +0000 Subject: [PATCH 427/816] revparse: ensure bare '@' is truly bare Support a revspec of '@' to mean 'HEAD', but ensure that it's at the start of the revspec. Previously we were erroneously allowing 'foo@' to mean 'HEAD' as well. Instead, 'foo@' should be rejected. --- src/libgit2/revparse.c | 6 ++++++ tests/libgit2/refs/revparse.c | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/libgit2/revparse.c b/src/libgit2/revparse.c index 06d92f82bf2..bf8131aab79 100644 --- a/src/libgit2/revparse.c +++ b/src/libgit2/revparse.c @@ -817,6 +817,12 @@ static int revparse( base_rev = temp_object; break; } else if (spec[pos+1] == '\0') { + if (pos) { + git_error_set(GIT_ERROR_REFERENCE, "invalid revspec"); + error = GIT_EINVALIDSPEC; + goto cleanup; + } + spec = "HEAD"; identifier_len = 4; parsed = true; diff --git a/tests/libgit2/refs/revparse.c b/tests/libgit2/refs/revparse.c index d2f464840a0..3fe07811796 100644 --- a/tests/libgit2/refs/revparse.c +++ b/tests/libgit2/refs/revparse.c @@ -889,3 +889,15 @@ void test_refs_revparse__parses_at_head(void) test_id("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVSPEC_SINGLE); test_id("@", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVSPEC_SINGLE); } + +void test_refs_revparse__rejects_bogus_at(void) +{ + git_repository *repo; + git_object *target; + + repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_fail_with(GIT_EINVALIDSPEC, git_revparse_single(&target, repo, "foo@")); + + cl_git_sandbox_cleanup(); +} From af68b86baad93fa529e6fe412c2b129c80ddb0d8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 09:57:18 +0000 Subject: [PATCH 428/816] revspec: correct capitalization for error message --- src/libgit2/revparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/revparse.c b/src/libgit2/revparse.c index bf8131aab79..08237628793 100644 --- a/src/libgit2/revparse.c +++ b/src/libgit2/revparse.c @@ -941,7 +941,7 @@ int git_revparse( * allowed. */ if (!git__strcmp(spec, "..")) { - git_error_set(GIT_ERROR_INVALID, "Invalid pattern '..'"); + git_error_set(GIT_ERROR_INVALID, "invalid pattern '..'"); return GIT_EINVALIDSPEC; } From 6e8c09a46f4136ada0601a75546f5b6bfb6298d0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 03:16:04 -0800 Subject: [PATCH 429/816] repo: ensure we can initialize win32 paths Given a win32 path, ensure that we can initialize it. This involves a posix-style path conversion at the beginning of our initialization. --- src/libgit2/repository.c | 2 ++ tests/libgit2/repo/init.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index b2afc4f59d2..737b96445a4 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -2676,6 +2676,8 @@ static int repo_init_directories( if (git_str_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0) return -1; + git_fs_path_mkposix(repo_path->ptr); + has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0); if (has_dotgit) opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT; diff --git a/tests/libgit2/repo/init.c b/tests/libgit2/repo/init.c index d78ec063cd2..446ab735e4e 100644 --- a/tests/libgit2/repo/init.c +++ b/tests/libgit2/repo/init.c @@ -755,3 +755,28 @@ void test_repo_init__longpath(void) git_str_dispose(&path); #endif } + +void test_repo_init__absolute_path_with_backslashes(void) +{ +#ifdef GIT_WIN32 + git_repository_init_options initopts = GIT_REPOSITORY_INIT_OPTIONS_INIT; + git_str path = GIT_STR_INIT; + char *c; + + cl_set_cleanup(&cleanup_repository, "path"); + + cl_git_pass(git_str_joinpath(&path, clar_sandbox_path(), "path/to/newrepo")); + + for (c = path.ptr; *c; c++) { + if (*c == '/') + *c = '\\'; + } + + initopts.flags |= GIT_REPOSITORY_INIT_MKDIR | GIT_REPOSITORY_INIT_MKPATH; + + cl_git_pass(git_repository_init_ext(&g_repo, path.ptr, &initopts)); + git_str_dispose(&path); +#else + clar__skip(); +#endif +} From 267479dad5bfc8b028965e54a2625f3960f9d319 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 11:31:22 +0000 Subject: [PATCH 430/816] http: support empty http.proxy config setting An empty `http.proxy` config setting should be treated like a missing `http.proxy` config setting. --- src/libgit2/transports/http.c | 2 +- src/libgit2/transports/winhttp.c | 2 +- tests/libgit2/online/fetch.c | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index 8437674fcc9..00bfcb0b39b 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -334,7 +334,7 @@ static int lookup_proxy( return 0; } - if (!proxy || + if (!proxy || !*proxy || (error = git_net_url_parse_http(&transport->proxy.url, proxy)) < 0) goto done; diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index ae572c56d8e..031ff3f70b0 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -436,7 +436,7 @@ static int winhttp_stream_connect(winhttp_stream *s) GIT_ERROR_CHECK_ALLOC(proxy_url); } - if (proxy_url) { + if (proxy_url && *proxy_url) { git_str processed_url = GIT_STR_INIT; WINHTTP_PROXY_INFO proxy_info; wchar_t *proxy_wide; diff --git a/tests/libgit2/online/fetch.c b/tests/libgit2/online/fetch.c index d640eac1b6c..08a14c6317d 100644 --- a/tests/libgit2/online/fetch.c +++ b/tests/libgit2/online/fetch.c @@ -110,6 +110,26 @@ void test_online_fetch__fetch_twice(void) git_remote_free(remote); } +void test_online_fetch__fetch_with_empty_http_proxy(void) +{ + git_remote *remote; + git_config *config; + git_fetch_options opts = GIT_FETCH_OPTIONS_INIT; + + opts.proxy_opts.type = GIT_PROXY_AUTO; + + cl_git_pass(git_repository_config(&config, _repo)); + cl_git_pass(git_config_set_string(config, "http.proxy", "")); + + cl_git_pass(git_remote_create(&remote, _repo, "test", + "https://github.com/libgit2/TestGitRepository")); + cl_git_pass(git_remote_fetch(remote, NULL, &opts, NULL)); + + git_remote_disconnect(remote); + git_remote_free(remote); + git_config_free(config); +} + static int transferProgressCallback(const git_indexer_progress *stats, void *payload) { bool *invoked = (bool *)payload; From 4a1c2bd8ced01f4b95b924a7c0348b5684a726f7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 12:37:58 +0000 Subject: [PATCH 431/816] diff: fix test for SHA256 support in diff_from_buffer --- tests/libgit2/diff/parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libgit2/diff/parse.c b/tests/libgit2/diff/parse.c index 0e5eb2809c8..59fc0280ed6 100644 --- a/tests/libgit2/diff/parse.c +++ b/tests/libgit2/diff/parse.c @@ -294,7 +294,7 @@ void test_diff_parse__eof_nl_missing(void) git_patch *ret_patch; git_diff_line *line; - cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(diff_from_buffer(&diff, patch, strlen(patch))); cl_git_pass(git_patch_from_diff(&ret_patch, diff, 0)); cl_assert((line = git_array_get(ret_patch->lines, 2)) != NULL); From 6b542105950b0d99b1d49d25d0db8f397e7e46e9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 13:42:38 +0000 Subject: [PATCH 432/816] merge: refactor merge tests for empty files treated as renames Don't munge the "trivial" tests, those are specifically about the "trivial" resolutions for git's tree merge. (For example, adding a file in a new branch and making no changes in the HEAD branch is something that can be handled _trivially_.) For tests of rename functionality, put them in the trees::rename tests. --- tests/libgit2/merge/trees/renames.c | 19 ++++++ tests/libgit2/merge/trees/trivial.c | 55 +++++------------- .../.gitted/logs/refs/heads/trivial-15 | 1 - .../.gitted/logs/refs/heads/trivial-15-branch | 2 - .../1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 | Bin 279 -> 0 bytes .../merge-resolve/.gitted/objects/29 | Bin 0 -> 75 bytes .../48/320305de02310b9c4fd744243b9b0d1d5f11af | Bin 46 -> 0 bytes .../54/c9d15687fb4f56e08252662962d6d1dbc09d9d | 3 + .../57/16ca5987cbf97d6bb54920bea6adde242d87e6 | Bin 0 -> 19 bytes .../60/b12be2d2f57977ce83d8dfd32e2394ac1ba1a2 | Bin 0 -> 38 bytes .../67/06996f054c6af4fec7c77939d00e2f486dab4c | Bin 172 -> 0 bytes .../a6/5140d5ec9f47064f614ecf8e43776baa5c0c11 | Bin 0 -> 75 bytes .../ab/347abd8cda4a0e3b8bb42bb620c0c72c7df779 | Bin 0 -> 165 bytes .../bc/114411903fd2afaa4bb9b85ed13f27e37ac375 | Bin 0 -> 74 bytes .../c0/d1f321977d1c18e23a28c581fed6d17d0cc013 | Bin 273 -> 0 bytes .../c4/52c5eb5aacf204fc95a55d1eb9668736fecfb6 | Bin 163 -> 0 bytes .../c5/be2acabac675af81df8bb70400235af2a9c225 | 4 -- .../cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 | Bin 280 -> 0 bytes .../cd/edf9760406dc79e0c6a8899ce9f180ec2a23a0 | 2 + .../de/06afe070b65f94d7d791c39a6d389c58dda60d | Bin 0 -> 75 bytes .../e5/0a49f9558d09d4d3bfc108363bb24c127ed263 | Bin 0 -> 20 bytes .../ea/789495e0a72efadcd0f86a48f4c9ed435bb8a3 | 3 + .../.gitted/refs/heads/emptyfile_renames | 1 + .../refs/heads/emptyfile_renames-branch | 1 + .../.gitted/refs/heads/trivial-15 | 1 - .../.gitted/refs/heads/trivial-15-branch | 1 - 26 files changed, 45 insertions(+), 48 deletions(-) delete mode 100644 tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 delete mode 100644 tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch delete mode 100644 tests/resources/merge-resolve/.gitted/objects/1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 create mode 100644 tests/resources/merge-resolve/.gitted/objects/29 delete mode 100644 tests/resources/merge-resolve/.gitted/objects/48/320305de02310b9c4fd744243b9b0d1d5f11af create mode 100644 tests/resources/merge-resolve/.gitted/objects/54/c9d15687fb4f56e08252662962d6d1dbc09d9d create mode 100644 tests/resources/merge-resolve/.gitted/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 create mode 100644 tests/resources/merge-resolve/.gitted/objects/60/b12be2d2f57977ce83d8dfd32e2394ac1ba1a2 delete mode 100644 tests/resources/merge-resolve/.gitted/objects/67/06996f054c6af4fec7c77939d00e2f486dab4c create mode 100644 tests/resources/merge-resolve/.gitted/objects/a6/5140d5ec9f47064f614ecf8e43776baa5c0c11 create mode 100644 tests/resources/merge-resolve/.gitted/objects/ab/347abd8cda4a0e3b8bb42bb620c0c72c7df779 create mode 100644 tests/resources/merge-resolve/.gitted/objects/bc/114411903fd2afaa4bb9b85ed13f27e37ac375 delete mode 100644 tests/resources/merge-resolve/.gitted/objects/c0/d1f321977d1c18e23a28c581fed6d17d0cc013 delete mode 100644 tests/resources/merge-resolve/.gitted/objects/c4/52c5eb5aacf204fc95a55d1eb9668736fecfb6 delete mode 100644 tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 delete mode 100644 tests/resources/merge-resolve/.gitted/objects/cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 create mode 100644 tests/resources/merge-resolve/.gitted/objects/cd/edf9760406dc79e0c6a8899ce9f180ec2a23a0 create mode 100644 tests/resources/merge-resolve/.gitted/objects/de/06afe070b65f94d7d791c39a6d389c58dda60d create mode 100644 tests/resources/merge-resolve/.gitted/objects/e5/0a49f9558d09d4d3bfc108363bb24c127ed263 create mode 100644 tests/resources/merge-resolve/.gitted/objects/ea/789495e0a72efadcd0f86a48f4c9ed435bb8a3 create mode 100644 tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames create mode 100644 tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames-branch delete mode 100644 tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 delete mode 100644 tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch diff --git a/tests/libgit2/merge/trees/renames.c b/tests/libgit2/merge/trees/renames.c index a27945ee071..9507b51bc9e 100644 --- a/tests/libgit2/merge/trees/renames.c +++ b/tests/libgit2/merge/trees/renames.c @@ -350,3 +350,22 @@ void test_merge_trees_renames__cache_recomputation(void) git_tree_free(our_tree); git__free(data); } + +void test_merge_trees_renames__emptyfile_renames(void) +{ + git_index *index; + git_merge_options *opts = NULL; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", 1, "bar" }, + { 0100644, "60b12be2d2f57977ce83d8dfd32e2394ac1ba1a2", 3, "bar" }, + { 0100644, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", 0, "boo" }, + { 0100644, "e50a49f9558d09d4d3bfc108363bb24c127ed263", 0, "foo" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, + "emptyfile_renames", "emptyfile_renames-branch", + opts)); + cl_assert(merge_test_index(index, merge_index_entries, 4)); + git_index_free(index); +} diff --git a/tests/libgit2/merge/trees/trivial.c b/tests/libgit2/merge/trees/trivial.c index 7f9d918e806..287a53cfe7a 100644 --- a/tests/libgit2/merge/trees/trivial.c +++ b/tests/libgit2/merge/trees/trivial.c @@ -25,7 +25,7 @@ void test_merge_trees_trivial__cleanup(void) } -static int merge_trivial(git_index **index, const char *ours, const char *theirs, bool ancestor_use_parent) +static int merge_trivial(git_index **index, const char *ours, const char *theirs) { git_commit *our_commit, *their_commit, *ancestor_commit; git_tree *our_tree, *their_tree, *ancestor_tree; @@ -42,12 +42,8 @@ static int merge_trivial(git_index **index, const char *ours, const char *theirs cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); - if (!ancestor_use_parent) { - cl_git_pass(git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))); - cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); - } else { - cl_git_pass(git_commit_parent(&ancestor_commit, their_commit, 0)); - } + cl_git_pass(git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))); + cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); cl_git_pass(git_commit_tree(&our_tree, our_commit)); @@ -88,7 +84,7 @@ void test_merge_trees_trivial__2alt(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch")); cl_assert(entry = git_index_get_bypath(result, "new-in-branch.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -103,7 +99,7 @@ void test_merge_trees_trivial__3alt(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch")); cl_assert(entry = git_index_get_bypath(result, "new-in-3alt.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -118,7 +114,7 @@ void test_merge_trees_trivial__4(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch")); cl_assert((entry = git_index_get_bypath(result, "new-and-different.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -136,7 +132,7 @@ void test_merge_trees_trivial__5alt_1(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch")); cl_assert(entry = git_index_get_bypath(result, "new-and-same.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -151,7 +147,7 @@ void test_merge_trees_trivial__5alt_2(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch")); cl_assert(entry = git_index_get_bypath(result, "modified-to-same.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -167,7 +163,7 @@ void test_merge_trees_trivial__6(void) const git_index_entry *entry; const git_index_reuc_entry *reuc; - cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch")); cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 1); @@ -185,7 +181,7 @@ void test_merge_trees_trivial__8(void) const git_index_entry *entry; const git_index_reuc_entry *reuc; - cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch")); cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); @@ -203,7 +199,7 @@ void test_merge_trees_trivial__7(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch")); cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -222,7 +218,7 @@ void test_merge_trees_trivial__10(void) const git_index_entry *entry; const git_index_reuc_entry *reuc; - cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch")); cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); @@ -240,7 +236,7 @@ void test_merge_trees_trivial__9(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch")); cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -259,7 +255,7 @@ void test_merge_trees_trivial__13(void) const git_index_entry *entry; git_oid expected_oid; - cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch")); cl_assert(entry = git_index_get_bypath(result, "modified-in-13.txt", 0)); cl_git_pass(git_oid__fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b", GIT_OID_SHA1)); @@ -278,7 +274,7 @@ void test_merge_trees_trivial__14(void) const git_index_entry *entry; git_oid expected_oid; - cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch")); cl_assert(entry = git_index_get_bypath(result, "modified-in-14-branch.txt", 0)); cl_git_pass(git_oid__fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9", GIT_OID_SHA1)); @@ -296,7 +292,7 @@ void test_merge_trees_trivial__11(void) git_index *result; const git_index_entry *entry; - cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch", false)); + cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch")); cl_assert((entry = git_index_get_bypath(result, "modified-in-both.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -308,22 +304,3 @@ void test_merge_trees_trivial__11(void) git_index_free(result); } - -/* 15: ancest:remote^, head:head, remote:remote = result:no merge */ -void test_merge_trees_trivial__15(void) -{ - git_index *result; - const git_index_entry *entry; - - /* Can't use merge_trivialfalsehere because a different ancestor is used. */ - cl_git_pass(merge_trivial(&result, "trivial-15", "trivial-15-branch", true)); - - cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_NORMAL)) == NULL); - cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_ANCESTOR))); - cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_OURS)) == NULL); - cl_assert((entry = git_index_get_bypath(result, "another-new-empty-15.txt", GIT_INDEX_STAGE_THEIRS))); - cl_assert(merge_trivial_conflict_entrycount(result) == 2); - - git_index_free(result); -} - diff --git a/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 b/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 deleted file mode 100644 index c71411b5f11..00000000000 --- a/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15 +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 c452c5eb5aacf204fc95a55d1eb9668736fecfb6 Gregory Herrero 1705326305 +0100 push diff --git a/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch b/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch deleted file mode 100644 index f85a1e96dd9..00000000000 --- a/tests/resources/merge-resolve/.gitted/logs/refs/heads/trivial-15-branch +++ /dev/null @@ -1,2 +0,0 @@ -0000000000000000000000000000000000000000 6706996f054c6af4fec7c77939d00e2f486dab4c Gregory Herrero 1705326302 +0100 push -6706996f054c6af4fec7c77939d00e2f486dab4c c5be2acabac675af81df8bb70400235af2a9c225 Gregory Herrero 1705326412 +0100 push diff --git a/tests/resources/merge-resolve/.gitted/objects/1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 b/tests/resources/merge-resolve/.gitted/objects/1d/6a96dd04ac7354ae6bb4ba24c514500fd0ec89 deleted file mode 100644 index ec618090bdf04fd36e456a413c316a3e8ab4dca1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 279 zcmV+y0qFjC0V^p=O;s>9H)k+3FfcPQQAo_oFUd$P(#=aP*G|#Ju#>6y3}`-K3(#yyOh9hSfPPi(a@)TI=n&J9|yLsoh+rHQksRaubV7 zQi}*`$j?j5$xJTE%u5F=y`uhL(?g2@DO=Gq<_YDCljTJBx*O7ai1V#(6;Mw#=Y#jm>Q5A6JwpRT>i+fSTp_0?Qy}vHCa*HmqIm^0(}VfFxV+4 dKIH3JZ<^*6VlXr?Ff%bxNJ=bXNZ6?T=+f89@^j5M?qAkZp0Y-I;UcJX hT7Eu5xY()4_R~LWv$uLG>|3_>o{Db!GXS}e9ew4xB)b3r literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/48/320305de02310b9c4fd744243b9b0d1d5f11af b/tests/resources/merge-resolve/.gitted/objects/48/320305de02310b9c4fd744243b9b0d1d5f11af deleted file mode 100644 index 25236a804aca5db4fbe9f17b32e88afeb1156a22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46 zcmb#A Cyb`|v diff --git a/tests/resources/merge-resolve/.gitted/objects/54/c9d15687fb4f56e08252662962d6d1dbc09d9d b/tests/resources/merge-resolve/.gitted/objects/54/c9d15687fb4f56e08252662962d6d1dbc09d9d new file mode 100644 index 00000000000..7e0555b3ff6 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/54/c9d15687fb4f56e08252662962d6d1dbc09d9d @@ -0,0 +1,3 @@ +xNI +1W]/a&#~(:FQ\A۸Mtr8K0YK&Xkwə"$pPwjv\RhgI=ŘK*SDaM*z68 .^aG?` +q6Y83W^BMiQ \ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 b/tests/resources/merge-resolve/.gitted/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 new file mode 100644 index 0000000000000000000000000000000000000000..cfc3920fb3f273219368fbff8644d599281d31f4 GIT binary patch literal 19 acmba@bd9V z+xM;eK=jc~)l01?6+$f)dD5?nDf2WDQjs8;iEzePCij<3Z`}*SX_g2nMU9cF&LK(V z#N`NC<_w_#tGImcYcv02x-@(GUo}%}{=B?lT;K5BEX!3#Y5T?F2`B~*0sSW+fIIYf a+x5RYuG{w5@^wHOishTEqk91!2~$WI3Rb58 diff --git a/tests/resources/merge-resolve/.gitted/objects/a6/5140d5ec9f47064f614ecf8e43776baa5c0c11 b/tests/resources/merge-resolve/.gitted/objects/a6/5140d5ec9f47064f614ecf8e43776baa5c0c11 new file mode 100644 index 0000000000000000000000000000000000000000..dc6cf6493cbe7b9ca4bccd8a6e212b4f7c385fa4 GIT binary patch literal 75 zcmV-R0JQ&j0V^p=O;s>6VlXr?Ff%bxNJ=bXcsBRZ>`fQ1IeT|&t}Bnaap*};@I|3_>o{Db!GXTtE9p+*ZB1!-N literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/ab/347abd8cda4a0e3b8bb42bb620c0c72c7df779 b/tests/resources/merge-resolve/.gitted/objects/ab/347abd8cda4a0e3b8bb42bb620c0c72c7df779 new file mode 100644 index 0000000000000000000000000000000000000000..d743a385c215b9e2a6b0073fb81115ba027e1ccd GIT binary patch literal 165 zcmV;W09yZe0i}*jssb?(gx@-+=)EBM?Ia-L#v6EnOuFN|MJ5s>Uf(F*z*<#(1x4jn z>;C|4!{6x4KrAs8mR>ICO0?w3N0m)XNG8PW0#QOq;+8sZ1Dwr~l*8c5Vv9qTK|778 zBWglYv}746l1PuSwhm`{rcQ8KTfMgp4m|1Go%mCH(>}L)1m$J0#yR6*C#S@u^X%Xs TXGC7pc4Zh1N^9Z;oFY*Th`UZ( literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/bc/114411903fd2afaa4bb9b85ed13f27e37ac375 b/tests/resources/merge-resolve/.gitted/objects/bc/114411903fd2afaa4bb9b85ed13f27e37ac375 new file mode 100644 index 0000000000000000000000000000000000000000..08941ff9538a4fea381f49ebd80332d417954c84 GIT binary patch literal 74 zcmV-Q0JZ;k0V^p=O;s>6VlXr?Ff%bxNXpM=csBRZ>`fQ1IeT|&t}Bnaap*};@I{Mj?>7TXPTRj!_En9m}MYsJK0M57_@mw7s{r~^~ literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/c0/d1f321977d1c18e23a28c581fed6d17d0cc013 b/tests/resources/merge-resolve/.gitted/objects/c0/d1f321977d1c18e23a28c581fed6d17d0cc013 deleted file mode 100644 index 4c20a212ade60c6f8046f0f5384bb06e145ce014..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 273 zcmV+s0q*{I0V^p=O;s>9vt%$dFfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRUTV2+ zYHmSErLLhVSnad9k7jSWc+J_nTXS7`)Qv+=dV(iH)fT1Z=9ghO{Ql!l+N8 zkTGc6^*G~R_FYU3NDhy&&R8ygh_N7J5=Yr3_6e($P%su?1|;*!D$i~?K&(uV5($wnQkS}f6h@CV zaLwRG2*M`6`@N~XsN9-NRjNr)yB(hsT0JG@ww#&ae Rrt9>X@?(d7Fh7HwP+9wjOc4M8 diff --git a/tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 b/tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 deleted file mode 100644 index 848f341c929..00000000000 --- a/tests/resources/merge-resolve/.gitted/objects/c5/be2acabac675af81df8bb70400235af2a9c225 +++ /dev/null @@ -1,4 +0,0 @@ -xAj1 @Ѭ} -CyFc(%,g2qno G->_o1P3 -ȒT -Qb*{}xJ@9SBܰ$I)/L 㟱v_n[Ժ`Z_prIC̄@=y;ݎn|;x*wY'IS \ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/objects/cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 b/tests/resources/merge-resolve/.gitted/objects/cd/d1cd02dbd164e9d18a644515bc2ca6551f13b4 deleted file mode 100644 index d2385b8f2353863209a288ba2cd3edc4ef04cfad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 280 zcmV+z0q6dB0V^p=O;s>9H)k+3FfcPQQAo_oFUd$P(#=aP*GO{^L*D ztK{>~g}6_UF=*TMIOAUST}%x~j)}3(ST29$SFD--<@UH>;hLAL e6Cd*RtT#<_EJ?4M_+j;{3r}q3#R3319++g`S&~%% diff --git a/tests/resources/merge-resolve/.gitted/objects/cd/edf9760406dc79e0c6a8899ce9f180ec2a23a0 b/tests/resources/merge-resolve/.gitted/objects/cd/edf9760406dc79e0c6a8899ce9f180ec2a23a0 new file mode 100644 index 00000000000..011b5b3e58c --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/objects/cd/edf9760406dc79e0c6a8899ce9f180ec2a23a0 @@ -0,0 +1,2 @@ +xA +B1C] "n)B[U R^Mo3c:d chCi2FGkKzŖ:ײ<ǝ[Ҏj9 zB0X!58猒E;4~*uQo$D \ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/objects/de/06afe070b65f94d7d791c39a6d389c58dda60d b/tests/resources/merge-resolve/.gitted/objects/de/06afe070b65f94d7d791c39a6d389c58dda60d new file mode 100644 index 0000000000000000000000000000000000000000..28567b624d1d3579d581e99f2fb49ea86add007c GIT binary patch literal 75 zcmV-R0JQ&j0V^p=O;s>6VlXr?Ff%bxNJ=bXNZ6?T=+f89@^j5M?qAkZp0Y-I;UcJX hT7EvmQ!dY+p}m|}F7H3cVP?I_N2u;nG61#K9B#?!BSruK literal 0 HcmV?d00001 diff --git a/tests/resources/merge-resolve/.gitted/objects/e5/0a49f9558d09d4d3bfc108363bb24c127ed263 b/tests/resources/merge-resolve/.gitted/objects/e5/0a49f9558d09d4d3bfc108363bb24c127ed263 new file mode 100644 index 0000000000000000000000000000000000000000..251c5dfb20c2b73cf789ff29345c8faa2ee433cc GIT binary patch literal 20 bcmbZ;uB[JrN9z)Vb!.Rj +: +$ŘK:!c \˃Fキ[?Kby{; pA-wS[_i{WOGR \ No newline at end of file diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames b/tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames new file mode 100644 index 00000000000..89b4eea8ff5 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames @@ -0,0 +1 @@ +ea789495e0a72efadcd0f86a48f4c9ed435bb8a3 diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames-branch b/tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames-branch new file mode 100644 index 00000000000..1c6a9f4db55 --- /dev/null +++ b/tests/resources/merge-resolve/.gitted/refs/heads/emptyfile_renames-branch @@ -0,0 +1 @@ +ab347abd8cda4a0e3b8bb42bb620c0c72c7df779 diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 b/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 deleted file mode 100644 index d6149eb8131..00000000000 --- a/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15 +++ /dev/null @@ -1 +0,0 @@ -c452c5eb5aacf204fc95a55d1eb9668736fecfb6 diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch b/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch deleted file mode 100644 index a255d1a3a95..00000000000 --- a/tests/resources/merge-resolve/.gitted/refs/heads/trivial-15-branch +++ /dev/null @@ -1 +0,0 @@ -c5be2acabac675af81df8bb70400235af2a9c225 From a204533ded1e30f79b50d1e681b9884043091c12 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 14:30:17 +0000 Subject: [PATCH 433/816] test: completely ignored diff is empty --- tests/libgit2/diff/workdir.c | 57 ++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/tests/libgit2/diff/workdir.c b/tests/libgit2/diff/workdir.c index c433b75cedc..504ece6fc91 100644 --- a/tests/libgit2/diff/workdir.c +++ b/tests/libgit2/diff/workdir.c @@ -2286,42 +2286,81 @@ void test_diff_workdir__to_index_reversed_content_loads(void) diff_expects exp; int use_iterator; char *pathspec = "new_file"; - + g_repo = cl_git_sandbox_init("status"); - + opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_SHOW_UNTRACKED_CONTENT | GIT_DIFF_REVERSE; opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; - + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); - + for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); - + if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); - + cl_assert_equal_i(1, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); - + cl_assert_equal_i(1, exp.hunks); - + cl_assert_equal_i(1, exp.lines); cl_assert_equal_i(0, exp.line_ctxt); cl_assert_equal_i(0, exp.line_adds); cl_assert_equal_i(1, exp.line_dels); } - + + git_diff_free(diff); +} + +void test_diff_workdir__completely_ignored_shows_empty_diff(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff; + git_patch *patch; + git_buf buf = GIT_BUF_INIT; + char *pathspec = "subdir.txt"; + + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + g_repo = cl_git_sandbox_init("status"); + cl_git_rewritefile("status/subdir.txt", "Is it a bird?\n\nIs it a plane?\n"); + + /* Perform the diff normally */ + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_pass(git_patch_from_diff(&patch, diff, 0)); + cl_git_pass(git_patch_to_buf(&buf, patch)); + + cl_assert_equal_s("diff --git a/subdir.txt b/subdir.txt\nindex e8ee89e..53c8db5 100644\n--- a/subdir.txt\n+++ b/subdir.txt\n@@ -1,2 +1,3 @@\n Is it a bird?\n+\n Is it a plane?\n", buf.ptr); + + git_buf_dispose(&buf); + git_patch_free(patch); + git_diff_free(diff); + + /* Perform the diff ignoring blank lines */ + opts.flags |= GIT_DIFF_IGNORE_BLANK_LINES; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_pass(git_patch_from_diff(&patch, diff, 0)); + cl_git_pass(git_patch_to_buf(&buf, patch)); + + cl_assert_equal_s("", buf.ptr); + + git_buf_dispose(&buf); + git_patch_free(patch); git_diff_free(diff); } From d704046712a762a79689c00767ef7602e86d630f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 20 Feb 2024 14:30:26 +0000 Subject: [PATCH 434/816] diff: don't print header for empty (fully ignored) diff When a diff has no content -- for example, when there are only whitespace changes, and they're being ignored -- we need to avoid printing the file header. Queue the file header update until the first hunk is printed, and display it then. --- src/libgit2/diff_print.c | 51 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/libgit2/diff_print.c b/src/libgit2/diff_print.c index 32c93682679..daeefca50ca 100644 --- a/src/libgit2/diff_print.c +++ b/src/libgit2/diff_print.c @@ -29,6 +29,7 @@ typedef struct { const char *new_prefix; uint32_t flags; int id_strlen; + unsigned int sent_file_header; git_oid_t oid_type; int (*strcomp)(const char *, const char *); @@ -579,6 +580,30 @@ static int diff_print_patch_file_binary( return error; } +GIT_INLINE(int) should_force_header(const git_diff_delta *delta) +{ + if (delta->old_file.mode != delta->new_file.mode) + return 1; + + if (delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED) + return 1; + + return 0; +} + +GIT_INLINE(int) flush_file_header(const git_diff_delta *delta, diff_print_info *pi) +{ + if (pi->sent_file_header) + return 0; + + pi->line.origin = GIT_DIFF_LINE_FILE_HDR; + pi->line.content = git_str_cstr(pi->buf); + pi->line.content_len = git_str_len(pi->buf); + pi->sent_file_header = 1; + + return pi->print_cb(delta, NULL, &pi->line, pi->payload); +} + static int diff_print_patch_file( const git_diff_delta *delta, float progress, void *data) { @@ -609,15 +634,22 @@ static int diff_print_patch_file( (pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0)) return 0; + pi->sent_file_header = 0; + if ((error = git_diff_delta__format_file_header(pi->buf, delta, oldpfx, newpfx, id_strlen, print_index)) < 0) return error; - pi->line.origin = GIT_DIFF_LINE_FILE_HDR; - pi->line.content = git_str_cstr(pi->buf); - pi->line.content_len = git_str_len(pi->buf); + /* + * pi->buf now contains the file header data. Go ahead and send it + * if there's useful data in there, like similarity. Otherwise, we + * should queue it to send when we see the first hunk. This prevents + * us from sending a header when all hunks were ignored. + */ + if (should_force_header(delta) && (error = flush_file_header(delta, pi)) < 0) + return error; - return pi->print_cb(delta, NULL, &pi->line, pi->payload); + return 0; } static int diff_print_patch_binary( @@ -632,6 +664,9 @@ static int diff_print_patch_binary( pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT; int error; + if ((error = flush_file_header(delta, pi)) < 0) + return error; + git_str_clear(pi->buf); if ((error = diff_print_patch_file_binary( @@ -651,10 +686,14 @@ static int diff_print_patch_hunk( void *data) { diff_print_info *pi = data; + int error; if (S_ISDIR(d->new_file.mode)) return 0; + if ((error = flush_file_header(d, pi)) < 0) + return error; + pi->line.origin = GIT_DIFF_LINE_HUNK_HDR; pi->line.content = h->header; pi->line.content_len = h->header_len; @@ -669,10 +708,14 @@ static int diff_print_patch_line( void *data) { diff_print_info *pi = data; + int error; if (S_ISDIR(delta->new_file.mode)) return 0; + if ((error = flush_file_header(delta, pi)) < 0) + return error; + return pi->print_cb(delta, hunk, line, pi->payload); } From aa31120f7c131cbe79f0f95b9bd5e745792ae47d Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sun, 6 Feb 2022 07:22:59 -0600 Subject: [PATCH 435/816] config: introduce GIT_CONFIG_LEVEL_WORKTREE Introduce the logical concept of a worktree-level config. The new value sits between _LOCAL and _APP to allow `git_config_get_*` to 'just work'. The assumption of how `git_config_get_*` works was tested experimentally by setting _WORKTREE to some nonsense value (like -3) and watching the new test fail. --- include/git2/config.h | 6 +++++- tests/libgit2/config/configlevel.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/git2/config.h b/include/git2/config.h index 332e62036d0..63293dbdaec 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -48,9 +48,13 @@ typedef enum { */ GIT_CONFIG_LEVEL_LOCAL = 5, + /** Worktree specific configuration file; $GIT_DIR/config.worktree + */ + GIT_CONFIG_LEVEL_WORKTREE = 6, + /** Application specific configuration file; freely defined by applications */ - GIT_CONFIG_LEVEL_APP = 6, + GIT_CONFIG_LEVEL_APP = 7, /** Represents the highest level available config file (i.e. the most * specific config file available that actually is loaded) diff --git a/tests/libgit2/config/configlevel.c b/tests/libgit2/config/configlevel.c index 8422d32c944..3534fbc2c84 100644 --- a/tests/libgit2/config/configlevel.c +++ b/tests/libgit2/config/configlevel.c @@ -71,3 +71,21 @@ void test_config_configlevel__fetching_a_level_from_an_empty_compound_config_ret git_config_free(cfg); } + +void test_config_configlevel__can_override_local_with_worktree(void) +{ + git_config *cfg; + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_config_new(&cfg)); + cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), + GIT_CONFIG_LEVEL_WORKTREE, NULL, 1)); + cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), + GIT_CONFIG_LEVEL_LOCAL, NULL, 1)); + + cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.stringglobal")); + cl_assert_equal_s("don't find me!", buf.ptr); + + git_buf_dispose(&buf); + git_config_free(cfg); +} From c4df10285edc3bab45cd779293800e7ec19d9bb0 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sun, 6 Feb 2022 09:26:41 -0600 Subject: [PATCH 436/816] config: load worktree config from disk Now that GIT_CONFIG_LEVEL_WORKTREE exists logically, define and load $GIT_DIR/config.worktree into that level. --- include/git2/repository.h | 1 + src/libgit2/repository.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/git2/repository.h b/include/git2/repository.h index 0ff0856510f..9ad6176f940 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -499,6 +499,7 @@ typedef enum { GIT_REPOSITORY_ITEM_PACKED_REFS, GIT_REPOSITORY_ITEM_REMOTES, GIT_REPOSITORY_ITEM_CONFIG, + GIT_REPOSITORY_ITEM_WORKTREE_CONFIG, GIT_REPOSITORY_ITEM_INFO, GIT_REPOSITORY_ITEM_HOOKS, GIT_REPOSITORY_ITEM_LOGS, diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 4eb3449133b..2859bd4800b 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -58,6 +58,7 @@ static const struct { { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "packed-refs", false }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "remotes", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config", false }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config.worktree", false }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "info", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "hooks", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "logs", true }, @@ -1291,6 +1292,12 @@ static int load_config( return error; if (repo) { + if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_WORKTREE_CONFIG)) == 0) + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_WORKTREE, repo, 0); + + if (error && error != GIT_ENOTFOUND) + goto on_error; + if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); From 5a86dfc17298bb80ff0dabe95f8e9fbdd6ad6e7c Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sun, 6 Feb 2022 10:00:40 -0600 Subject: [PATCH 437/816] repository: support the 'worktreeConfig' extension Now that worktree-level configuration can be read from disk and manipulated in memory, we should be able to say we support 'extensions.worktreeConfig'. --- src/libgit2/repository.c | 3 ++- tests/libgit2/core/opts.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 2859bd4800b..be938b5b9d0 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1852,7 +1852,8 @@ static int check_repositoryformatversion(int *version, git_config *config) static const char *builtin_extensions[] = { "noop", - "objectformat" + "objectformat", + "worktreeconfig", }; static git_vector user_extensions = { 0, git__strcmp_cb }; diff --git a/tests/libgit2/core/opts.c b/tests/libgit2/core/opts.c index 1aa095adf4c..cbef29f991d 100644 --- a/tests/libgit2/core/opts.c +++ b/tests/libgit2/core/opts.c @@ -34,9 +34,10 @@ void test_core_opts__extensions_query(void) cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 2); + cl_assert_equal_sz(out.count, 3); cl_assert_equal_s("noop", out.strings[0]); cl_assert_equal_s("objectformat", out.strings[1]); + cl_assert_equal_s("worktreeconfig", out.strings[2]); git_strarray_dispose(&out); } @@ -49,10 +50,11 @@ void test_core_opts__extensions_add(void) cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 3); + cl_assert_equal_sz(out.count, 4); cl_assert_equal_s("foo", out.strings[0]); cl_assert_equal_s("noop", out.strings[1]); cl_assert_equal_s("objectformat", out.strings[2]); + cl_assert_equal_s("worktreeconfig", out.strings[3]); git_strarray_dispose(&out); } @@ -65,10 +67,11 @@ void test_core_opts__extensions_remove(void) cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 3); + cl_assert_equal_sz(out.count, 4); cl_assert_equal_s("bar", out.strings[0]); cl_assert_equal_s("baz", out.strings[1]); cl_assert_equal_s("objectformat", out.strings[2]); + cl_assert_equal_s("worktreeconfig", out.strings[3]); git_strarray_dispose(&out); } @@ -81,11 +84,12 @@ void test_core_opts__extensions_uniq(void) cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 4); + cl_assert_equal_sz(out.count, 5); cl_assert_equal_s("bar", out.strings[0]); cl_assert_equal_s("foo", out.strings[1]); cl_assert_equal_s("noop", out.strings[2]); cl_assert_equal_s("objectformat", out.strings[3]); + cl_assert_equal_s("worktreeconfig", out.strings[4]); git_strarray_dispose(&out); } From 42e7e681de2dbd37b0b1018fc78a0e3a7ff1cf68 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Tue, 20 Feb 2024 21:38:52 -0600 Subject: [PATCH 438/816] config: refactor get_backend_for_use This structure provides for cleaner diffs in upcoming commits. --- src/libgit2/config.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 04f3ec2fee2..e67839c3622 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -594,6 +594,7 @@ static int get_backend_for_use(git_config_backend **out, { size_t i; backend_internal *backend; + int error = 0; *out = NULL; @@ -605,16 +606,20 @@ static int get_backend_for_use(git_config_backend **out, } git_vector_foreach(&cfg->backends, i, backend) { - if (!backend->backend->readonly) { - *out = backend->backend; - return 0; - } + if (backend->backend->readonly) + continue; + + *out = backend->backend; + goto cleanup; } + error = GIT_ENOTFOUND; git_error_set(GIT_ERROR_CONFIG, "cannot %s value for '%s' when all config backends are readonly", uses[use], name); - return GIT_ENOTFOUND; + + cleanup: + return error; } int git_config_delete_entry(git_config *cfg, const char *name) From ea66ab07738642a3d7dae6d249a92f5fd1ff3e89 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Tue, 20 Feb 2024 21:39:11 -0600 Subject: [PATCH 439/816] config: skip worktree config in get_backend_for_use It would seem that `get_backend_for_use` is primarily used when writing config data -- either to set keys or delete them (based on the possible values of `backend_use`). When git-config(1) is used for side-effects, it will modify only the local (repository-level) configuration unless explicitly overridden. From git-config(1): --local For writing options: write to the repository .git/config file. This is the default behavior. `get_backend_for_use` does not have the ability to specify a config level and typically is expected (it seems) to 'do the right thing'. Taking its cue from git-config(1), don't update worktree-specific config unless it's the only option. If that functionality is needed by consumers, I assume they would find the appropriate backend with `git_config_open_level` and feed that `git_config` object through to the `git_config_set_*` functions (as demonstrated in the provided test). --- src/libgit2/config.c | 13 ++++++++++++- tests/libgit2/worktree/config.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index e67839c3622..732d10830ec 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -593,12 +593,14 @@ static int get_backend_for_use(git_config_backend **out, git_config *cfg, const char *name, backend_use use) { size_t i; + size_t len; backend_internal *backend; int error = 0; *out = NULL; - if (git_vector_length(&cfg->backends) == 0) { + len = git_vector_length(&cfg->backends); + if (len == 0) { git_error_set(GIT_ERROR_CONFIG, "cannot %s value for '%s' when no config backends exist", uses[use], name); @@ -609,6 +611,15 @@ static int get_backend_for_use(git_config_backend **out, if (backend->backend->readonly) continue; + /* git-config doesn't update worktree-level config + unless specifically requested; follow suit. If you + specifically want to update that level, open the + single config level with git_config_open_level and + provide that as the config. In this case, there + will only be one backend in the config. */ + if (len > 1 && backend->level == GIT_CONFIG_LEVEL_WORKTREE) + continue; + *out = backend->backend; goto cleanup; } diff --git a/tests/libgit2/worktree/config.c b/tests/libgit2/worktree/config.c index 81dcfe1fa51..c23cd044fba 100644 --- a/tests/libgit2/worktree/config.c +++ b/tests/libgit2/worktree/config.c @@ -27,7 +27,7 @@ void test_worktree_config__open(void) git_config_free(cfg); } -void test_worktree_config__set(void) +void test_worktree_config__set_level_local(void) { git_config *cfg; int32_t val; @@ -45,3 +45,31 @@ void test_worktree_config__set(void) cl_assert_equal_i(val, 5); git_config_free(cfg); } + +void test_worktree_config__set_level_worktree(void) +{ + git_config *cfg; + git_config *wtcfg; + int32_t val; + + cl_git_pass(git_repository_config(&cfg, fixture.repo)); + cl_git_pass(git_config_open_level(&wtcfg, cfg, GIT_CONFIG_LEVEL_WORKTREE)); + cl_git_pass(git_config_set_int32(wtcfg, "worktree.specific", 42)); + + cl_git_pass(git_config_get_int32(&val, cfg, "worktree.specific")); + cl_assert_equal_i(val, 42); + + /* reopen to verify config has been set */ + git_config_free(cfg); + cl_git_pass(git_repository_config(&cfg, fixture.repo)); + cl_git_pass(git_config_get_int32(&val, cfg, "worktree.specific")); + cl_assert_equal_i(val, 42); + + cl_assert(git_config_delete_entry(cfg, "worktree.specific") == GIT_ENOTFOUND); + + cl_git_pass(git_config_delete_entry(wtcfg, "worktree.specific")); + cl_assert(git_config_get_int32(&val, cfg, "worktree.specific") == GIT_ENOTFOUND); + + git_config_free(cfg); + git_config_free(wtcfg); +} From 9b21c428cfebdb5cd047d7fd6505d8c32e47f101 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Tue, 20 Feb 2024 21:46:07 -0600 Subject: [PATCH 440/816] config: return only backends that contain the key When deleting a key from a repository with multiple config backends (like a --local config and a --worktree config), it's important to return the correct backend to modify. This patch ensures that we don't return a backend that is incapable of deleting a given piece of configuration when that is the required use. --- src/libgit2/config.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 732d10830ec..6d3cd9836d3 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -596,6 +596,7 @@ static int get_backend_for_use(git_config_backend **out, size_t len; backend_internal *backend; int error = 0; + git_config_entry *entry = NULL; *out = NULL; @@ -620,6 +621,15 @@ static int get_backend_for_use(git_config_backend **out, if (len > 1 && backend->level == GIT_CONFIG_LEVEL_WORKTREE) continue; + /* If we're trying to delete a piece of config, make + sure the backend we return actually defines it in + the first place. */ + if (use == BACKEND_USE_DELETE) { + if (backend->backend->get(backend->backend, name, &entry) < 0) + continue; + git_config_entry_free(entry); + } + *out = backend->backend; goto cleanup; } From 498f443379f3fb248bb20c9ae6dce0f956dea327 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Tue, 20 Feb 2024 21:46:16 -0600 Subject: [PATCH 441/816] config: normalize key name in get_backend_for_use Before passing the config key name to backend->get(), it needs to be normalized first. Not all current callers are performing this normalization, so perform it centrally instead. Co-authored-by: Brian Lyles --- src/libgit2/config.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 6d3cd9836d3..6994a8e2736 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -597,6 +597,7 @@ static int get_backend_for_use(git_config_backend **out, backend_internal *backend; int error = 0; git_config_entry *entry = NULL; + char *key = NULL; *out = NULL; @@ -625,7 +626,9 @@ static int get_backend_for_use(git_config_backend **out, sure the backend we return actually defines it in the first place. */ if (use == BACKEND_USE_DELETE) { - if (backend->backend->get(backend->backend, name, &entry) < 0) + if (key == NULL && (error = git_config__normalize_name(name, &key)) < 0) + goto cleanup; + if (backend->backend->get(backend->backend, key, &entry) < 0) continue; git_config_entry_free(entry); } @@ -640,6 +643,7 @@ static int get_backend_for_use(git_config_backend **out, uses[use], name); cleanup: + git__free(key); return error; } From 47f3953111a94bcd11b9798989bc702eda2cdb44 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Wed, 21 Feb 2024 13:51:36 -0600 Subject: [PATCH 442/816] config: use appropriate backend_use value This looks like a simple copy/paste error. --- src/libgit2/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 6994a8e2736..908bf8d390a 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -1126,7 +1126,7 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex { git_config_backend *backend; - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) + if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET) < 0) return GIT_ENOTFOUND; return backend->set_multivar(backend, name, regexp, value); From 4cd2d1798ce2af4bff7ce8a76b6e97d702183567 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Tue, 20 Feb 2024 21:34:29 -0600 Subject: [PATCH 443/816] config: propagate errors from get_backend_for_use Now that get_backend_for_use can return other error codes (by virtue of key-name normalization), make sure to propagate the appropriate error code when used. --- src/libgit2/config.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 908bf8d390a..d3193c95e26 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -650,9 +650,10 @@ static int get_backend_for_use(git_config_backend **out, int git_config_delete_entry(git_config *cfg, const char *name) { git_config_backend *backend; + int error = 0; - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) - return GIT_ENOTFOUND; + if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE)) < 0) + return error; return backend->del(backend, name); } @@ -684,8 +685,8 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) return -1; } - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET) < 0) - return GIT_ENOTFOUND; + if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET)) < 0) + return error; error = backend->set(backend, name, value); @@ -1125,9 +1126,10 @@ int git_config_multivar_iterator_new(git_config_iterator **out, const git_config int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) { git_config_backend *backend; + int error = 0; - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET) < 0) - return GIT_ENOTFOUND; + if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET)) < 0) + return error; return backend->set_multivar(backend, name, regexp, value); } @@ -1135,9 +1137,10 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex int git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp) { git_config_backend *backend; + int error = 0; - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) - return GIT_ENOTFOUND; + if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE)) < 0) + return error; return backend->del_multivar(backend, name, regexp); } From 88608a5e9e4c0a617bac158e762b058e16b9b600 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 22 Feb 2024 14:06:06 +0000 Subject: [PATCH 444/816] worktree: update worktree refs test Ensure that we test for the expected error code (GIT_ENOTFOUND) on not found refs. In addition, we don't need to handle the error case with an explicit free; it's okay to leak memory on test failures. --- tests/libgit2/worktree/refs.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/tests/libgit2/worktree/refs.c b/tests/libgit2/worktree/refs.c index 6bcf7aa9dac..51e7b2b9463 100644 --- a/tests/libgit2/worktree/refs.c +++ b/tests/libgit2/worktree/refs.c @@ -69,23 +69,19 @@ void test_worktree_refs__list_worktree_specific(void) git_oid oid; cl_git_pass(git_reference_name_to_id(&oid, fixture.repo, "refs/heads/dir")); - cl_git_fail(git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref")); + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref")); cl_git_pass(git_reference_create( &new_branch, fixture.worktree, "refs/bisect/a-bisect-ref", &oid, 0, "test")); - cl_git_fail(git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref")); + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref")); cl_git_pass(git_reference_lookup(&ref, fixture.worktree, "refs/bisect/a-bisect-ref")); cl_git_pass(git_reference_list(&refs, fixture.repo)); cl_git_pass(git_reference_list(&wtrefs, fixture.worktree)); - if (refs.count + 1 != wtrefs.count) { - error = GIT_ERROR; - goto exit; - } + cl_assert_equal_sz(wtrefs.count, refs.count + 1); -exit: git_reference_free(ref); git_reference_free(new_branch); git_strarray_dispose(&refs); @@ -102,13 +98,13 @@ void test_worktree_refs__list_worktree_specific_hidden_in_main_repo(void) cl_git_pass( git_reference_name_to_id(&oid, fixture.repo, "refs/heads/dir")); - cl_git_fail(git_reference_lookup( + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup( &ref, fixture.worktree, "refs/bisect/a-bisect-ref")); cl_git_pass(git_reference_create( &new_branch, fixture.repo, "refs/bisect/a-bisect-ref", &oid, 0, "test")); - cl_git_fail(git_reference_lookup( + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup( &ref, fixture.worktree, "refs/bisect/a-bisect-ref")); cl_git_pass(git_reference_lookup( &ref, fixture.repo, "refs/bisect/a-bisect-ref")); @@ -116,12 +112,8 @@ void test_worktree_refs__list_worktree_specific_hidden_in_main_repo(void) cl_git_pass(git_reference_list(&refs, fixture.repo)); cl_git_pass(git_reference_list(&wtrefs, fixture.worktree)); - if (refs.count != wtrefs.count + 1) { - error = GIT_ERROR; - goto exit; - } + cl_assert_equal_sz(refs.count, wtrefs.count + 1); -exit: git_reference_free(ref); git_reference_free(new_branch); git_strarray_dispose(&refs); From bd242a05e29d74e44e5a5d98ff6023c0f0a4750e Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 24 Feb 2024 14:33:26 +0100 Subject: [PATCH 445/816] Fix broken links Signed-off-by: Sven Strickroth --- README.md | 2 +- examples/general.c | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 19fe7196976..f646feb197c 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Getting Help **Getting Help** If you have questions about the library, please be sure to check out the -[API documentation](http://libgit2.github.com/libgit2/). If you still have +[API documentation](http://libgit2.github.io/libgit2/). If you still have questions, reach out to us on Slack or post a question on [StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) (with the `libgit2` tag). diff --git a/examples/general.c b/examples/general.c index 7f44cd78680..a3767809230 100644 --- a/examples/general.c +++ b/examples/general.c @@ -32,7 +32,7 @@ * check out [Chapter 10][pg] of the Pro Git book. * * [lg]: http://libgit2.github.com - * [ap]: http://libgit2.github.com/libgit2 + * [ap]: http://libgit2.github.io/libgit2 * [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain */ @@ -97,7 +97,7 @@ int lg2_general(git_repository *repo, int argc, char** argv) * * (Try running this program against tests/resources/testrepo.git.) * - * [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository + * [me]: http://libgit2.github.io/libgit2/#HEAD/group/repository */ repo_path = (argc > 1) ? argv[1] : "/opt/libgit2-test/.git"; @@ -173,7 +173,7 @@ static void oid_parsing(git_oid *oid) * working with raw objects, we'll need to get this structure from the * repository. * - * [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb + * [odb]: http://libgit2.github.io/libgit2/#HEAD/group/odb */ static void object_database(git_repository *repo, git_oid *oid) { @@ -262,7 +262,7 @@ static void object_database(git_repository *repo, git_oid *oid) * of them here. You can read about the other ones in the [commit API * docs][cd]. * - * [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit + * [cd]: http://libgit2.github.io/libgit2/#HEAD/group/commit */ static void commit_writing(git_repository *repo) { @@ -347,7 +347,7 @@ static void commit_writing(git_repository *repo) * data in the commit - the author (name, email, datetime), committer * (same), tree, message, encoding and parent(s). * - * [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit + * [pco]: http://libgit2.github.io/libgit2/#HEAD/group/commit */ static void commit_parsing(git_repository *repo) { @@ -418,7 +418,7 @@ static void commit_parsing(git_repository *repo) * functions very similarly to the commit lookup, parsing and creation * methods, since the objects themselves are very similar. * - * [tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag + * [tm]: http://libgit2.github.io/libgit2/#HEAD/group/tag */ static void tag_parsing(git_repository *repo) { @@ -472,7 +472,7 @@ static void tag_parsing(git_repository *repo) * object type in Git, but a useful structure for parsing and traversing * tree entries. * - * [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree + * [tp]: http://libgit2.github.io/libgit2/#HEAD/group/tree */ static void tree_parsing(git_repository *repo) { @@ -536,7 +536,7 @@ static void tree_parsing(git_repository *repo) * from disk and writing it to the db and getting the oid back so you * don't have to do all those steps yourself. * - * [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob + * [ba]: http://libgit2.github.io/libgit2/#HEAD/group/blob */ static void blob_parsing(git_repository *repo) { @@ -578,7 +578,7 @@ static void blob_parsing(git_repository *repo) * that were ancestors of (reachable from) a given starting point. This * can allow you to create `git log` type functionality. * - * [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk + * [rw]: http://libgit2.github.io/libgit2/#HEAD/group/revwalk */ static void revwalking(git_repository *repo) { @@ -643,7 +643,7 @@ static void revwalking(git_repository *repo) * The [index file API][gi] allows you to read, traverse, update and write * the Git index file (sometimes thought of as the staging area). * - * [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index + * [gi]: http://libgit2.github.io/libgit2/#HEAD/group/index */ static void index_walking(git_repository *repo) { @@ -687,7 +687,7 @@ static void index_walking(git_repository *repo) * references such as branches, tags and remote references (everything in * the .git/refs directory). * - * [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference + * [ref]: http://libgit2.github.io/libgit2/#HEAD/group/reference */ static void reference_listing(git_repository *repo) { @@ -740,7 +740,7 @@ static void reference_listing(git_repository *repo) * The [config API][config] allows you to list and update config values * in any of the accessible config file locations (system, global, local). * - * [config]: http://libgit2.github.com/libgit2/#HEAD/group/config + * [config]: http://libgit2.github.io/libgit2/#HEAD/group/config */ static void config_files(const char *repo_path, git_repository* repo) { From f9e055468d167cb4d6bde1ecd9e293d8a7d40db5 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 24 Feb 2024 14:47:40 +0100 Subject: [PATCH 446/816] Fix memory leaks Signed-off-by: Sven Strickroth --- src/libgit2/repository.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 4eb3449133b..ba182eea4bb 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3246,14 +3246,18 @@ int git_repository_set_workdir( if (git_fs_path_prettify_dir(&path, workdir, NULL) < 0) return -1; - if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) + if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) { + git_str_dispose(&path); return 0; + } if (update_gitlink) { git_config *config; - if (git_repository_config__weakptr(&config, repo) < 0) + if (git_repository_config__weakptr(&config, repo) < 0) { + git_str_dispose(&path); return -1; + } error = repo_write_gitlink(path.ptr, git_repository_path(repo), false); @@ -3275,6 +3279,7 @@ int git_repository_set_workdir( git__free(old_workdir); } + git_str_dispose(&path); return error; } From 2f6c4f75e374e08e5e1e2de294b77cc5cd7de232 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 24 Feb 2024 15:18:42 +0100 Subject: [PATCH 447/816] Fix broken regexp that matches submodule names containing ".path" Signed-off-by: Sven Strickroth --- src/libgit2/submodule.c | 4 ++-- tests/libgit2/submodule/lookup.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/libgit2/submodule.c b/src/libgit2/submodule.c index 95ea84fc233..830d41c7d22 100644 --- a/src/libgit2/submodule.c +++ b/src/libgit2/submodule.c @@ -196,7 +196,7 @@ static void free_submodule_names(git_strmap *names) */ static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg) { - const char *key = "submodule\\..*\\.path"; + const char *key = "^submodule\\..*\\.path$"; git_config_iterator *iter = NULL; git_config_entry *entry; git_str buf = GIT_STR_INIT; @@ -332,7 +332,7 @@ int git_submodule__lookup_with_cache( /* If it's not configured or we're looking by path */ if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) { git_config_backend *mods; - const char *pattern = "submodule\\..*\\.path"; + const char *pattern = "^submodule\\..*\\.path$"; git_str path = GIT_STR_INIT; fbp_data data = { NULL, NULL }; diff --git a/tests/libgit2/submodule/lookup.c b/tests/libgit2/submodule/lookup.c index febb7dfad7d..14a624badef 100644 --- a/tests/libgit2/submodule/lookup.c +++ b/tests/libgit2/submodule/lookup.c @@ -401,6 +401,24 @@ void test_submodule_lookup__prefix_name(void) git_submodule_free(sm); } +/* ".path" in name of submodule */ +void test_submodule_lookup__dotpath_in_name(void) +{ + sm_lookup_data data; + + cl_git_rewritefile( + "submod2/.gitmodules", "[submodule \"kwb.pathdict\"]\n" + " path = kwb.pathdict\n" + " url = ../Test_App\n" + "[submodule \"fakin.path.app\"]\n" + " path = fakin.path.app\n" + " url = ../Test_App\n"); + + memset(&data, 0, sizeof(data)); + cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data)); + cl_assert_equal_i(9, data.count); +} + void test_submodule_lookup__renamed(void) { const char *newpath = "sm_actually_changed"; From cc35d987b412878b6f944243658fce88e845ec94 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 29 Feb 2024 18:25:24 +0000 Subject: [PATCH 448/816] ci: drop debugging ls --- ci/test.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index 4217568226a..5f6b3c31d23 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -207,7 +207,6 @@ if should_run "SSH_TESTS"; then echo "Starting SSH server..." SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX` cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${SSHD_DIR}/test.git" - ls -FlasR "${SSHD_DIR}" cat >"${SSHD_DIR}/sshd_config" <<-EOF Port 2222 From 1a3d6a889323f26acd2c572466356f9591f3147c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 29 Feb 2024 18:24:38 +0000 Subject: [PATCH 449/816] ci: allow opting out of push-options tests The push-options online tests require push options support in the git itself that's on the system. Allow callers with old git to opt out. --- .github/actions/run-build/action.yml | 1 + ci/test.sh | 15 +++++---------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/actions/run-build/action.yml b/.github/actions/run-build/action.yml index bd0f59c9a88..9afcfb11e72 100644 --- a/.github/actions/run-build/action.yml +++ b/.github/actions/run-build/action.yml @@ -40,6 +40,7 @@ runs: -e PKG_CONFIG_PATH \ -e SKIP_NEGOTIATE_TESTS \ -e SKIP_SSH_TESTS \ + -e SKIP_PUSHOPTIONS_TESTS \ -e TSAN_OPTIONS \ -e UBSAN_OPTIONS \ ${{ inputs.container-version }} \ diff --git a/ci/test.sh b/ci/test.sh index 5f6b3c31d23..98093c6ec5c 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -18,6 +18,11 @@ if [[ "$(uname -s)" == MINGW* ]]; then SKIP_NTLM_TESTS=1 fi +# older versions of git don't support push options +if [ -z "$SKIP_PUSHOPTIONS_TESTS" ]; then + export GITTEST_PUSH_OPTIONS=true +fi + SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )} BUILD_DIR=$(pwd) BUILD_PATH=${BUILD_PATH:=$PATH} @@ -324,10 +329,8 @@ if should_run "GITDAEMON_TESTS"; then echo "" export GITTEST_REMOTE_URL="git://localhost/test.git" - export GITTEST_PUSH_OPTIONS=true run_test gitdaemon unset GITTEST_REMOTE_URL - unset GITTEST_PUSH_OPTIONS echo "" echo "Running gitdaemon (namespace) tests" @@ -382,12 +385,10 @@ if should_run "NTLM_TESTS"; then export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" - export GITTEST_PUSH_OPTIONS=true run_test auth_clone_and_push unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS - unset GITTEST_PUSH_OPTIONS echo "" echo "Running NTLM tests (Apache emulation)" @@ -396,12 +397,10 @@ if should_run "NTLM_TESTS"; then export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" - export GITTEST_PUSH_OPTIONS=true run_test auth_clone_and_push unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS - unset GITTEST_PUSH_OPTIONS fi if should_run "NEGOTIATE_TESTS" && -n "$GITTEST_NEGOTIATE_PASSWORD" ; then @@ -451,20 +450,16 @@ if should_run "SSH_TESTS"; then echo "" export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git" - export GITTEST_PUSH_OPTIONS=true run_test ssh unset GITTEST_REMOTE_URL - unset GITTEST_PUSH_OPTIONS echo "" echo "Running ssh tests (scp-style paths)" echo "" export GITTEST_REMOTE_URL="[localhost:2222]:$SSHD_DIR/test.git" - export GITTEST_PUSH_OPTIONS=true run_test ssh unset GITTEST_REMOTE_URL - unset GITTEST_PUSH_OPTIONS unset GITTEST_SSH_CMD From 038f078d44e00df040cd2e24e038bce89253aa79 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 29 Feb 2024 21:16:56 +0000 Subject: [PATCH 450/816] ci: disable push options tests on older systems --- .github/workflows/nightly.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 43796859762..25249e7440d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -178,6 +178,7 @@ jobs: CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true - name: "Linux (CentOS 7, dynamically-loaded OpenSSL)" id: centos7-dynamicopenssl os: ubuntu-latest @@ -187,6 +188,7 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true - name: "Linux (CentOS 8, OpenSSL)" id: centos8-openssl os: ubuntu-latest @@ -218,6 +220,7 @@ jobs: CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (x86, Bionic, Clang, OpenSSL)" container: @@ -229,6 +232,7 @@ jobs: CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (x86, Bionic, GCC, OpenSSL)" container: @@ -239,6 +243,7 @@ jobs: CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (arm32, Bionic, GCC, OpenSSL)" container: @@ -251,6 +256,7 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true SKIP_PROXY_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true GITTEST_FLAKY_STAT: true os: ubuntu-latest - name: "Linux (arm64, Bionic, GCC, OpenSSL)" @@ -264,6 +270,7 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true SKIP_PROXY_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest # Nightly builds: ensure we fallback when missing core functionality @@ -276,6 +283,7 @@ jobs: CC: gcc CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja + SKIP_PUSHOPTIONS_TESTS: true - name: "Linux (no mmap)" id: noble-nommap os: ubuntu-latest From 6c7df67071d779208c3e5ca3155d01640c8e477b Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Fri, 1 Mar 2024 14:45:08 +0100 Subject: [PATCH 451/816] Consistently use libgit2.org Signed-off-by: Sven Strickroth --- README.md | 2 +- examples/README.md | 4 ++-- examples/general.c | 26 +++++++++++++------------- src/libgit2/git2.rc | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f646feb197c..f4dbc789154 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Getting Help **Getting Help** If you have questions about the library, please be sure to check out the -[API documentation](http://libgit2.github.io/libgit2/). If you still have +[API documentation](https://libgit2.org/libgit2/). If you still have questions, reach out to us on Slack or post a question on [StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) (with the `libgit2` tag). diff --git a/examples/README.md b/examples/README.md index 769c4b2678a..0f1f253877a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -15,8 +15,8 @@ so there are no restrictions on their use. For annotated HTML versions, see the "Examples" section of: - http://libgit2.github.com/libgit2 + https://libgit2.org/libgit2 such as: - http://libgit2.github.com/libgit2/ex/HEAD/general.html + https://libgit2.org/libgit2/ex/HEAD/general.html diff --git a/examples/general.c b/examples/general.c index a3767809230..0275f84a24e 100644 --- a/examples/general.c +++ b/examples/general.c @@ -31,8 +31,8 @@ * Git Internals that you will need to know to work with Git at this level, * check out [Chapter 10][pg] of the Pro Git book. * - * [lg]: http://libgit2.github.com - * [ap]: http://libgit2.github.io/libgit2 + * [lg]: https://libgit2.org + * [ap]: https://libgit2.org/libgit2 * [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain */ @@ -97,7 +97,7 @@ int lg2_general(git_repository *repo, int argc, char** argv) * * (Try running this program against tests/resources/testrepo.git.) * - * [me]: http://libgit2.github.io/libgit2/#HEAD/group/repository + * [me]: https://libgit2.org/libgit2/#HEAD/group/repository */ repo_path = (argc > 1) ? argv[1] : "/opt/libgit2-test/.git"; @@ -173,7 +173,7 @@ static void oid_parsing(git_oid *oid) * working with raw objects, we'll need to get this structure from the * repository. * - * [odb]: http://libgit2.github.io/libgit2/#HEAD/group/odb + * [odb]: https://libgit2.org/libgit2/#HEAD/group/odb */ static void object_database(git_repository *repo, git_oid *oid) { @@ -262,7 +262,7 @@ static void object_database(git_repository *repo, git_oid *oid) * of them here. You can read about the other ones in the [commit API * docs][cd]. * - * [cd]: http://libgit2.github.io/libgit2/#HEAD/group/commit + * [cd]: https://libgit2.org/libgit2/#HEAD/group/commit */ static void commit_writing(git_repository *repo) { @@ -347,7 +347,7 @@ static void commit_writing(git_repository *repo) * data in the commit - the author (name, email, datetime), committer * (same), tree, message, encoding and parent(s). * - * [pco]: http://libgit2.github.io/libgit2/#HEAD/group/commit + * [pco]: https://libgit2.org/libgit2/#HEAD/group/commit */ static void commit_parsing(git_repository *repo) { @@ -418,7 +418,7 @@ static void commit_parsing(git_repository *repo) * functions very similarly to the commit lookup, parsing and creation * methods, since the objects themselves are very similar. * - * [tm]: http://libgit2.github.io/libgit2/#HEAD/group/tag + * [tm]: https://libgit2.org/libgit2/#HEAD/group/tag */ static void tag_parsing(git_repository *repo) { @@ -472,7 +472,7 @@ static void tag_parsing(git_repository *repo) * object type in Git, but a useful structure for parsing and traversing * tree entries. * - * [tp]: http://libgit2.github.io/libgit2/#HEAD/group/tree + * [tp]: https://libgit2.org/libgit2/#HEAD/group/tree */ static void tree_parsing(git_repository *repo) { @@ -536,7 +536,7 @@ static void tree_parsing(git_repository *repo) * from disk and writing it to the db and getting the oid back so you * don't have to do all those steps yourself. * - * [ba]: http://libgit2.github.io/libgit2/#HEAD/group/blob + * [ba]: https://libgit2.org/libgit2/#HEAD/group/blob */ static void blob_parsing(git_repository *repo) { @@ -578,7 +578,7 @@ static void blob_parsing(git_repository *repo) * that were ancestors of (reachable from) a given starting point. This * can allow you to create `git log` type functionality. * - * [rw]: http://libgit2.github.io/libgit2/#HEAD/group/revwalk + * [rw]: https://libgit2.org/libgit2/#HEAD/group/revwalk */ static void revwalking(git_repository *repo) { @@ -643,7 +643,7 @@ static void revwalking(git_repository *repo) * The [index file API][gi] allows you to read, traverse, update and write * the Git index file (sometimes thought of as the staging area). * - * [gi]: http://libgit2.github.io/libgit2/#HEAD/group/index + * [gi]: https://libgit2.org/libgit2/#HEAD/group/index */ static void index_walking(git_repository *repo) { @@ -687,7 +687,7 @@ static void index_walking(git_repository *repo) * references such as branches, tags and remote references (everything in * the .git/refs directory). * - * [ref]: http://libgit2.github.io/libgit2/#HEAD/group/reference + * [ref]: https://libgit2.org/libgit2/#HEAD/group/reference */ static void reference_listing(git_repository *repo) { @@ -740,7 +740,7 @@ static void reference_listing(git_repository *repo) * The [config API][config] allows you to list and update config values * in any of the accessible config file locations (system, global, local). * - * [config]: http://libgit2.github.io/libgit2/#HEAD/group/config + * [config]: https://libgit2.org/libgit2/#HEAD/group/config */ static void config_files(const char *repo_path, git_repository* repo) { diff --git a/src/libgit2/git2.rc b/src/libgit2/git2.rc index d273afd7066..b94ecafd774 100644 --- a/src/libgit2/git2.rc +++ b/src/libgit2/git2.rc @@ -10,7 +10,7 @@ #endif #ifndef LIBGIT2_COMMENTS -# define LIBGIT2_COMMENTS "For more information visit http://libgit2.github.com/" +# define LIBGIT2_COMMENTS "For more information visit https://libgit2.org/" #endif #ifdef __GNUC__ From 70ab8216079469cc7a20443953dfa37b94e16671 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 2 Mar 2024 09:06:46 +0000 Subject: [PATCH 452/816] config: improve documentation for config levels --- include/git2/config.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/git2/config.h b/include/git2/config.h index 63293dbdaec..a711e1561dc 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -22,8 +22,15 @@ GIT_BEGIN_DECL /** * Priority level of a config file. + * * These priority levels correspond to the natural escalation logic - * (from higher to lower) when searching for config entries in git.git. + * (from higher to lower) when reading or searching for config entries + * in git.git. Meaning that for the same key, the configuration in + * the local configuration is preferred over the configuration in + * the system configuration file. + * + * Callers can add their own custom configuration, beginning at the + * `GIT_CONFIG_LEVEL_APP` level. * * git_config_open_default() and git_repository_config() honor those * priority levels as well. From 78f145366e3865ff6d20d9aecbbff57decaf773f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 2 Mar 2024 09:07:12 +0000 Subject: [PATCH 453/816] config: update tests to use `fail_with` `cl_git_fail_with` is preferred over asserting a return value; the former gives more detailed information about the mismatch. --- tests/libgit2/worktree/config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/libgit2/worktree/config.c b/tests/libgit2/worktree/config.c index c23cd044fba..2ddec25e264 100644 --- a/tests/libgit2/worktree/config.c +++ b/tests/libgit2/worktree/config.c @@ -65,10 +65,10 @@ void test_worktree_config__set_level_worktree(void) cl_git_pass(git_config_get_int32(&val, cfg, "worktree.specific")); cl_assert_equal_i(val, 42); - cl_assert(git_config_delete_entry(cfg, "worktree.specific") == GIT_ENOTFOUND); + cl_git_fail_with(GIT_ENOTFOUND, git_config_delete_entry(cfg, "worktree.specific")); cl_git_pass(git_config_delete_entry(wtcfg, "worktree.specific")); - cl_assert(git_config_get_int32(&val, cfg, "worktree.specific") == GIT_ENOTFOUND); + cl_git_fail_with(GIT_ENOTFOUND, git_config_get_int32(&val, cfg, "worktree.specific")); git_config_free(cfg); git_config_free(wtcfg); From 88b516713d7606c115d5253c535a4d556b899dde Mon Sep 17 00:00:00 2001 From: Laurence McGlashan Date: Mon, 4 Mar 2024 10:46:45 +0000 Subject: [PATCH 454/816] trace: Re-enable tests as tracing is now enabled by default --- tests/libgit2/trace/trace.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/libgit2/trace/trace.c b/tests/libgit2/trace/trace.c index 097208bffd6..9fea57668a2 100644 --- a/tests/libgit2/trace/trace.c +++ b/tests/libgit2/trace/trace.c @@ -32,16 +32,11 @@ void test_trace_trace__cleanup(void) void test_trace_trace__sets(void) { -#ifdef GIT_TRACE cl_assert(git_trace_level() == GIT_TRACE_INFO); -#else - cl_skip(); -#endif } void test_trace_trace__can_reset(void) { -#ifdef GIT_TRACE cl_assert(git_trace_level() == GIT_TRACE_INFO); cl_git_pass(git_trace_set(GIT_TRACE_ERROR, trace_callback)); @@ -51,14 +46,10 @@ void test_trace_trace__can_reset(void) git_trace(GIT_TRACE_ERROR, "Hello %s!", "world"); cl_assert(written == 1); -#else - cl_skip(); -#endif } void test_trace_trace__can_unset(void) { -#ifdef GIT_TRACE cl_assert(git_trace_level() == GIT_TRACE_INFO); cl_git_pass(git_trace_set(GIT_TRACE_NONE, NULL)); @@ -67,40 +58,25 @@ void test_trace_trace__can_unset(void) cl_assert(written == 0); git_trace(GIT_TRACE_FATAL, "Hello %s!", "world"); cl_assert(written == 0); -#else - cl_skip(); -#endif } void test_trace_trace__skips_higher_level(void) { -#ifdef GIT_TRACE cl_assert(written == 0); git_trace(GIT_TRACE_DEBUG, "Hello %s!", "world"); cl_assert(written == 0); -#else - cl_skip(); -#endif } void test_trace_trace__writes(void) { -#ifdef GIT_TRACE cl_assert(written == 0); git_trace(GIT_TRACE_INFO, "Hello %s!", "world"); cl_assert(written == 1); -#else - cl_skip(); -#endif } void test_trace_trace__writes_lower_level(void) { -#ifdef GIT_TRACE cl_assert(written == 0); git_trace(GIT_TRACE_ERROR, "Hello %s!", "world"); cl_assert(written == 1); -#else - cl_skip(); -#endif } From 885744a77e8a727dd725f6a5fa8d80c199668fb7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 5 Mar 2024 09:23:03 +0000 Subject: [PATCH 455/816] worktree: keep version number at 1 We aren't upgrading options struct version numbers when we make ABI changes. This is a future (v2.0+) plan for libgit2. In the meantime, keep the version numbers at 1. --- include/git2/worktree.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/git2/worktree.h b/include/git2/worktree.h index 3f1acbdb0ff..c41bc8e7bc1 100644 --- a/include/git2/worktree.h +++ b/include/git2/worktree.h @@ -86,11 +86,12 @@ typedef struct git_worktree_add_options { int lock; /**< lock newly created worktree */ int checkout_existing; /**< allow checkout of existing branch matching worktree name */ + git_reference *ref; /**< reference to use for the new worktree HEAD */ } git_worktree_add_options; -#define GIT_WORKTREE_ADD_OPTIONS_VERSION 2 -#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0,0,NULL} +#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1 +#define GIT_WORKTREE_ADD_OPTIONS_INIT { GIT_WORKTREE_ADD_OPTIONS_VERSION } /** * Initialize git_worktree_add_options structure From 7bbb07f83f36dbdad6b2fa0b45eb7a87a1a818f9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 8 Mar 2024 16:51:11 +0000 Subject: [PATCH 456/816] worktree: dry up the refdb_fs iterator The refdb iterator has grown a bit and has a few concerns intermixed. Refactor a bit to improve readability while trying to avoid unnecessary git_str allocations. --- src/libgit2/refdb_fs.c | 201 +++++++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 90 deletions(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 4628e01dc99..14368e34775 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -794,125 +794,146 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter) git__free(iter); } -static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) +struct iter_load_context { + refdb_fs_backend *backend; + refdb_fs_iter *iter; + + /* + * If we have a glob with a prefix (eg `refs/heads/ *`) then we can + * optimize our prefix to avoid walking refs that we know won't + * match. This is that prefix. + */ + const char *ref_prefix; + size_t ref_prefix_len; + + /* Temporary variables to avoid unnecessary allocations */ + git_str ref_name; + git_str path; +}; + +static void iter_load_optimize_prefix(struct iter_load_context *ctx) { - int error = 0; - git_str path = GIT_STR_INIT; - git_iterator *fsit = NULL; - git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT; - const git_index_entry *entry = NULL; - const char *ref_prefix = GIT_REFS_DIR; - size_t ref_prefix_len = strlen(ref_prefix); + const char *pos, *last_sep = NULL; - if (!backend->commonpath) /* do nothing if no commonpath for loose refs */ - return 0; + if (!ctx->iter->glob) + return; - fsit_opts.flags = backend->iterator_flags; - - if (iter->glob) { - const char *last_sep = NULL; - const char *pos; - for (pos = iter->glob; *pos; ++pos) { - switch (*pos) { - case '?': - case '*': - case '[': - case '\\': - break; - case '/': - last_sep = pos; - /* FALLTHROUGH */ - default: - continue; - } + for (pos = ctx->iter->glob; *pos; pos++) { + switch (*pos) { + case '?': + case '*': + case '[': + case '\\': break; + case '/': + last_sep = pos; + /* FALLTHROUGH */ + default: + continue; } - if (last_sep) { - ref_prefix = iter->glob; - ref_prefix_len = (last_sep - ref_prefix) + 1; - } + break; } - if ((error = git_str_puts(&path, backend->commonpath)) < 0 || - (error = git_str_put(&path, ref_prefix, ref_prefix_len)) < 0) { - git_str_dispose(&path); - return error; + if (last_sep) { + ctx->ref_prefix = ctx->iter->glob; + ctx->ref_prefix_len = (last_sep - ctx->ref_prefix) + 1; } +} + +static int iter_load_paths( + struct iter_load_context *ctx, + const char *root_path, + bool worktree) +{ + git_iterator *fsit = NULL; + git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT; + const git_index_entry *entry; + int error = 0; + + fsit_opts.flags = ctx->backend->iterator_flags; + + git_str_clear(&ctx->path); + git_str_puts(&ctx->path, root_path); + git_str_put(&ctx->path, ctx->ref_prefix, ctx->ref_prefix_len); + + if ((error = git_iterator_for_filesystem(&fsit, ctx->path.ptr, &fsit_opts)) < 0) { + /* + * Subdirectories - either glob provided or per-worktree refs - need + * not exist. + */ + if ((worktree || ctx->iter->glob) && error == GIT_ENOTFOUND) + error = 0; - if ((error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) { - git_str_dispose(&path); - return (iter->glob && error == GIT_ENOTFOUND)? 0 : error; + goto done; } - error = git_str_sets(&path, ref_prefix); + git_str_clear(&ctx->ref_name); + git_str_put(&ctx->ref_name, ctx->ref_prefix, ctx->ref_prefix_len); - while (!error && !git_iterator_advance(&entry, fsit)) { - const char *ref_name; + while (git_iterator_advance(&entry, fsit) == 0) { char *ref_dup; - git_str_truncate(&path, ref_prefix_len); - git_str_puts(&path, entry->path); - ref_name = git_str_cstr(&path); - if (git_repository_is_worktree(backend->repo) == 1 && is_per_worktree_ref(ref_name)) + git_str_truncate(&ctx->ref_name, ctx->ref_prefix_len); + git_str_puts(&ctx->ref_name, entry->path); + + if (worktree) { + if (!is_per_worktree_ref(ctx->ref_name.ptr)) + continue; + } else { + if (git_repository_is_worktree(ctx->backend->repo) && + is_per_worktree_ref(ctx->ref_name.ptr)) + continue; + } + + if (git__suffixcmp(ctx->ref_name.ptr, ".lock") == 0) continue; - if (git__suffixcmp(ref_name, ".lock") == 0 || - (iter->glob && wildmatch(iter->glob, ref_name, 0) != 0)) + if (ctx->iter->glob && wildmatch(ctx->iter->glob, ctx->ref_name.ptr, 0)) continue; - ref_dup = git_pool_strdup(&iter->pool, ref_name); - if (!ref_dup) - error = -1; - else - error = git_vector_insert(&iter->loose, ref_dup); + ref_dup = git_pool_strdup(&ctx->iter->pool, ctx->ref_name.ptr); + GIT_ERROR_CHECK_ALLOC(ref_dup); + + if ((error = git_vector_insert(&ctx->iter->loose, ref_dup)) < 0) + goto done; } - if (!error && git_repository_is_worktree(backend->repo) == 1) { - git_iterator_free(fsit); - git_str_clear(&path); - if ((error = git_str_puts(&path, backend->gitpath)) < 0 || - (error = git_str_put(&path, ref_prefix, ref_prefix_len)) < 0 || - !git_fs_path_exists(git_str_cstr(&path))) { - git_str_dispose(&path); - return error; - } +done: + git_iterator_free(fsit); + return error; +} - if ((error = git_iterator_for_filesystem( - &fsit, path.ptr, &fsit_opts)) < 0) { - git_str_dispose(&path); - return (iter->glob && error == GIT_ENOTFOUND) ? 0 : error; - } +#define iter_load_context_init(b, i) { b, i, GIT_REFS_DIR, CONST_STRLEN(GIT_REFS_DIR) } +#define iter_load_context_dispose(ctx) do { \ + git_str_dispose(&((ctx)->path)); \ + git_str_dispose(&((ctx)->ref_name)); \ +} while(0) - error = git_str_sets(&path, ref_prefix); +static int iter_load_loose_paths( + refdb_fs_backend *backend, + refdb_fs_iter *iter) +{ + struct iter_load_context ctx = iter_load_context_init(backend, iter); - while (!error && !git_iterator_advance(&entry, fsit)) { - const char *ref_name; - char *ref_dup; + int error = 0; - git_str_truncate(&path, ref_prefix_len); - git_str_puts(&path, entry->path); - ref_name = git_str_cstr(&path); + if (!backend->commonpath) + return 0; - if (!is_per_worktree_ref(ref_name)) - continue; + iter_load_optimize_prefix(&ctx); - if (git__suffixcmp(ref_name, ".lock") == 0 || - (iter->glob && - wildmatch(iter->glob, ref_name, 0) != 0)) - continue; + if ((error = iter_load_paths(&ctx, + backend->commonpath, false)) < 0) + goto done; - ref_dup = git_pool_strdup(&iter->pool, ref_name); - if (!ref_dup) - error = -1; - else - error = git_vector_insert( - &iter->loose, ref_dup); - } + if (git_repository_is_worktree(backend->repo)) { + if ((error = iter_load_paths(&ctx, + backend->gitpath, true)) < 0) + goto done; } - git_iterator_free(fsit); - git_str_dispose(&path); - +done: + iter_load_context_dispose(&ctx); return error; } From b499a3465c121c9f942648adadd56495727b38d9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 3 Mar 2024 21:48:06 +0000 Subject: [PATCH 457/816] config: introduce a writers list Configuration read order and write order should be separated. For example: configuration readers have a worktree level that is higher priority than the local configuration _for reads_. Despite that, the worktree configuration is not written to by default. Use a new list, `writers`, to identify the write target. To do this, we need another level of indirection between backend instances (which are refcounted and shared amongst different git_config instances) and the config reader/writer list (since each of those different git_config instances can have different read/write priorities). --- include/git2/config.h | 9 + src/libgit2/config.c | 597 ++++++++++++++++++++------------------- src/libgit2/config.h | 3 +- src/libgit2/repository.c | 8 +- 4 files changed, 327 insertions(+), 290 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index a711e1561dc..32361431326 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -32,6 +32,10 @@ GIT_BEGIN_DECL * Callers can add their own custom configuration, beginning at the * `GIT_CONFIG_LEVEL_APP` level. * + * Writes, by default, occur in the highest priority level backend + * that is writable. This ordering can be overridden with + * `git_config_set_writeorder`. + * * git_config_open_default() and git_repository_config() honor those * priority levels as well. */ @@ -307,6 +311,11 @@ GIT_EXTERN(int) git_config_open_level( */ GIT_EXTERN(int) git_config_open_global(git_config **out, git_config *config); +GIT_EXTERN(int) git_config_set_writeorder( + git_config *cfg, + git_config_level_t *levels, + size_t len); + /** * Create a snapshot of the configuration * diff --git a/src/libgit2/config.c b/src/libgit2/config.c index d3193c95e26..fdf32e9669a 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -22,6 +22,32 @@ #include +/* + * A refcounted instance of a config_backend that can be shared across + * a configuration instance, any snapshots, and individual configuration + * levels (from `git_config_open_level`). + */ +typedef struct { + git_refcount rc; + git_config_backend *backend; +} backend_instance; + +/* + * An entry in the readers or writers vector in the configuration. + * This is kept separate from the refcounted instance so that different + * views of the configuration can have different notions of levels or + * write orders. + * + * (eg, a standard configuration has a priority ordering of writers, a + * snapshot has *no* writers, and an individual level has a single + * writer.) + */ +typedef struct { + backend_instance *instance; + git_config_level_t level; + int write_order; +} backend_entry; + void git_config_entry_free(git_config_entry *entry) { if (!entry) @@ -30,75 +56,75 @@ void git_config_entry_free(git_config_entry *entry) entry->free(entry); } -typedef struct { - git_refcount rc; - - git_config_backend *backend; - git_config_level_t level; -} backend_internal; - -static void backend_internal_free(backend_internal *internal) +static void backend_instance_free(backend_instance *instance) { git_config_backend *backend; - backend = internal->backend; + backend = instance->backend; backend->free(backend); - git__free(internal); + git__free(instance); } -static void config_free(git_config *cfg) +static void config_free(git_config *config) { size_t i; - backend_internal *internal; + backend_entry *entry; - for (i = 0; i < cfg->backends.length; ++i) { - internal = git_vector_get(&cfg->backends, i); - GIT_REFCOUNT_DEC(internal, backend_internal_free); + git_vector_foreach(&config->readers, i, entry) { + GIT_REFCOUNT_DEC(entry->instance, backend_instance_free); + git__free(entry); } - git_vector_free(&cfg->backends); - - git__memzero(cfg, sizeof(*cfg)); - git__free(cfg); + git_vector_free(&config->readers); + git_vector_free(&config->writers); + git__free(config); } -void git_config_free(git_config *cfg) +void git_config_free(git_config *config) { - if (cfg == NULL) + if (config == NULL) return; - GIT_REFCOUNT_DEC(cfg, config_free); + GIT_REFCOUNT_DEC(config, config_free); } -static int config_backend_cmp(const void *a, const void *b) +static int reader_cmp(const void *_a, const void *_b) { - const backend_internal *bk_a = (const backend_internal *)(a); - const backend_internal *bk_b = (const backend_internal *)(b); + const backend_entry *a = _a; + const backend_entry *b = _b; - return bk_b->level - bk_a->level; + return b->level - a->level; } -int git_config_new(git_config **out) +static int writer_cmp(const void *_a, const void *_b) { - git_config *cfg; + const backend_entry *a = _a; + const backend_entry *b = _b; - cfg = git__malloc(sizeof(git_config)); - GIT_ERROR_CHECK_ALLOC(cfg); + return b->write_order - a->write_order; +} - memset(cfg, 0x0, sizeof(git_config)); +int git_config_new(git_config **out) +{ + git_config *config; - if (git_vector_init(&cfg->backends, 3, config_backend_cmp) < 0) { - git__free(cfg); + config = git__calloc(1, sizeof(git_config)); + GIT_ERROR_CHECK_ALLOC(config); + + if (git_vector_init(&config->readers, 8, reader_cmp) < 0 || + git_vector_init(&config->writers, 8, writer_cmp) < 0) { + config_free(config); return -1; } - *out = cfg; - GIT_REFCOUNT_INC(cfg); + GIT_REFCOUNT_INC(config); + + *out = config; return 0; } int git_config_add_file_ondisk( - git_config *cfg, + git_config *config, const char *path, git_config_level_t level, const git_repository *repo, @@ -108,7 +134,7 @@ int git_config_add_file_ondisk( struct stat st; int res; - GIT_ASSERT_ARG(cfg); + GIT_ASSERT_ARG(config); GIT_ASSERT_ARG(path); res = p_stat(path, &st); @@ -120,7 +146,7 @@ int git_config_add_file_ondisk( if (git_config_backend_from_file(&file, path) < 0) return -1; - if ((res = git_config_add_backend(cfg, file, level, repo, force)) < 0) { + if ((res = git_config_add_backend(config, file, level, repo, force)) < 0) { /* * free manually; the file is not owned by the config * instance yet and will not be freed on cleanup @@ -154,7 +180,7 @@ int git_config_snapshot(git_config **out, git_config *in) { int error = 0; size_t i; - backend_internal *internal; + backend_entry *entry; git_config *config; *out = NULL; @@ -162,18 +188,20 @@ int git_config_snapshot(git_config **out, git_config *in) if (git_config_new(&config) < 0) return -1; - git_vector_foreach(&in->backends, i, internal) { + git_vector_foreach(&in->readers, i, entry) { git_config_backend *b; - if ((error = internal->backend->snapshot(&b, internal->backend)) < 0) + if ((error = entry->instance->backend->snapshot(&b, entry->instance->backend)) < 0) break; - if ((error = git_config_add_backend(config, b, internal->level, NULL, 0)) < 0) { + if ((error = git_config_add_backend(config, b, entry->level, NULL, 0)) < 0) { b->free(b); break; } } + git_config_set_writeorder(config, NULL, 0); + if (error < 0) git_config_free(config); else @@ -183,141 +211,162 @@ int git_config_snapshot(git_config **out, git_config *in) } static int find_backend_by_level( - backend_internal **out, - const git_config *cfg, + backend_instance **out, + const git_config *config, git_config_level_t level) { - int pos = -1; - backend_internal *internal; + backend_entry *entry, *found = NULL; size_t i; - /* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config backend - * which has the highest level. As config backends are stored in a vector - * sorted by decreasing order of level, getting the backend at position 0 - * will do the job. + /* + * when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the + * config backend which has the highest level. As config backends + * are stored in a vector sorted by decreasing order of level, + * getting the backend at position 0 will do the job. */ if (level == GIT_CONFIG_HIGHEST_LEVEL) { - pos = 0; + found = git_vector_get(&config->readers, 0); } else { - git_vector_foreach(&cfg->backends, i, internal) { - if (internal->level == level) - pos = (int)i; + git_vector_foreach(&config->readers, i, entry) { + if (entry->level == level) { + found = entry; + break; + } } } - if (pos == -1) { + if (!found) { git_error_set(GIT_ERROR_CONFIG, - "no configuration exists for the given level '%i'", (int)level); + "no configuration exists for the given level '%d'", level); return GIT_ENOTFOUND; } - *out = git_vector_get(&cfg->backends, pos); - + *out = entry->instance; return 0; } -static int duplicate_level(void **old_raw, void *new_raw) +static int duplicate_level(void **_old, void *_new) { - backend_internal **old = (backend_internal **)old_raw; + backend_entry **old = (backend_entry **)_old; - GIT_UNUSED(new_raw); + GIT_UNUSED(_new); - git_error_set(GIT_ERROR_CONFIG, "there already exists a configuration for the given level (%i)", (int)(*old)->level); + git_error_set(GIT_ERROR_CONFIG, "configuration at level %d already exists", (*old)->level); return GIT_EEXISTS; } static void try_remove_existing_backend( - git_config *cfg, + git_config *config, git_config_level_t level) { - int pos = -1; - backend_internal *internal; + backend_entry *entry, *found = NULL; size_t i; - git_vector_foreach(&cfg->backends, i, internal) { - if (internal->level == level) - pos = (int)i; + git_vector_foreach(&config->readers, i, entry) { + if (entry->level == level) { + git_vector_remove(&config->readers, i); + found = entry; + break; + } } - if (pos == -1) + if (!found) return; - internal = git_vector_get(&cfg->backends, pos); - - if (git_vector_remove(&cfg->backends, pos) < 0) - return; + git_vector_foreach(&config->writers, i, entry) { + if (entry->level == level) { + git_vector_remove(&config->writers, i); + break; + } + } - GIT_REFCOUNT_DEC(internal, backend_internal_free); + GIT_REFCOUNT_DEC(found->instance, backend_instance_free); + git__free(found); } -static int git_config__add_internal( - git_config *cfg, - backend_internal *internal, +static int git_config__add_instance( + git_config *config, + backend_instance *instance, git_config_level_t level, int force) { + backend_entry *entry; int result; /* delete existing config backend for level if it exists */ if (force) - try_remove_existing_backend(cfg, level); + try_remove_existing_backend(config, level); - if ((result = git_vector_insert_sorted(&cfg->backends, - internal, &duplicate_level)) < 0) - return result; + entry = git__malloc(sizeof(backend_entry)); + GIT_ERROR_CHECK_ALLOC(entry); - git_vector_sort(&cfg->backends); - internal->backend->cfg = cfg; + entry->instance = instance; + entry->level = level; + entry->write_order = level; - GIT_REFCOUNT_INC(internal); + if ((result = git_vector_insert_sorted(&config->readers, + entry, &duplicate_level)) < 0 || + (result = git_vector_insert_sorted(&config->writers, + entry, NULL)) < 0) { + git__free(entry); + return result; + } + + GIT_REFCOUNT_INC(entry->instance); return 0; } -int git_config_open_global(git_config **cfg_out, git_config *cfg) +int git_config_open_global(git_config **out, git_config *config) { - if (!git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_XDG)) + int error; + + error = git_config_open_level(out, config, GIT_CONFIG_LEVEL_XDG); + + if (error == 0) return 0; + else if (error != GIT_ENOTFOUND) + return error; - return git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_GLOBAL); + return git_config_open_level(out, config, GIT_CONFIG_LEVEL_GLOBAL); } int git_config_open_level( - git_config **cfg_out, - const git_config *cfg_parent, + git_config **out, + const git_config *parent, git_config_level_t level) { - git_config *cfg; - backend_internal *internal; + git_config *config; + backend_instance *instance; int res; - if ((res = find_backend_by_level(&internal, cfg_parent, level)) < 0) + if ((res = find_backend_by_level(&instance, parent, level)) < 0) return res; - if ((res = git_config_new(&cfg)) < 0) + if ((res = git_config_new(&config)) < 0) return res; - if ((res = git_config__add_internal(cfg, internal, level, true)) < 0) { - git_config_free(cfg); + if ((res = git_config__add_instance(config, instance, level, true)) < 0) { + git_config_free(config); return res; } - *cfg_out = cfg; + *out = config; return 0; } int git_config_add_backend( - git_config *cfg, + git_config *config, git_config_backend *backend, git_config_level_t level, const git_repository *repo, int force) { - backend_internal *internal; + backend_instance *instance; int result; - GIT_ASSERT_ARG(cfg); + GIT_ASSERT_ARG(config); GIT_ASSERT_ARG(backend); GIT_ERROR_CHECK_VERSION(backend, GIT_CONFIG_BACKEND_VERSION, "git_config_backend"); @@ -325,22 +374,50 @@ int git_config_add_backend( if ((result = backend->open(backend, level, repo)) < 0) return result; - internal = git__malloc(sizeof(backend_internal)); - GIT_ERROR_CHECK_ALLOC(internal); + instance = git__calloc(1, sizeof(backend_instance)); + GIT_ERROR_CHECK_ALLOC(instance); - memset(internal, 0x0, sizeof(backend_internal)); + instance->backend = backend; + instance->backend->cfg = config; - internal->backend = backend; - internal->level = level; - - if ((result = git_config__add_internal(cfg, internal, level, force)) < 0) { - git__free(internal); + if ((result = git_config__add_instance(config, instance, level, force)) < 0) { + git__free(instance); return result; } return 0; } +int git_config_set_writeorder( + git_config *config, + git_config_level_t *levels, + size_t len) +{ + backend_entry *entry; + size_t i, j; + + GIT_ASSERT(len < INT_MAX); + + git_vector_foreach(&config->readers, i, entry) { + bool found = false; + + for (j = 0; j < len; j++) { + if (levels[j] == entry->level) { + entry->write_order = (int)j; + found = true; + break; + } + } + + if (!found) + entry->write_order = -1; + } + + git_vector_sort(&config->writers); + + return 0; +} + /* * Loop over all the variables */ @@ -348,19 +425,18 @@ int git_config_add_backend( typedef struct { git_config_iterator parent; git_config_iterator *current; - const git_config *cfg; + const git_config *config; git_regexp regex; size_t i; } all_iter; -static int find_next_backend(size_t *out, const git_config *cfg, size_t i) +static int find_next_backend(size_t *out, const git_config *config, size_t i) { - backend_internal *internal; + backend_entry *entry; for (; i > 0; --i) { - internal = git_vector_get(&cfg->backends, i - 1); - if (!internal || !internal->backend) - continue; + entry = git_vector_get(&config->readers, i - 1); + GIT_ASSERT(entry && entry->instance && entry->instance->backend); *out = i; return 0; @@ -369,16 +445,16 @@ static int find_next_backend(size_t *out, const git_config *cfg, size_t i) return -1; } -static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter) +static int all_iter_next(git_config_entry **out, git_config_iterator *_iter) { all_iter *iter = (all_iter *) _iter; - backend_internal *internal; + backend_entry *entry; git_config_backend *backend; size_t i; int error = 0; if (iter->current != NULL && - (error = iter->current->next(entry, iter->current)) == 0) { + (error = iter->current->next(out, iter->current)) == 0) { return 0; } @@ -386,11 +462,11 @@ static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter) return error; do { - if (find_next_backend(&i, iter->cfg, iter->i) < 0) + if (find_next_backend(&i, iter->config, iter->i) < 0) return GIT_ITEROVER; - internal = git_vector_get(&iter->cfg->backends, i - 1); - backend = internal->backend; + entry = git_vector_get(&iter->config->readers, i - 1); + backend = entry->instance->backend; iter->i = i - 1; if (iter->current) @@ -404,7 +480,7 @@ static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter) if (error < 0) return error; - error = iter->current->next(entry, iter->current); + error = iter->current->next(out, iter->current); /* If this backend is empty, then keep going */ if (error == GIT_ITEROVER) continue; @@ -423,7 +499,7 @@ static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_it /* * We use the "normal" function to grab the next one across - * backends and then apply the regex + * readers and then apply the regex */ while ((error = all_iter_next(entry, _iter)) == 0) { /* skip non-matching keys if regexp was provided */ @@ -455,7 +531,7 @@ static void all_iter_glob_free(git_config_iterator *_iter) all_iter_free(_iter); } -int git_config_iterator_new(git_config_iterator **out, const git_config *cfg) +int git_config_iterator_new(git_config_iterator **out, const git_config *config) { all_iter *iter; @@ -465,21 +541,21 @@ int git_config_iterator_new(git_config_iterator **out, const git_config *cfg) iter->parent.free = all_iter_free; iter->parent.next = all_iter_next; - iter->i = cfg->backends.length; - iter->cfg = cfg; + iter->i = config->readers.length; + iter->config = config; *out = (git_config_iterator *) iter; return 0; } -int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp) +int git_config_iterator_glob_new(git_config_iterator **out, const git_config *config, const char *regexp) { all_iter *iter; int result; if (regexp == NULL) - return git_config_iterator_new(out, cfg); + return git_config_iterator_new(out, config); iter = git__calloc(1, sizeof(all_iter)); GIT_ERROR_CHECK_ALLOC(iter); @@ -491,8 +567,8 @@ int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cf iter->parent.next = all_iter_glob_next; iter->parent.free = all_iter_glob_free; - iter->i = cfg->backends.length; - iter->cfg = cfg; + iter->i = config->readers.length; + iter->config = config; *out = (git_config_iterator *) iter; @@ -500,9 +576,9 @@ int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cf } int git_config_foreach( - const git_config *cfg, git_config_foreach_cb cb, void *payload) + const git_config *config, git_config_foreach_cb cb, void *payload) { - return git_config_foreach_match(cfg, NULL, cb, payload); + return git_config_foreach_match(config, NULL, cb, payload); } int git_config_backend_foreach_match( @@ -548,7 +624,7 @@ int git_config_backend_foreach_match( } int git_config_foreach_match( - const git_config *cfg, + const git_config *config, const char *regexp, git_config_foreach_cb cb, void *payload) @@ -557,7 +633,7 @@ int git_config_foreach_match( git_config_iterator *iter; git_config_entry *entry; - if ((error = git_config_iterator_glob_new(&iter, cfg, regexp)) < 0) + if ((error = git_config_iterator_glob_new(&iter, config, regexp)) < 0) return error; while (!(error = git_config_next(&entry, iter))) { @@ -579,103 +655,52 @@ int git_config_foreach_match( * Setters **************/ -typedef enum { - BACKEND_USE_SET, - BACKEND_USE_DELETE -} backend_use; - -static const char *uses[] = { - "set", - "delete" -}; - -static int get_backend_for_use(git_config_backend **out, - git_config *cfg, const char *name, backend_use use) +static git_config_backend *get_writer(git_config *config) { + backend_entry *entry; size_t i; - size_t len; - backend_internal *backend; - int error = 0; - git_config_entry *entry = NULL; - char *key = NULL; - *out = NULL; - - len = git_vector_length(&cfg->backends); - if (len == 0) { - git_error_set(GIT_ERROR_CONFIG, - "cannot %s value for '%s' when no config backends exist", - uses[use], name); - return GIT_ENOTFOUND; - } - - git_vector_foreach(&cfg->backends, i, backend) { - if (backend->backend->readonly) + git_vector_foreach(&config->writers, i, entry) { + if (entry->instance->backend->readonly) continue; - /* git-config doesn't update worktree-level config - unless specifically requested; follow suit. If you - specifically want to update that level, open the - single config level with git_config_open_level and - provide that as the config. In this case, there - will only be one backend in the config. */ - if (len > 1 && backend->level == GIT_CONFIG_LEVEL_WORKTREE) + if (entry->write_order < 0) continue; - /* If we're trying to delete a piece of config, make - sure the backend we return actually defines it in - the first place. */ - if (use == BACKEND_USE_DELETE) { - if (key == NULL && (error = git_config__normalize_name(name, &key)) < 0) - goto cleanup; - if (backend->backend->get(backend->backend, key, &entry) < 0) - continue; - git_config_entry_free(entry); - } - - *out = backend->backend; - goto cleanup; + return entry->instance->backend; } - error = GIT_ENOTFOUND; - git_error_set(GIT_ERROR_CONFIG, - "cannot %s value for '%s' when all config backends are readonly", - uses[use], name); - - cleanup: - git__free(key); - return error; + return NULL; } -int git_config_delete_entry(git_config *cfg, const char *name) +int git_config_delete_entry(git_config *config, const char *name) { git_config_backend *backend; - int error = 0; - if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE)) < 0) - return error; + if ((backend = get_writer(config)) == NULL) + return GIT_ENOTFOUND; return backend->del(backend, name); } -int git_config_set_int64(git_config *cfg, const char *name, int64_t value) +int git_config_set_int64(git_config *config, const char *name, int64_t value) { char str_value[32]; /* All numbers should fit in here */ p_snprintf(str_value, sizeof(str_value), "%" PRId64, value); - return git_config_set_string(cfg, name, str_value); + return git_config_set_string(config, name, str_value); } -int git_config_set_int32(git_config *cfg, const char *name, int32_t value) +int git_config_set_int32(git_config *config, const char *name, int32_t value) { - return git_config_set_int64(cfg, name, (int64_t)value); + return git_config_set_int64(config, name, (int64_t)value); } -int git_config_set_bool(git_config *cfg, const char *name, int value) +int git_config_set_bool(git_config *config, const char *name, int value) { - return git_config_set_string(cfg, name, value ? "true" : "false"); + return git_config_set_string(config, name, value ? "true" : "false"); } -int git_config_set_string(git_config *cfg, const char *name, const char *value) +int git_config_set_string(git_config *config, const char *name, const char *value) { int error; git_config_backend *backend; @@ -685,13 +710,15 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) return -1; } - if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET)) < 0) - return error; + if ((backend = get_writer(config)) == NULL) { + git_error_set(GIT_ERROR_CONFIG, "cannot set '%s': the configuration is read-only", name); + return GIT_ENOTFOUND; + } error = backend->set(backend, name, value); - if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) - git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(cfg)); + if (!error && GIT_REFCOUNT_OWNER(config) != NULL) + git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(config)); return error; } @@ -745,16 +772,17 @@ enum { static int get_entry( git_config_entry **out, - const git_config *cfg, + const git_config *config, const char *name, bool normalize_name, int want_errors) { + backend_entry *entry; + git_config_backend *backend; int res = GIT_ENOTFOUND; const char *key = name; char *normalized = NULL; size_t i; - backend_internal *internal; *out = NULL; @@ -765,11 +793,12 @@ static int get_entry( } res = GIT_ENOTFOUND; - git_vector_foreach(&cfg->backends, i, internal) { - if (!internal || !internal->backend) - continue; + git_vector_foreach(&config->readers, i, entry) { + GIT_ASSERT(entry->instance && entry->instance->backend); + + backend = entry->instance->backend; + res = backend->get(backend, key, out); - res = internal->backend->get(internal->backend, key, out); if (res != GIT_ENOTFOUND) break; } @@ -777,9 +806,9 @@ static int get_entry( git__free(normalized); cleanup: - if (res == GIT_ENOTFOUND) + if (res == GIT_ENOTFOUND) { res = (want_errors > GET_ALL_ERRORS) ? 0 : config_error_notfound(name); - else if (res && (want_errors == GET_NO_ERRORS)) { + } else if (res && (want_errors == GET_NO_ERRORS)) { git_error_clear(); res = 0; } @@ -788,24 +817,24 @@ static int get_entry( } int git_config_get_entry( - git_config_entry **out, const git_config *cfg, const char *name) + git_config_entry **out, const git_config *config, const char *name) { - return get_entry(out, cfg, name, true, GET_ALL_ERRORS); + return get_entry(out, config, name, true, GET_ALL_ERRORS); } int git_config__lookup_entry( git_config_entry **out, - const git_config *cfg, + const git_config *config, const char *key, bool no_errors) { return get_entry( - out, cfg, key, false, no_errors ? GET_NO_ERRORS : GET_NO_MISSING); + out, config, key, false, no_errors ? GET_NO_ERRORS : GET_NO_MISSING); } int git_config_get_mapped( int *out, - const git_config *cfg, + const git_config *config, const char *name, const git_configmap *maps, size_t map_n) @@ -813,7 +842,7 @@ int git_config_get_mapped( git_config_entry *entry; int ret; - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) return ret; ret = git_config_lookup_map_value(out, maps, map_n, entry->value); @@ -822,12 +851,12 @@ int git_config_get_mapped( return ret; } -int git_config_get_int64(int64_t *out, const git_config *cfg, const char *name) +int git_config_get_int64(int64_t *out, const git_config *config, const char *name) { git_config_entry *entry; int ret; - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) return ret; ret = git_config_parse_int64(out, entry->value); @@ -836,12 +865,12 @@ int git_config_get_int64(int64_t *out, const git_config *cfg, const char *name) return ret; } -int git_config_get_int32(int32_t *out, const git_config *cfg, const char *name) +int git_config_get_int32(int32_t *out, const git_config *config, const char *name) { git_config_entry *entry; int ret; - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) return ret; ret = git_config_parse_int32(out, entry->value); @@ -850,12 +879,12 @@ int git_config_get_int32(int32_t *out, const git_config *cfg, const char *name) return ret; } -int git_config_get_bool(int *out, const git_config *cfg, const char *name) +int git_config_get_bool(int *out, const git_config *config, const char *name) { git_config_entry *entry; int ret; - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) return ret; ret = git_config_parse_bool(out, entry->value); @@ -864,16 +893,15 @@ int git_config_get_bool(int *out, const git_config *cfg, const char *name) return ret; } -static int is_readonly(const git_config *cfg) +static int is_readonly(const git_config *config) { + backend_entry *entry; size_t i; - backend_internal *internal; - git_vector_foreach(&cfg->backends, i, internal) { - if (!internal || !internal->backend) - continue; + git_vector_foreach(&config->writers, i, entry) { + GIT_ASSERT(entry->instance && entry->instance->backend); - if (!internal->backend->readonly) + if (!entry->instance->backend->readonly) return 0; } @@ -904,21 +932,21 @@ int git_config_parse_path(git_buf *out, const char *value) int git_config_get_path( git_buf *out, - const git_config *cfg, + const git_config *config, const char *name) { - GIT_BUF_WRAP_PRIVATE(out, git_config__get_path, cfg, name); + GIT_BUF_WRAP_PRIVATE(out, git_config__get_path, config, name); } int git_config__get_path( git_str *out, - const git_config *cfg, + const git_config *config, const char *name) { git_config_entry *entry; int error; - if ((error = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) + if ((error = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) return error; error = git_config__parse_path(out, entry->value); @@ -928,17 +956,17 @@ int git_config__get_path( } int git_config_get_string( - const char **out, const git_config *cfg, const char *name) + const char **out, const git_config *config, const char *name) { git_config_entry *entry; int ret; - if (!is_readonly(cfg)) { + if (!is_readonly(config)) { git_error_set(GIT_ERROR_CONFIG, "get_string called on a live config object"); return -1; } - ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS); + ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS); *out = !ret ? (entry->value ? entry->value : "") : NULL; git_config_entry_free(entry); @@ -947,22 +975,22 @@ int git_config_get_string( } int git_config_get_string_buf( - git_buf *out, const git_config *cfg, const char *name) + git_buf *out, const git_config *config, const char *name) { - GIT_BUF_WRAP_PRIVATE(out, git_config__get_string_buf, cfg, name); + GIT_BUF_WRAP_PRIVATE(out, git_config__get_string_buf, config, name); } int git_config__get_string_buf( - git_str *out, const git_config *cfg, const char *name) + git_str *out, const git_config *config, const char *name) { git_config_entry *entry; int ret; const char *str; GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(cfg); + GIT_ASSERT_ARG(config); - ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS); + ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS); str = !ret ? (entry->value ? entry->value : "") : NULL; if (str) @@ -974,12 +1002,12 @@ int git_config__get_string_buf( } char *git_config__get_string_force( - const git_config *cfg, const char *key, const char *fallback_value) + const git_config *config, const char *key, const char *fallback_value) { git_config_entry *entry; char *ret; - get_entry(&entry, cfg, key, false, GET_NO_ERRORS); + get_entry(&entry, config, key, false, GET_NO_ERRORS); ret = (entry && entry->value) ? git__strdup(entry->value) : fallback_value ? git__strdup(fallback_value) : NULL; git_config_entry_free(entry); @@ -987,12 +1015,12 @@ char *git_config__get_string_force( } int git_config__get_bool_force( - const git_config *cfg, const char *key, int fallback_value) + const git_config *config, const char *key, int fallback_value) { int val = fallback_value; git_config_entry *entry; - get_entry(&entry, cfg, key, false, GET_NO_ERRORS); + get_entry(&entry, config, key, false, GET_NO_ERRORS); if (entry && git_config_parse_bool(&val, entry->value) < 0) git_error_clear(); @@ -1002,12 +1030,12 @@ int git_config__get_bool_force( } int git_config__get_int_force( - const git_config *cfg, const char *key, int fallback_value) + const git_config *config, const char *key, int fallback_value) { int32_t val = (int32_t)fallback_value; git_config_entry *entry; - get_entry(&entry, cfg, key, false, GET_NO_ERRORS); + get_entry(&entry, config, key, false, GET_NO_ERRORS); if (entry && git_config_parse_int32(&val, entry->value) < 0) git_error_clear(); @@ -1017,14 +1045,14 @@ int git_config__get_int_force( } int git_config_get_multivar_foreach( - const git_config *cfg, const char *name, const char *regexp, + const git_config *config, const char *name, const char *regexp, git_config_foreach_cb cb, void *payload) { int err, found; git_config_iterator *iter; git_config_entry *entry; - if ((err = git_config_multivar_iterator_new(&iter, cfg, name, regexp)) < 0) + if ((err = git_config_multivar_iterator_new(&iter, config, name, regexp)) < 0) return err; found = 0; @@ -1086,13 +1114,13 @@ static void multivar_iter_free(git_config_iterator *_iter) git__free(iter); } -int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp) +int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *config, const char *name, const char *regexp) { multivar_iter *iter = NULL; git_config_iterator *inner = NULL; int error; - if ((error = git_config_iterator_new(&inner, cfg)) < 0) + if ((error = git_config_iterator_new(&inner, config)) < 0) return error; iter = git__calloc(1, sizeof(multivar_iter)); @@ -1123,24 +1151,24 @@ int git_config_multivar_iterator_new(git_config_iterator **out, const git_config return error; } -int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) +int git_config_set_multivar(git_config *config, const char *name, const char *regexp, const char *value) { git_config_backend *backend; - int error = 0; - if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET)) < 0) - return error; + if ((backend = get_writer(config)) == NULL) { + git_error_set(GIT_ERROR_CONFIG, "cannot set '%s': the configuration is read-only", name); + return GIT_ENOTFOUND; + } return backend->set_multivar(backend, name, regexp, value); } -int git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp) +int git_config_delete_multivar(git_config *config, const char *name, const char *regexp) { git_config_backend *backend; - int error = 0; - if ((error = get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE)) < 0) - return error; + if ((backend = get_writer(config)) == NULL) + return GIT_ENOTFOUND; return backend->del_multivar(backend, name, regexp); } @@ -1251,78 +1279,71 @@ int git_config__global_location(git_str *buf) int git_config_open_default(git_config **out) { int error; - git_config *cfg = NULL; + git_config *config = NULL; git_str buf = GIT_STR_INIT; - if ((error = git_config_new(&cfg)) < 0) + if ((error = git_config_new(&config)) < 0) return error; if (!git_config__find_global(&buf) || !git_config__global_location(&buf)) { - error = git_config_add_file_ondisk(cfg, buf.ptr, + error = git_config_add_file_ondisk(config, buf.ptr, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0); } if (!error && !git_config__find_xdg(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, + error = git_config_add_file_ondisk(config, buf.ptr, GIT_CONFIG_LEVEL_XDG, NULL, 0); if (!error && !git_config__find_system(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, + error = git_config_add_file_ondisk(config, buf.ptr, GIT_CONFIG_LEVEL_SYSTEM, NULL, 0); if (!error && !git_config__find_programdata(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, + error = git_config_add_file_ondisk(config, buf.ptr, GIT_CONFIG_LEVEL_PROGRAMDATA, NULL, 0); git_str_dispose(&buf); if (error) { - git_config_free(cfg); - cfg = NULL; + git_config_free(config); + config = NULL; } - *out = cfg; + *out = config; return error; } -int git_config_lock(git_transaction **out, git_config *cfg) +int git_config_lock(git_transaction **out, git_config *config) { - int error; git_config_backend *backend; - backend_internal *internal; + int error; - GIT_ASSERT_ARG(cfg); + GIT_ASSERT_ARG(config); - internal = git_vector_get(&cfg->backends, 0); - if (!internal || !internal->backend) { - git_error_set(GIT_ERROR_CONFIG, "cannot lock; the config has no backends"); - return -1; + if ((backend = get_writer(config)) == NULL) { + git_error_set(GIT_ERROR_CONFIG, "cannot lock: the configuration is read-only"); + return GIT_ENOTFOUND; } - backend = internal->backend; if ((error = backend->lock(backend)) < 0) return error; - return git_transaction_config_new(out, cfg); + return git_transaction_config_new(out, config); } -int git_config_unlock(git_config *cfg, int commit) +int git_config_unlock(git_config *config, int commit) { git_config_backend *backend; - backend_internal *internal; - GIT_ASSERT_ARG(cfg); + GIT_ASSERT_ARG(config); - internal = git_vector_get(&cfg->backends, 0); - if (!internal || !internal->backend) { - git_error_set(GIT_ERROR_CONFIG, "cannot lock; the config has no backends"); - return -1; + if ((backend = get_writer(config)) == NULL) { + git_error_set(GIT_ERROR_CONFIG, "cannot unlock: the configuration is read-only"); + return GIT_ENOTFOUND; } - backend = internal->backend; - return backend->unlock(backend, commit); } diff --git a/src/libgit2/config.h b/src/libgit2/config.h index 01b84b157f7..3119f7d748b 100644 --- a/src/libgit2/config.h +++ b/src/libgit2/config.h @@ -24,7 +24,8 @@ struct git_config { git_refcount rc; - git_vector backends; + git_vector readers; + git_vector writers; }; extern int git_config__global_location(git_str *buf); diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index be938b5b9d0..97671fe40b1 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1282,9 +1282,10 @@ static int load_config( const char *system_config_path, const char *programdata_path) { - int error; git_str config_path = GIT_STR_INIT; git_config *cfg = NULL; + git_config_level_t write_order; + int error; GIT_ASSERT_ARG(out); @@ -1333,6 +1334,11 @@ static int load_config( git_error_clear(); /* clear any lingering ENOTFOUND errors */ + write_order = GIT_CONFIG_LEVEL_LOCAL; + + if ((error = git_config_set_writeorder(cfg, &write_order, 1)) < 0) + goto on_error; + *out = cfg; return 0; From fb187bd00367463587ea88f351b71822d3f6057c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 4 Mar 2024 13:28:21 +0000 Subject: [PATCH 458/816] config: return GIT_EREADONLY on read-only configs Introduce `GIT_EREADONLY` and return it when a read-only configuration is attempted to be mutated. This is preferred over the prior `GIT_ENOTFOUND` which is not accurate. --- include/git2/errors.h | 3 ++- src/libgit2/config.c | 12 ++++++------ tests/libgit2/config/readonly.c | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index bdace8c43dd..5dda9fa0362 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -60,7 +60,8 @@ typedef enum { GIT_EAPPLYFAIL = -35, /**< Patch application failed */ GIT_EOWNER = -36, /**< The object is not owned by the current user */ GIT_TIMEOUT = -37, /**< The operation timed out */ - GIT_EUNCHANGED = -38 /**< There were no changes */ + GIT_EUNCHANGED = -38, /**< There were no changes */ + GIT_EREADONLY = -39 /**< The subject is read-only */ } git_error_code; /** diff --git a/src/libgit2/config.c b/src/libgit2/config.c index fdf32e9669a..7e38d86936f 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -678,7 +678,7 @@ int git_config_delete_entry(git_config *config, const char *name) git_config_backend *backend; if ((backend = get_writer(config)) == NULL) - return GIT_ENOTFOUND; + return GIT_EREADONLY; return backend->del(backend, name); } @@ -712,7 +712,7 @@ int git_config_set_string(git_config *config, const char *name, const char *valu if ((backend = get_writer(config)) == NULL) { git_error_set(GIT_ERROR_CONFIG, "cannot set '%s': the configuration is read-only", name); - return GIT_ENOTFOUND; + return GIT_EREADONLY; } error = backend->set(backend, name, value); @@ -1157,7 +1157,7 @@ int git_config_set_multivar(git_config *config, const char *name, const char *re if ((backend = get_writer(config)) == NULL) { git_error_set(GIT_ERROR_CONFIG, "cannot set '%s': the configuration is read-only", name); - return GIT_ENOTFOUND; + return GIT_EREADONLY; } return backend->set_multivar(backend, name, regexp, value); @@ -1168,7 +1168,7 @@ int git_config_delete_multivar(git_config *config, const char *name, const char git_config_backend *backend; if ((backend = get_writer(config)) == NULL) - return GIT_ENOTFOUND; + return GIT_EREADONLY; return backend->del_multivar(backend, name, regexp); } @@ -1324,7 +1324,7 @@ int git_config_lock(git_transaction **out, git_config *config) if ((backend = get_writer(config)) == NULL) { git_error_set(GIT_ERROR_CONFIG, "cannot lock: the configuration is read-only"); - return GIT_ENOTFOUND; + return GIT_EREADONLY; } if ((error = backend->lock(backend)) < 0) @@ -1341,7 +1341,7 @@ int git_config_unlock(git_config *config, int commit) if ((backend = get_writer(config)) == NULL) { git_error_set(GIT_ERROR_CONFIG, "cannot unlock: the configuration is read-only"); - return GIT_ENOTFOUND; + return GIT_EREADONLY; } return backend->unlock(backend, commit); diff --git a/tests/libgit2/config/readonly.c b/tests/libgit2/config/readonly.c index a8901e394c0..483f83a85fd 100644 --- a/tests/libgit2/config/readonly.c +++ b/tests/libgit2/config/readonly.c @@ -24,7 +24,7 @@ void test_config_readonly__writing_to_readonly_fails(void) backend->readonly = 1; cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); - cl_git_fail_with(GIT_ENOTFOUND, git_config_set_string(cfg, "foo.bar", "baz")); + cl_git_fail_with(GIT_EREADONLY, git_config_set_string(cfg, "foo.bar", "baz")); cl_assert(!git_fs_path_exists("global")); } From 5f85714e1f80a16f95c646fbb2124d8f963c0a2c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 4 Mar 2024 14:55:40 +0000 Subject: [PATCH 459/816] config: don't git_config_free an aborted transaction When a configuration transaction is freed with `git_transaction_free` - without first committing it - we should not `git_config_free`. We never increased the refcount, so we certainly shouldn't decrease it. Also, add a test around aborting a transaction without committing it. --- tests/libgit2/config/write.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/libgit2/config/write.c b/tests/libgit2/config/write.c index 9d8c3fe9495..c71d4f6dc86 100644 --- a/tests/libgit2/config/write.c +++ b/tests/libgit2/config/write.c @@ -696,6 +696,36 @@ void test_config_write__locking(void) git_config_free(cfg); } +void test_config_write__abort_lock(void) +{ + git_config *cfg; + git_config_entry *entry; + git_transaction *tx; + const char *filename = "locked-file"; + + /* Open the config and lock it */ + cl_git_mkfile(filename, "[section]\n\tname = value\n"); + cl_git_pass(git_config_open_ondisk(&cfg, filename)); + cl_git_pass(git_config_get_entry(&entry, cfg, "section.name")); + cl_assert_equal_s("value", entry->value); + git_config_entry_free(entry); + cl_git_pass(git_config_lock(&tx, cfg)); + + /* Change entries in the locked backend */ + cl_git_pass(git_config_set_string(cfg, "section.name", "other value")); + cl_git_pass(git_config_set_string(cfg, "section2.name3", "more value")); + + git_transaction_free(tx); + + /* Now that we've unlocked it, we should see no changes */ + cl_git_pass(git_config_get_entry(&entry, cfg, "section.name")); + cl_assert_equal_s("value", entry->value); + git_config_entry_free(entry); + cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg, "section2.name3")); + + git_config_free(cfg); +} + void test_config_write__repeated(void) { const char *filename = "config-repeated"; From d287e1a4fe020253f2b194e2f81e199145f3646d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 4 Mar 2024 15:11:54 +0000 Subject: [PATCH 460/816] config: store the backend in a transaction When we `git_config_unlock`, we shouldn't _unlock the thing that we locked_ instead of assuming that the highest-priority target _remains_ the highest-priority target. --- src/libgit2/config.c | 17 +++++++---------- src/libgit2/config.h | 10 +++++++--- src/libgit2/transaction.c | 17 +++++++++++------ src/libgit2/transaction.h | 5 ++++- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 7e38d86936f..26b6fd677cd 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -1330,19 +1330,16 @@ int git_config_lock(git_transaction **out, git_config *config) if ((error = backend->lock(backend)) < 0) return error; - return git_transaction_config_new(out, config); + return git_transaction_config_new(out, config, backend); } -int git_config_unlock(git_config *config, int commit) +int git_config_unlock( + git_config *config, + git_config_backend *backend, + int commit) { - git_config_backend *backend; - - GIT_ASSERT_ARG(config); - - if ((backend = get_writer(config)) == NULL) { - git_error_set(GIT_ERROR_CONFIG, "cannot unlock: the configuration is read-only"); - return GIT_EREADONLY; - } + GIT_ASSERT_ARG(config && backend); + GIT_UNUSED(config); return backend->unlock(backend, commit); } diff --git a/src/libgit2/config.h b/src/libgit2/config.h index 3119f7d748b..d3428e7da4e 100644 --- a/src/libgit2/config.h +++ b/src/libgit2/config.h @@ -95,17 +95,21 @@ int git_config_lookup_map_enum(git_configmap_t *type_out, size_t map_n, int enum_val); /** - * Unlock the backend with the highest priority + * Unlock the given backend that was previously locked. * * Unlocking will allow other writers to update the configuration * file. Optionally, any changes performed since the lock will be * applied to the configuration. * - * @param cfg the configuration + * @param config the config instance + * @param backend the config backend * @param commit boolean which indicates whether to commit any changes * done since locking * @return 0 or an error code */ -GIT_EXTERN(int) git_config_unlock(git_config *cfg, int commit); +GIT_EXTERN(int) git_config_unlock( + git_config *config, + git_config_backend *backend, + int commit); #endif diff --git a/src/libgit2/transaction.c b/src/libgit2/transaction.c index ccffa9984cc..47bdb03a2f9 100644 --- a/src/libgit2/transaction.c +++ b/src/libgit2/transaction.c @@ -49,12 +49,16 @@ struct git_transaction { git_repository *repo; git_refdb *db; git_config *cfg; + git_config_backend *backend; git_strmap *locks; git_pool pool; }; -int git_transaction_config_new(git_transaction **out, git_config *cfg) +int git_transaction_config_new( + git_transaction **out, + git_config *cfg, + git_config_backend *backend) { git_transaction *tx; @@ -66,6 +70,8 @@ int git_transaction_config_new(git_transaction **out, git_config *cfg) tx->type = TRANSACTION_CONFIG; tx->cfg = cfg; + tx->backend = backend; + *out = tx; return 0; } @@ -333,8 +339,9 @@ int git_transaction_commit(git_transaction *tx) GIT_ASSERT_ARG(tx); if (tx->type == TRANSACTION_CONFIG) { - error = git_config_unlock(tx->cfg, true); + error = git_config_unlock(tx->cfg, tx->backend, true); tx->cfg = NULL; + tx->backend = NULL; return error; } @@ -369,10 +376,8 @@ void git_transaction_free(git_transaction *tx) return; if (tx->type == TRANSACTION_CONFIG) { - if (tx->cfg) { - git_config_unlock(tx->cfg, false); - git_config_free(tx->cfg); - } + if (tx->cfg) + git_config_unlock(tx->cfg, tx->backend, false); git__free(tx); return; diff --git a/src/libgit2/transaction.h b/src/libgit2/transaction.h index 780c068303e..961c8c3c844 100644 --- a/src/libgit2/transaction.h +++ b/src/libgit2/transaction.h @@ -9,6 +9,9 @@ #include "common.h" -int git_transaction_config_new(git_transaction **out, git_config *cfg); +int git_transaction_config_new( + git_transaction **out, + git_config *cfg, + git_config_backend *backend); #endif From e8910c175dd4418505962687050193cb08e3c3e4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 4 Mar 2024 16:42:59 +0000 Subject: [PATCH 461/816] config: refcount the backend when we start a transaction When we start a transaction, we should refcount the backend so that we don't lose it. This prevents the case where we have a transaction open and a configuration entry locked and somebody forces a new backend at the same level and the backend is freed. Now a user can gently wind down their transaction even when the backend has been removed from the live configuration object. --- src/libgit2/config.c | 35 +++++++++++++++++++++++++---------- src/libgit2/config.h | 4 ++-- src/libgit2/transaction.c | 12 ++++++------ src/libgit2/transaction.h | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 26b6fd677cd..21b9666db33 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -655,8 +655,8 @@ int git_config_foreach_match( * Setters **************/ -static git_config_backend *get_writer(git_config *config) -{ + static backend_instance *get_writer_instance(git_config *config) + { backend_entry *entry; size_t i; @@ -667,10 +667,17 @@ static git_config_backend *get_writer(git_config *config) if (entry->write_order < 0) continue; - return entry->instance->backend; + return entry->instance; } return NULL; + } + +static git_config_backend *get_writer(git_config *config) +{ + backend_instance *instance = get_writer_instance(config); + + return instance ? instance->backend : NULL; } int git_config_delete_entry(git_config *config, const char *name) @@ -1317,31 +1324,39 @@ int git_config_open_default(git_config **out) int git_config_lock(git_transaction **out, git_config *config) { - git_config_backend *backend; + backend_instance *instance; int error; GIT_ASSERT_ARG(config); - if ((backend = get_writer(config)) == NULL) { + if ((instance = get_writer_instance(config)) == NULL) { git_error_set(GIT_ERROR_CONFIG, "cannot lock: the configuration is read-only"); return GIT_EREADONLY; } - if ((error = backend->lock(backend)) < 0) + if ((error = instance->backend->lock(instance->backend)) < 0 || + (error = git_transaction_config_new(out, config, instance)) < 0) return error; - return git_transaction_config_new(out, config, backend); + GIT_REFCOUNT_INC(instance); + return 0; } int git_config_unlock( git_config *config, - git_config_backend *backend, + void *data, int commit) { - GIT_ASSERT_ARG(config && backend); + backend_instance *instance = data; + int error; + + GIT_ASSERT_ARG(config && data); GIT_UNUSED(config); - return backend->unlock(backend, commit); + error = instance->backend->unlock(instance->backend, commit); + GIT_REFCOUNT_DEC(instance, backend_instance_free); + + return error; } /*********** diff --git a/src/libgit2/config.h b/src/libgit2/config.h index d3428e7da4e..5003cbf9c1f 100644 --- a/src/libgit2/config.h +++ b/src/libgit2/config.h @@ -102,14 +102,14 @@ int git_config_lookup_map_enum(git_configmap_t *type_out, * applied to the configuration. * * @param config the config instance - * @param backend the config backend + * @param data the config data passed to git_transaction_new * @param commit boolean which indicates whether to commit any changes * done since locking * @return 0 or an error code */ GIT_EXTERN(int) git_config_unlock( git_config *config, - git_config_backend *backend, + void *data, int commit); #endif diff --git a/src/libgit2/transaction.c b/src/libgit2/transaction.c index 47bdb03a2f9..963416196b4 100644 --- a/src/libgit2/transaction.c +++ b/src/libgit2/transaction.c @@ -49,7 +49,7 @@ struct git_transaction { git_repository *repo; git_refdb *db; git_config *cfg; - git_config_backend *backend; + void *cfg_data; git_strmap *locks; git_pool pool; @@ -58,7 +58,7 @@ struct git_transaction { int git_transaction_config_new( git_transaction **out, git_config *cfg, - git_config_backend *backend) + void *data) { git_transaction *tx; @@ -70,7 +70,7 @@ int git_transaction_config_new( tx->type = TRANSACTION_CONFIG; tx->cfg = cfg; - tx->backend = backend; + tx->cfg_data = data; *out = tx; return 0; @@ -339,9 +339,9 @@ int git_transaction_commit(git_transaction *tx) GIT_ASSERT_ARG(tx); if (tx->type == TRANSACTION_CONFIG) { - error = git_config_unlock(tx->cfg, tx->backend, true); + error = git_config_unlock(tx->cfg, tx->cfg_data, true); tx->cfg = NULL; - tx->backend = NULL; + tx->cfg_data = NULL; return error; } @@ -377,7 +377,7 @@ void git_transaction_free(git_transaction *tx) if (tx->type == TRANSACTION_CONFIG) { if (tx->cfg) - git_config_unlock(tx->cfg, tx->backend, false); + git_config_unlock(tx->cfg, tx->cfg_data, false); git__free(tx); return; diff --git a/src/libgit2/transaction.h b/src/libgit2/transaction.h index 961c8c3c844..cb26017ae9f 100644 --- a/src/libgit2/transaction.h +++ b/src/libgit2/transaction.h @@ -12,6 +12,6 @@ int git_transaction_config_new( git_transaction **out, git_config *cfg, - git_config_backend *backend); + void *data); #endif From e890ca35aa321cf128078e628ea05e79bd2c9607 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 11 Mar 2024 15:20:02 +0000 Subject: [PATCH 462/816] config: only read worktree config if extension is set Only read the worktree configuration when `extensions.worktreeconfig` is set to true. --- src/libgit2/repository.c | 29 +++++++++++++++++++++++++---- tests/libgit2/worktree/config.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 97671fe40b1..124ec3672ab 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1274,6 +1274,24 @@ int git_repository_discover( return error; } +static int has_config_worktree(bool *out, git_config *cfg) +{ + int worktreeconfig = 0, error; + + *out = false; + + error = git_config_get_bool(&worktreeconfig, cfg, "extensions.worktreeconfig"); + + if (error == 0) + *out = worktreeconfig; + else if (error == GIT_ENOTFOUND) + *out = false; + else + return error; + + return 0; +} + static int load_config( git_config **out, git_repository *repo, @@ -1285,6 +1303,7 @@ static int load_config( git_str config_path = GIT_STR_INIT; git_config *cfg = NULL; git_config_level_t write_order; + bool has_worktree; int error; GIT_ASSERT_ARG(out); @@ -1293,14 +1312,16 @@ static int load_config( return error; if (repo) { - if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_WORKTREE_CONFIG)) == 0) - error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_WORKTREE, repo, 0); + if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); if (error && error != GIT_ENOTFOUND) goto on_error; - if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) - error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); + if ((error = has_config_worktree(&has_worktree, cfg)) == 0 && + has_worktree && + (error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_WORKTREE_CONFIG)) == 0) + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_WORKTREE, repo, 0); if (error && error != GIT_ENOTFOUND) goto on_error; diff --git a/tests/libgit2/worktree/config.c b/tests/libgit2/worktree/config.c index 2ddec25e264..dee8e0c06d6 100644 --- a/tests/libgit2/worktree/config.c +++ b/tests/libgit2/worktree/config.c @@ -6,15 +6,19 @@ static worktree_fixture fixture = WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); +static worktree_fixture submodule = + WORKTREE_FIXTURE_INIT("submodules", "submodules-worktree-parent"); void test_worktree_config__initialize(void) { setup_fixture_worktree(&fixture); + setup_fixture_worktree(&submodule); } void test_worktree_config__cleanup(void) { cleanup_fixture_worktree(&fixture); + cleanup_fixture_worktree(&submodule); } void test_worktree_config__open(void) @@ -46,6 +50,31 @@ void test_worktree_config__set_level_local(void) git_config_free(cfg); } +void test_worktree_config__requires_extension(void) +{ + git_config *cfg; + git_config *wtcfg; + int extension = 0; + + /* + * the "submodules" repo does not have extensions.worktreeconfig + * set, the worktree configuration should not be available. + */ + cl_git_pass(git_repository_config(&cfg, submodule.repo)); + cl_git_fail_with(GIT_ENOTFOUND, git_config_get_bool(&extension, cfg, "extensions.worktreeconfig")); + cl_assert_equal_i(0, extension); + cl_git_fail_with(GIT_ENOTFOUND, git_config_open_level(&wtcfg, cfg, GIT_CONFIG_LEVEL_WORKTREE)); + git_config_free(cfg); + + /* the "testrepo" repo does have the configuration set. */ + cl_git_pass(git_repository_config(&cfg, fixture.repo)); + cl_git_pass(git_config_get_bool(&extension, cfg, "extensions.worktreeconfig")); + cl_assert_equal_i(1, extension); + cl_git_pass(git_config_open_level(&wtcfg, cfg, GIT_CONFIG_LEVEL_WORKTREE)); + git_config_free(wtcfg); + git_config_free(cfg); +} + void test_worktree_config__set_level_worktree(void) { git_config *cfg; From 3baa6372fd5957ebc8601ee7223118fa19f00ce4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 11 Mar 2024 15:21:12 +0000 Subject: [PATCH 463/816] config: read the individual worktree config Instead of reading the worktree configuration from the commondir, read it from the gitdir. This ensures that each worktree gets its own configuration. --- src/libgit2/repository.c | 2 +- tests/libgit2/worktree/config.c | 22 +++++++++++++++++++ tests/resources/testrepo/.gitted/config | 2 ++ .../testrepo/.gitted/config.worktree | 2 ++ .../testrepo-worktree/config.worktree | 2 ++ 5 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/resources/testrepo/.gitted/config.worktree create mode 100644 tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/config.worktree diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 124ec3672ab..09b74df4a6e 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -58,7 +58,7 @@ static const struct { { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "packed-refs", false }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "remotes", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config", false }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config.worktree", false }, + { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM_GITDIR, "config.worktree", false }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "info", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "hooks", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "logs", true }, diff --git a/tests/libgit2/worktree/config.c b/tests/libgit2/worktree/config.c index dee8e0c06d6..1fd1f75b47b 100644 --- a/tests/libgit2/worktree/config.c +++ b/tests/libgit2/worktree/config.c @@ -75,6 +75,28 @@ void test_worktree_config__requires_extension(void) git_config_free(cfg); } +void test_worktree_config__exists(void) +{ + git_config *cfg, *wtcfg, *snap; + const char *str; + + cl_git_pass(git_repository_config(&cfg, fixture.repo)); + cl_git_pass(git_repository_config(&wtcfg, fixture.worktree)); + + cl_git_pass(git_config_snapshot(&snap, cfg)); + cl_git_pass(git_config_get_string(&str, snap, "worktreetest.config")); + cl_assert_equal_s("mainrepo", str); + git_config_free(snap); + + cl_git_pass(git_config_snapshot(&snap, wtcfg)); + cl_git_pass(git_config_get_string(&str, snap, "worktreetest.config")); + cl_assert_equal_s("worktreerepo", str); + git_config_free(snap); + + git_config_free(cfg); + git_config_free(wtcfg); +} + void test_worktree_config__set_level_worktree(void) { git_config *cfg; diff --git a/tests/resources/testrepo/.gitted/config b/tests/resources/testrepo/.gitted/config index d0114012f98..04d750a93bc 100644 --- a/tests/resources/testrepo/.gitted/config +++ b/tests/resources/testrepo/.gitted/config @@ -3,6 +3,8 @@ filemode = true bare = false logallrefupdates = true +[extensions] + worktreeconfig = true [remote "test"] url = git://github.com/libgit2/libgit2 fetch = +refs/heads/*:refs/remotes/test/* diff --git a/tests/resources/testrepo/.gitted/config.worktree b/tests/resources/testrepo/.gitted/config.worktree new file mode 100644 index 00000000000..df9f0caf650 --- /dev/null +++ b/tests/resources/testrepo/.gitted/config.worktree @@ -0,0 +1,2 @@ +[worktreetest] + config = mainrepo diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/config.worktree b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/config.worktree new file mode 100644 index 00000000000..7a130a7aed7 --- /dev/null +++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/config.worktree @@ -0,0 +1,2 @@ +[worktreetest] + config = worktreerepo From b454eba9a717919bb5b43d3b2b70bcd54ca5f3e6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 11 Mar 2024 21:07:21 +0000 Subject: [PATCH 464/816] errors: introduce GIT_ENOTSUPPORTED libgit2 lacks many of the things that git supports. Give a reasonable error code for these cases. --- include/git2/errors.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index bdace8c43dd..2e007ecb55e 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -60,7 +60,8 @@ typedef enum { GIT_EAPPLYFAIL = -35, /**< Patch application failed */ GIT_EOWNER = -36, /**< The object is not owned by the current user */ GIT_TIMEOUT = -37, /**< The operation timed out */ - GIT_EUNCHANGED = -38 /**< There were no changes */ + GIT_EUNCHANGED = -38, /**< There were no changes */ + GIT_ENOTSUPPORTED = -39 /**< An option is not supported */ } git_error_code; /** From b8f3dae325fb257f14404979b837aef374a8a497 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 11 Mar 2024 21:07:46 +0000 Subject: [PATCH 465/816] fetch: fail on depth for local transport We don't support shallow clones for the local transport, currently. Fail, instead of silently ignoring the depth option. --- src/libgit2/transports/local.c | 5 +++++ tests/libgit2/clone/local.c | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/libgit2/transports/local.c b/src/libgit2/transports/local.c index 64c21afbd0d..fe59bcab0c1 100644 --- a/src/libgit2/transports/local.c +++ b/src/libgit2/transports/local.c @@ -303,6 +303,11 @@ static int local_negotiate_fetch( GIT_UNUSED(wants); + if (wants->depth) { + git_error_set(GIT_ERROR_NET, "shallow fetch is not supported by the local transport"); + return GIT_ENOTSUPPORTED; + } + /* Fill in the loids */ git_vector_foreach(&t->refs, i, rhead) { git_object *obj; diff --git a/tests/libgit2/clone/local.c b/tests/libgit2/clone/local.c index e0bd74df78a..a89b2343759 100644 --- a/tests/libgit2/clone/local.c +++ b/tests/libgit2/clone/local.c @@ -210,3 +210,14 @@ void test_clone_local__git_style_unc_paths(void) cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES)); #endif } + +void test_clone_local__shallow_fails(void) +{ + git_repository *repo; + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + + opts.fetch_opts.depth = 4; + + cl_git_fail_with(GIT_ENOTSUPPORTED, git_clone(&repo, cl_fixture("testrepo.git"), "./clone.git", &opts)); + git_repository_free(repo); +} From 2625ed24b9a4b0cd0dedbb3327fddf773893a486 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 13 Mar 2024 17:20:11 -0400 Subject: [PATCH 466/816] Initial implementation. --- src/libgit2/streams/mbedtls.c | 36 ++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index 49aa76c3ed8..c875a2f50e8 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -32,7 +32,6 @@ # endif #endif -#include #include #include #include @@ -54,10 +53,17 @@ static mbedtls_entropy_context *mbedtls_entropy; static void shutdown_ssl(void) { if (git__ssl_conf) { - mbedtls_x509_crt_free(git__ssl_conf->ca_chain); - git__free(git__ssl_conf->ca_chain); - mbedtls_ctr_drbg_free(git__ssl_conf->p_rng); - git__free(git__ssl_conf->p_rng); + #if MBEDTLS_VERSION_MAJOR >= 3 + mbedtls_x509_crt_free(git__ssl_conf->private_ca_chain); + git__free(git__ssl_conf->private_ca_chain); + mbedtls_ctr_drbg_free(git__ssl_conf->private_p_rng); + git__free(git__ssl_conf->private_p_rng); + #else + mbedtls_x509_crt_free(git__ssl_conf->ca_chain); + git__free(git__ssl_conf->ca_chain); + mbedtls_ctr_drbg_free(git__ssl_conf->p_rng); + git__free(git__ssl_conf->p_rng); + #endif mbedtls_ssl_config_free(git__ssl_conf); git__free(git__ssl_conf); git__ssl_conf = NULL; @@ -94,7 +100,10 @@ int git_mbedtls_stream_global_init(void) } /* configure TLSv1 */ - mbedtls_ssl_conf_min_version(git__ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); + #if MBEDTLS_VERSION_MAJOR < 3 + /* SSLv3 is not included in mbedtls3 */ + mbedtls_ssl_conf_min_version(git__ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); + #endif /* verify_server_cert is responsible for making the check. * OPTIONAL because REQUIRED drops the certificate as soon as the check @@ -192,7 +201,11 @@ static int ssl_set_error(mbedtls_ssl_context *ssl, int error) break; case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: - git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, ssl->session_negotiate->verify_result, errbuf); + #ifdef MBEDTLS_VERSION_MAJOR >= 3 + git_error_set(GIT_ERROR_SSL, "SSL error: %#04x - %s", error, errbuf); + #else + git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, ssl->session_negotiate->verify_result, errbuf); + #endif ret = GIT_ECERTIFICATE; break; @@ -462,8 +475,13 @@ int git_mbedtls__set_cert_location(const char *file, const char *path) return -1; } - mbedtls_x509_crt_free(git__ssl_conf->ca_chain); - git__free(git__ssl_conf->ca_chain); + #if MBEDTLS_VERSION_MAJOR >= 3 + mbedtls_x509_crt_free(git__ssl_conf->private_ca_chain); + git__free(git__ssl_conf->private_ca_chain); + #else + mbedtls_x509_crt_free(git__ssl_conf->ca_chain); + git__free(git__ssl_conf->ca_chain); + #endif mbedtls_ssl_conf_ca_chain(git__ssl_conf, cacert, NULL); return 0; From 5934779ae0aa1c66def5153c8a4628c65e5b0fc0 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 13 Mar 2024 17:35:39 -0400 Subject: [PATCH 467/816] Restored verify result report. --- src/libgit2/streams/mbedtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index c875a2f50e8..f2ce411abd7 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -201,8 +201,8 @@ static int ssl_set_error(mbedtls_ssl_context *ssl, int error) break; case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: - #ifdef MBEDTLS_VERSION_MAJOR >= 3 - git_error_set(GIT_ERROR_SSL, "SSL error: %#04x - %s", error, errbuf); + #if MBEDTLS_VERSION_MAJOR >= 3 + git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, mbedtls_ssl_get_verify_result(ssl), errbuf); #else git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, ssl->session_negotiate->verify_result, errbuf); #endif From fdaf373c0e50555c16e97f5ae41db8571fcc3ba6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Mar 2024 11:27:36 +0000 Subject: [PATCH 468/816] trailer: test actual array equivalence We never test the lengths of the two arrays, so a short return from `git_message_trailers` will match erroneously. --- tests/libgit2/message/trailer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/libgit2/message/trailer.c b/tests/libgit2/message/trailer.c index 919e10a499c..3705794fbdb 100644 --- a/tests/libgit2/message/trailer.c +++ b/tests/libgit2/message/trailer.c @@ -3,19 +3,22 @@ static void assert_trailers(const char *message, git_message_trailer *trailers) { git_message_trailer_array arr; - size_t i; + size_t i, count; int rc = git_message_trailers(&arr, message); cl_assert_equal_i(0, rc); - for(i=0; i Date: Thu, 14 Mar 2024 11:28:20 +0000 Subject: [PATCH 469/816] trailer: ensure we identify patch lines like git Git looks explicitly for `---` followed by whitespace (`isspace()`) to determine when a patch line begins in a commit message. Match that behavior. This ensures that we don't treat (say) `----` as a patch line incorrectly. --- src/libgit2/trailer.c | 2 +- tests/libgit2/message/trailer.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/libgit2/trailer.c b/src/libgit2/trailer.c index 4761c9922f2..52e655914b0 100644 --- a/src/libgit2/trailer.c +++ b/src/libgit2/trailer.c @@ -158,7 +158,7 @@ static size_t find_patch_start(const char *str) const char *s; for (s = str; *s; s = next_line(s)) { - if (git__prefixcmp(s, "---") == 0) + if (git__prefixcmp(s, "---") == 0 && git__isspace(s[3])) return s - str; } diff --git a/tests/libgit2/message/trailer.c b/tests/libgit2/message/trailer.c index 3705794fbdb..09e8f6115a7 100644 --- a/tests/libgit2/message/trailer.c +++ b/tests/libgit2/message/trailer.c @@ -165,3 +165,23 @@ void test_message_trailer__invalid(void) "Another: trailer\n" , trailers); } + +void test_message_trailer__ignores_dashes(void) +{ + git_message_trailer trailers[] = { + { "Signed-off-by", "some@one.com" }, + { "Another", "trailer" }, + { NULL, NULL }, + }; + + assert_trailers( + "Message\n" + "\n" + "Markdown header\n" + "---------------\n" + "Lorem ipsum\n" + "\n" + "Signed-off-by: some@one.com\n" + "Another: trailer\n" + , trailers); +} From 4c9353227b039bc4e7532df60031bbd5900b8352 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Mar 2024 19:20:18 +0000 Subject: [PATCH 470/816] tests: don't free an unininitialized repo --- tests/libgit2/clone/local.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/libgit2/clone/local.c b/tests/libgit2/clone/local.c index a89b2343759..d35fe86b27e 100644 --- a/tests/libgit2/clone/local.c +++ b/tests/libgit2/clone/local.c @@ -219,5 +219,4 @@ void test_clone_local__shallow_fails(void) opts.fetch_opts.depth = 4; cl_git_fail_with(GIT_ENOTSUPPORTED, git_clone(&repo, cl_fixture("testrepo.git"), "./clone.git", &opts)); - git_repository_free(repo); } From 53978e678455e0cdcd7f77b242b34450d2169706 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 11:04:36 +0000 Subject: [PATCH 471/816] ci: reduce ASLR randomization for TSAN Linux updated its ASLR randomization in a way that is incompatible with TSAN. See https://github.com/google/sanitizers/issues/1716 Reducing the randomness for ASLR allows the sanitizers to cope. --- .github/workflows/main.yml | 10 +++++++--- .github/workflows/nightly.yml | 9 ++++++--- ci/setup-sanitizer-build.sh | 7 +++++++ 3 files changed, 20 insertions(+), 6 deletions(-) create mode 100755 ci/setup-sanitizer-build.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index accb042e463..284b40358f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,6 +65,7 @@ jobs: - name: "macOS" id: macos os: macos-12 + setup-script: osx env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON @@ -72,7 +73,6 @@ jobs: PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - setup-script: osx - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs os: windows-2019 @@ -125,6 +125,8 @@ jobs: # All builds: sanitizers - name: "Sanitizer (Memory)" id: sanitizer-memory + os: ubuntu-latest + setup-script: sanitizer container: name: noble env: @@ -136,9 +138,10 @@ jobs: SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 - os: ubuntu-latest - name: "Sanitizer (Address)" id: sanitizer-address + os: ubuntu-latest + setup-script: sanitizer container: name: noble env: @@ -150,10 +153,10 @@ jobs: SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 - os: ubuntu-latest - name: "Sanitizer (UndefinedBehavior)" id: sanitizer-ub os: ubuntu-latest + setup-script: sanitizer container: name: noble env: @@ -168,6 +171,7 @@ jobs: - name: "Sanitizer (Thread)" id: sanitizer-thread os: ubuntu-latest + setup-script: sanitizer container: name: noble env: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 25249e7440d..779f66f586e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -66,6 +66,7 @@ jobs: - name: "macOS" id: macos os: macos-12 + setup-script: osx env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON @@ -73,7 +74,6 @@ jobs: PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - setup-script: osx - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs os: windows-2019 @@ -126,6 +126,8 @@ jobs: # All builds: sanitizers - name: "Sanitizer (Memory)" id: memorysanitizer + os: ubuntu-latest + setup-script: sanitizer container: name: noble env: @@ -137,10 +139,10 @@ jobs: SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 - os: ubuntu-latest - name: "Sanitizer (UndefinedBehavior)" id: ubsanitizer os: ubuntu-latest + setup-script: sanitizer container: name: noble env: @@ -155,6 +157,7 @@ jobs: - name: "Sanitizer (Thread)" id: threadsanitizer os: ubuntu-latest + setup-script: sanitizer container: name: noble env: @@ -330,13 +333,13 @@ jobs: - name: "macOS (SHA256)" id: macos os: macos-12 + setup-script: osx env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - setup-script: osx - name: "Windows (SHA256, amd64, Visual Studio)" id: windows-amd64-vs os: windows-2019 diff --git a/ci/setup-sanitizer-build.sh b/ci/setup-sanitizer-build.sh new file mode 100755 index 00000000000..e4591f85bec --- /dev/null +++ b/ci/setup-sanitizer-build.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +set -ex + +# Linux updated its ASLR randomization in a way that is incompatible with +# TSAN. See https://github.com/google/sanitizers/issues/1716 +sudo sysctl vm.mmap_rnd_bits=28 From b70dd1270614fef64b11bda4e55d71c96a687a88 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 Mar 2024 11:07:31 +0000 Subject: [PATCH 472/816] packbuilder: adjust nondeterministic tests The packbuilder tests should be deterministic. This comment suggests that they are: ``` /* * By default, packfiles are created with only one thread. * Therefore we can predict the object ordering and make sure * we create exactly the same pack as git.git does when *not* * reusing existing deltas (as libgit2). * * $ cd tests/resources/testrepo.git * $ git rev-list --objects HEAD | \ * git pack-objects -q --no-reuse-delta --threads=1 pack * $ sha1sum pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack * 5d410bdf97cf896f9007681b92868471d636954b * */ ``` but it is disappointingly incorrect. As is evidenced by the fact that -- at least on _my_ machine -- that command does not actually produce that output any longer. Variations in things like the which compression library is actually used, and its defaults, mean that we cannot accurately predict or enforce the bytes in the packfile from one system to another. Adjust the tests so that they do not believe that they should enforce the bytes in the packfile. This allows broader compatibility with zlib-compatible compression libraries, or other compression levels. --- tests/libgit2/pack/packbuilder.c | 70 ++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/tests/libgit2/pack/packbuilder.c b/tests/libgit2/pack/packbuilder.c index ff3dc1f68aa..7da3877e451 100644 --- a/tests/libgit2/pack/packbuilder.c +++ b/tests/libgit2/pack/packbuilder.c @@ -98,9 +98,6 @@ void test_pack_packbuilder__create_pack(void) { git_indexer_progress stats; git_str buf = GIT_STR_INIT, path = GIT_STR_INIT; - git_hash_ctx ctx; - unsigned char hash[GIT_HASH_SHA1_SIZE]; - char hex[(GIT_HASH_SHA1_SIZE * 2) + 1]; seed_packbuilder(); @@ -114,33 +111,13 @@ void test_pack_packbuilder__create_pack(void) cl_git_pass(git_indexer_commit(_indexer, &stats)); git_str_printf(&path, "pack-%s.pack", git_indexer_name(_indexer)); - - /* - * By default, packfiles are created with only one thread. - * Therefore we can predict the object ordering and make sure - * we create exactly the same pack as git.git does when *not* - * reusing existing deltas (as libgit2). - * - * $ cd tests/resources/testrepo.git - * $ git rev-list --objects HEAD | \ - * git pack-objects -q --no-reuse-delta --threads=1 pack - * $ sha1sum pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack - * 5d410bdf97cf896f9007681b92868471d636954b - * - */ + cl_assert(git_fs_path_exists(path.ptr)); cl_git_pass(git_futils_readbuffer(&buf, git_str_cstr(&path))); - - cl_git_pass(git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1)); - cl_git_pass(git_hash_update(&ctx, buf.ptr, buf.size)); - cl_git_pass(git_hash_final(hash, &ctx)); - git_hash_ctx_cleanup(&ctx); + cl_assert(buf.size > 256); git_str_dispose(&path); git_str_dispose(&buf); - - git_hash_fmt(hex, hash, GIT_HASH_SHA1_SIZE); - cl_assert_equal_s(hex, "5d410bdf97cf896f9007681b92868471d636954b"); } void test_pack_packbuilder__get_name(void) @@ -148,22 +125,49 @@ void test_pack_packbuilder__get_name(void) seed_packbuilder(); cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL)); - cl_assert_equal_s("7f5fa362c664d68ba7221259be1cbd187434b2f0", git_packbuilder_name(_packbuilder)); + cl_assert(git_packbuilder_name(_packbuilder) != NULL); +} + +static void get_packfile_path(git_str *out, git_packbuilder *pb) +{ + git_str_puts(out, "pack-"); + git_str_puts(out, git_packbuilder_name(pb)); + git_str_puts(out, ".pack"); +} + +static void get_index_path(git_str *out, git_packbuilder *pb) +{ + git_str_puts(out, "pack-"); + git_str_puts(out, git_packbuilder_name(pb)); + git_str_puts(out, ".idx"); } void test_pack_packbuilder__write_default_path(void) { + git_str idx = GIT_STR_INIT, pack = GIT_STR_INIT; + seed_packbuilder(); cl_git_pass(git_packbuilder_write(_packbuilder, NULL, 0, NULL, NULL)); - cl_assert(git_fs_path_exists("objects/pack/pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.idx")); - cl_assert(git_fs_path_exists("objects/pack/pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack")); + + git_str_puts(&idx, "objects/pack/"); + get_index_path(&idx, _packbuilder); + + git_str_puts(&pack, "objects/pack/"); + get_packfile_path(&pack, _packbuilder); + + cl_assert(git_fs_path_exists(idx.ptr)); + cl_assert(git_fs_path_exists(pack.ptr)); + + git_str_dispose(&idx); + git_str_dispose(&pack); } static void test_write_pack_permission(mode_t given, mode_t expected) { struct stat statbuf; mode_t mask, os_mask; + git_str idx = GIT_STR_INIT, pack = GIT_STR_INIT; seed_packbuilder(); @@ -181,11 +185,17 @@ static void test_write_pack_permission(mode_t given, mode_t expected) mask = p_umask(0); p_umask(mask); - cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.idx", &statbuf)); + get_index_path(&idx, _packbuilder); + get_packfile_path(&pack, _packbuilder); + + cl_git_pass(p_stat(idx.ptr, &statbuf)); cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask); - cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack", &statbuf)); + cl_git_pass(p_stat(pack.ptr, &statbuf)); cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask); + + git_str_dispose(&idx); + git_str_dispose(&pack); } void test_pack_packbuilder__permissions_standard(void) From 594063935b3bd3a419b66ae24c99d041eb95f3a6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 14:31:55 +0000 Subject: [PATCH 473/816] cli: use libgit2 system includes libgit2 may adjust the system includes - for example, to locate a dependency installed in a funny location. Ensure that the cli understands those include paths as well. --- src/cli/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 84b6c190151..97797e33bd9 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -4,7 +4,8 @@ set(CLI_INCLUDES "${libgit2_SOURCE_DIR}/src/util" "${libgit2_SOURCE_DIR}/src/cli" "${libgit2_SOURCE_DIR}/include" - "${LIBGIT2_DEPENDENCY_INCLUDES}") + "${LIBGIT2_DEPENDENCY_INCLUDES}" + "${LIBGIT2_SYSTEM_INCLUDES}") if(WIN32 AND NOT CYGWIN) file(GLOB CLI_SRC_OS win32/*.c) From 079861729b55a43366a59cb6922bee6f6975d982 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 14:32:54 +0000 Subject: [PATCH 474/816] build: update ntlmclient dependency The ntlmclient dependency now bundles an MD4 implementation for compatibility with newer mbedTLS. Include that so that we can support mbedTLS 3. --- deps/ntlmclient/CMakeLists.txt | 2 +- deps/ntlmclient/crypt_builtin_md4.c | 311 ++++++++++++++++++++++++++++ deps/ntlmclient/crypt_mbedtls.c | 20 -- 3 files changed, 312 insertions(+), 21 deletions(-) create mode 100644 deps/ntlmclient/crypt_builtin_md4.c diff --git a/deps/ntlmclient/CMakeLists.txt b/deps/ntlmclient/CMakeLists.txt index 8356d472367..f1f5de162a0 100644 --- a/deps/ntlmclient/CMakeLists.txt +++ b/deps/ntlmclient/CMakeLists.txt @@ -31,7 +31,7 @@ elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") elseif(USE_HTTPS STREQUAL "mbedTLS") add_definitions(-DCRYPT_MBEDTLS) include_directories(${MBEDTLS_INCLUDE_DIR}) - set(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c" "crypt_mbedtls.h") + set(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c" "crypt_mbedtls.h" "crypt_builtin_md4.c") else() message(FATAL_ERROR "Unable to use libgit2's HTTPS backend (${USE_HTTPS}) for NTLM crypto") endif() diff --git a/deps/ntlmclient/crypt_builtin_md4.c b/deps/ntlmclient/crypt_builtin_md4.c new file mode 100644 index 00000000000..de9a85cafaa --- /dev/null +++ b/deps/ntlmclient/crypt_builtin_md4.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) Edward Thomson. All rights reserved. + * + * This file is part of ntlmclient, distributed under the MIT license. + * For full terms and copyright information, and for third-party + * copyright information, see the included LICENSE.txt file. + */ + +#include +#include + +#include "ntlm.h" +#include "crypt.h" + +/* + * Below is the MD4 code from RFC 1320, with minor modifications + * to make it compile on a modern compiler. It is included since + * many system crypto libraries lack MD4, sensibly. + */ + +/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm + */ + +/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD4 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD4 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef uint16_t UINT2; + +/* UINT4 defines a four byte word */ +typedef uint32_t UINT4; + +#define MD4_memcpy memcpy +#define MD4_memset memset + +/* MD4 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD4_CTX; + +/* Constants for MD4Transform routine. + */ +#define S11 3 +#define S12 7 +#define S13 11 +#define S14 19 +#define S21 3 +#define S22 5 +#define S23 9 +#define S24 13 +#define S31 3 +#define S32 9 +#define S33 11 +#define S34 15 + +static void MD4Transform(UINT4 [4], const unsigned char [64]); +static void Encode (unsigned char *, UINT4 *, unsigned int); +static void Decode (UINT4 *, const unsigned char *, unsigned int); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G and H are basic MD4 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s) { \ + (a) += F ((b), (c), (d)) + (x); \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define GG(a, b, c, d, x, s) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define HH(a, b, c, d, x, s) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + +/* MD4 initialization. Begins an MD4 operation, writing a new context. + */ +static void MD4Init (MD4_CTX *context) +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD4 block update operation. Continues an MD4 message-digest + operation, processing another message block, and updating the + context. + */ +static void MD4Update (MD4_CTX *context, const unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. + */ + if (inputLen >= partLen) { + MD4_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD4Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD4Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD4_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD4 finalization. Ends an MD4 message-digest operation, writing the + the message digest and zeroizing the context. + */ +static void MD4Final (unsigned char digest[16], MD4_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD4Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD4Update (context, bits, 8); + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + */ + MD4_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD4 basic transformation. Transforms state based on block. + */ +static void MD4Transform (UINT4 state[4], const unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11); /* 1 */ + FF (d, a, b, c, x[ 1], S12); /* 2 */ + FF (c, d, a, b, x[ 2], S13); /* 3 */ + FF (b, c, d, a, x[ 3], S14); /* 4 */ + FF (a, b, c, d, x[ 4], S11); /* 5 */ + FF (d, a, b, c, x[ 5], S12); /* 6 */ + FF (c, d, a, b, x[ 6], S13); /* 7 */ + FF (b, c, d, a, x[ 7], S14); /* 8 */ + FF (a, b, c, d, x[ 8], S11); /* 9 */ + FF (d, a, b, c, x[ 9], S12); /* 10 */ + FF (c, d, a, b, x[10], S13); /* 11 */ + FF (b, c, d, a, x[11], S14); /* 12 */ + FF (a, b, c, d, x[12], S11); /* 13 */ + FF (d, a, b, c, x[13], S12); /* 14 */ + FF (c, d, a, b, x[14], S13); /* 15 */ + FF (b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 0], S21); /* 17 */ + GG (d, a, b, c, x[ 4], S22); /* 18 */ + GG (c, d, a, b, x[ 8], S23); /* 19 */ + GG (b, c, d, a, x[12], S24); /* 20 */ + GG (a, b, c, d, x[ 1], S21); /* 21 */ + GG (d, a, b, c, x[ 5], S22); /* 22 */ + GG (c, d, a, b, x[ 9], S23); /* 23 */ + GG (b, c, d, a, x[13], S24); /* 24 */ + GG (a, b, c, d, x[ 2], S21); /* 25 */ + GG (d, a, b, c, x[ 6], S22); /* 26 */ + GG (c, d, a, b, x[10], S23); /* 27 */ + GG (b, c, d, a, x[14], S24); /* 28 */ + GG (a, b, c, d, x[ 3], S21); /* 29 */ + GG (d, a, b, c, x[ 7], S22); /* 30 */ + GG (c, d, a, b, x[11], S23); /* 31 */ + GG (b, c, d, a, x[15], S24); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 0], S31); /* 33 */ + HH (d, a, b, c, x[ 8], S32); /* 34 */ + HH (c, d, a, b, x[ 4], S33); /* 35 */ + HH (b, c, d, a, x[12], S34); /* 36 */ + HH (a, b, c, d, x[ 2], S31); /* 37 */ + HH (d, a, b, c, x[10], S32); /* 38 */ + HH (c, d, a, b, x[ 6], S33); /* 39 */ + HH (b, c, d, a, x[14], S34); /* 40 */ + HH (a, b, c, d, x[ 1], S31); /* 41 */ + HH (d, a, b, c, x[ 9], S32); /* 42 */ + HH (c, d, a, b, x[ 5], S33); /* 43 */ + HH (b, c, d, a, x[13], S34); /* 44 */ + HH (a, b, c, d, x[ 3], S31); /* 45 */ + HH (d, a, b, c, x[11], S32); /* 46 */ + HH (c, d, a, b, x[ 7], S33); /* 47 */ + HH (b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + MD4_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (unsigned char *output, UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (UINT4 *output, const unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +bool ntlm_md4_digest( + unsigned char out[CRYPT_MD4_DIGESTSIZE], + ntlm_client *ntlm, + const unsigned char *in, + size_t in_len) +{ + MD4_CTX ctx; + + NTLM_UNUSED(ntlm); + + if (in_len > UINT_MAX) + return false; + + MD4Init(&ctx); + MD4Update(&ctx, in, (unsigned int)in_len); + MD4Final (out, &ctx); + + return true; +} diff --git a/deps/ntlmclient/crypt_mbedtls.c b/deps/ntlmclient/crypt_mbedtls.c index 6283c3eec08..4bbb878015d 100644 --- a/deps/ntlmclient/crypt_mbedtls.c +++ b/deps/ntlmclient/crypt_mbedtls.c @@ -12,7 +12,6 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/des.h" #include "mbedtls/entropy.h" -#include "mbedtls/md4.h" #include "ntlm.h" #include "crypt.h" @@ -88,25 +87,6 @@ bool ntlm_des_encrypt( return success; } -bool ntlm_md4_digest( - unsigned char out[CRYPT_MD4_DIGESTSIZE], - ntlm_client *ntlm, - const unsigned char *in, - size_t in_len) -{ - mbedtls_md4_context ctx; - - NTLM_UNUSED(ntlm); - - mbedtls_md4_init(&ctx); - mbedtls_md4_starts(&ctx); - mbedtls_md4_update(&ctx, in, in_len); - mbedtls_md4_finish(&ctx, out); - mbedtls_md4_free(&ctx); - - return true; -} - bool ntlm_hmac_md5_init( ntlm_client *ntlm, const unsigned char *key, From 3266fc4938cce5f4251b7a055cbb4ff099d090a3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 14:57:06 +0000 Subject: [PATCH 475/816] mbedtls: keep track of what we allocate, then free it Instead of trying to allocate something, hand it to mbedTLS, and then peer into its private data structures to try to free that thing... we could just keep track of it ourselves. Once we've done that, we needn't do an allocation _anyway_, we can just keep it on the stack. --- src/libgit2/streams/mbedtls.c | 128 ++++++++++++++-------------------- 1 file changed, 52 insertions(+), 76 deletions(-) diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index f2ce411abd7..1b2780706c6 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -42,9 +42,15 @@ #define GIT_SSL_DEFAULT_CIPHERS "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-DSS-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-DSS-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-DSS-WITH-AES-128-CBC-SHA256:TLS-DHE-DSS-WITH-AES-256-CBC-SHA256:TLS-DHE-DSS-WITH-AES-128-CBC-SHA:TLS-DHE-DSS-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-AES-128-GCM-SHA256:TLS-RSA-WITH-AES-256-GCM-SHA384:TLS-RSA-WITH-AES-128-CBC-SHA256:TLS-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA" #define GIT_SSL_DEFAULT_CIPHERS_COUNT 30 -static mbedtls_ssl_config *git__ssl_conf; static int ciphers_list[GIT_SSL_DEFAULT_CIPHERS_COUNT]; -static mbedtls_entropy_context *mbedtls_entropy; + +static bool initialized = false; +static mbedtls_ssl_config mbedtls_config; +static mbedtls_ctr_drbg_context mbedtls_rng; +static mbedtls_entropy_context mbedtls_entropy; + +static bool has_ca_chain = false; +static mbedtls_x509_crt mbedtls_ca_chain; /** * This function aims to clean-up the SSL context which @@ -52,26 +58,16 @@ static mbedtls_entropy_context *mbedtls_entropy; */ static void shutdown_ssl(void) { - if (git__ssl_conf) { - #if MBEDTLS_VERSION_MAJOR >= 3 - mbedtls_x509_crt_free(git__ssl_conf->private_ca_chain); - git__free(git__ssl_conf->private_ca_chain); - mbedtls_ctr_drbg_free(git__ssl_conf->private_p_rng); - git__free(git__ssl_conf->private_p_rng); - #else - mbedtls_x509_crt_free(git__ssl_conf->ca_chain); - git__free(git__ssl_conf->ca_chain); - mbedtls_ctr_drbg_free(git__ssl_conf->p_rng); - git__free(git__ssl_conf->p_rng); - #endif - mbedtls_ssl_config_free(git__ssl_conf); - git__free(git__ssl_conf); - git__ssl_conf = NULL; + if (has_ca_chain) { + mbedtls_x509_crt_free(&mbedtls_ca_chain); + has_ca_chain = false; } - if (mbedtls_entropy) { - mbedtls_entropy_free(mbedtls_entropy); - git__free(mbedtls_entropy); - mbedtls_entropy = NULL; + + if (initialized) { + mbedtls_ctr_drbg_free(&mbedtls_rng); + mbedtls_ssl_config_free(&mbedtls_config); + mbedtls_entropy_free(&mbedtls_entropy); + initialized = false; } } @@ -80,35 +76,33 @@ int git_mbedtls_stream_global_init(void) int loaded = 0; char *crtpath = GIT_DEFAULT_CERT_LOCATION; struct stat statbuf; - mbedtls_ctr_drbg_context *ctr_drbg = NULL; size_t ciphers_known = 0; char *cipher_name = NULL; char *cipher_string = NULL; char *cipher_string_tmp = NULL; - git__ssl_conf = git__malloc(sizeof(mbedtls_ssl_config)); - GIT_ERROR_CHECK_ALLOC(git__ssl_conf); + mbedtls_ssl_config_init(&mbedtls_config); + mbedtls_entropy_init(&mbedtls_entropy); + mbedtls_ctr_drbg_init(&mbedtls_rng); - mbedtls_ssl_config_init(git__ssl_conf); - if (mbedtls_ssl_config_defaults(git__ssl_conf, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT) != 0) { + if (mbedtls_ssl_config_defaults(&mbedtls_config, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT) != 0) { git_error_set(GIT_ERROR_SSL, "failed to initialize mbedTLS"); goto cleanup; } - /* configure TLSv1 */ - #if MBEDTLS_VERSION_MAJOR < 3 - /* SSLv3 is not included in mbedtls3 */ - mbedtls_ssl_conf_min_version(git__ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); - #endif + /* configure TLSv1.1 */ +#ifdef MBEDTLS_SSL_MINOR_VERSION_2 + mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); +#endif /* verify_server_cert is responsible for making the check. * OPTIONAL because REQUIRED drops the certificate as soon as the check * is made, so we can never see the certificate and override it. */ - mbedtls_ssl_conf_authmode(git__ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_authmode(&mbedtls_config, MBEDTLS_SSL_VERIFY_OPTIONAL); /* set the list of allowed ciphersuites */ ciphers_known = 0; @@ -132,42 +126,33 @@ int git_mbedtls_stream_global_init(void) git_error_set(GIT_ERROR_SSL, "no cipher could be enabled"); goto cleanup; } - mbedtls_ssl_conf_ciphersuites(git__ssl_conf, ciphers_list); + mbedtls_ssl_conf_ciphersuites(&mbedtls_config, ciphers_list); /* Seeding the random number generator */ - mbedtls_entropy = git__malloc(sizeof(mbedtls_entropy_context)); - GIT_ERROR_CHECK_ALLOC(mbedtls_entropy); - - mbedtls_entropy_init(mbedtls_entropy); - - ctr_drbg = git__malloc(sizeof(mbedtls_ctr_drbg_context)); - GIT_ERROR_CHECK_ALLOC(ctr_drbg); - mbedtls_ctr_drbg_init(ctr_drbg); - - if (mbedtls_ctr_drbg_seed(ctr_drbg, - mbedtls_entropy_func, - mbedtls_entropy, NULL, 0) != 0) { + if (mbedtls_ctr_drbg_seed(&mbedtls_rng, mbedtls_entropy_func, + &mbedtls_entropy, NULL, 0) != 0) { git_error_set(GIT_ERROR_SSL, "failed to initialize mbedTLS entropy pool"); goto cleanup; } - mbedtls_ssl_conf_rng(git__ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg); + mbedtls_ssl_conf_rng(&mbedtls_config, mbedtls_ctr_drbg_random, &mbedtls_rng); /* load default certificates */ if (crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) loaded = (git_mbedtls__set_cert_location(crtpath, NULL) == 0); + if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) loaded = (git_mbedtls__set_cert_location(NULL, crtpath) == 0); + initialized = true; + return git_runtime_shutdown_register(shutdown_ssl); cleanup: - mbedtls_ctr_drbg_free(ctr_drbg); - git__free(ctr_drbg); - mbedtls_ssl_config_free(git__ssl_conf); - git__free(git__ssl_conf); - git__ssl_conf = NULL; + mbedtls_ctr_drbg_free(&mbedtls_rng); + mbedtls_ssl_config_free(&mbedtls_config); + mbedtls_entropy_free(&mbedtls_entropy); return -1; } @@ -201,11 +186,7 @@ static int ssl_set_error(mbedtls_ssl_context *ssl, int error) break; case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: - #if MBEDTLS_VERSION_MAJOR >= 3 - git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, mbedtls_ssl_get_verify_result(ssl), errbuf); - #else - git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, ssl->session_negotiate->verify_result, errbuf); - #endif + git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, mbedtls_ssl_get_verify_result(ssl), errbuf); ret = GIT_ECERTIFICATE; break; @@ -387,7 +368,7 @@ static int mbedtls_stream_wrap( st->ssl = git__malloc(sizeof(mbedtls_ssl_context)); GIT_ERROR_CHECK_ALLOC(st->ssl); mbedtls_ssl_init(st->ssl); - if (mbedtls_ssl_setup(st->ssl, git__ssl_conf)) { + if (mbedtls_ssl_setup(st->ssl, &mbedtls_config)) { git_error_set(GIT_ERROR_SSL, "failed to create ssl object"); error = -1; goto out_err; @@ -454,35 +435,30 @@ int git_mbedtls__set_cert_location(const char *file, const char *path) { int ret = 0; char errbuf[512]; - mbedtls_x509_crt *cacert; GIT_ASSERT_ARG(file || path); - cacert = git__malloc(sizeof(mbedtls_x509_crt)); - GIT_ERROR_CHECK_ALLOC(cacert); + if (has_ca_chain) + mbedtls_x509_crt_free(&mbedtls_ca_chain); + + mbedtls_x509_crt_init(&mbedtls_ca_chain); - mbedtls_x509_crt_init(cacert); if (file) - ret = mbedtls_x509_crt_parse_file(cacert, file); + ret = mbedtls_x509_crt_parse_file(&mbedtls_ca_chain, file); + if (ret >= 0 && path) - ret = mbedtls_x509_crt_parse_path(cacert, path); + ret = mbedtls_x509_crt_parse_path(&mbedtls_ca_chain, path); + /* mbedtls_x509_crt_parse_path returns the number of invalid certs on success */ if (ret < 0) { - mbedtls_x509_crt_free(cacert); - git__free(cacert); + mbedtls_x509_crt_free(&mbedtls_ca_chain); mbedtls_strerror( ret, errbuf, 512 ); git_error_set(GIT_ERROR_SSL, "failed to load CA certificates: %#04x - %s", ret, errbuf); return -1; } - #if MBEDTLS_VERSION_MAJOR >= 3 - mbedtls_x509_crt_free(git__ssl_conf->private_ca_chain); - git__free(git__ssl_conf->private_ca_chain); - #else - mbedtls_x509_crt_free(git__ssl_conf->ca_chain); - git__free(git__ssl_conf->ca_chain); - #endif - mbedtls_ssl_conf_ca_chain(git__ssl_conf, cacert, NULL); + mbedtls_ssl_conf_ca_chain(&mbedtls_config, &mbedtls_ca_chain, NULL); + has_ca_chain = true; return 0; } From 58dfe647b7cb474661f5f5a6f072efc929cecf03 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 16:38:44 +0000 Subject: [PATCH 476/816] build: update to latest actions versions --- .github/workflows/benchmark.yml | 6 +++--- .github/workflows/build-containers.yml | 2 +- .github/workflows/main.yml | 14 +++++++------- .github/workflows/nightly.yml | 14 +++++++------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 831ffbb8235..51a5fc1c083 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -54,7 +54,7 @@ jobs: runs-on: ${{ matrix.platform.os }} steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 @@ -79,7 +79,7 @@ jobs: ../source/tests/benchmarks/benchmark.sh --baseline-cli "git" --cli "${GIT2_CLI}" --name libgit2 --json benchmarks.json --zip benchmarks.zip shell: bash - name: Upload results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: benchmark-${{ matrix.platform.id }} path: benchmark @@ -93,7 +93,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out benchmark repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: libgit2/benchmarks path: site diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 56ac66a9016..5518548c6c3 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -44,7 +44,7 @@ jobs: name: "Create container: ${{ matrix.container.name }}" steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 284b40358f1..236a7d13bb6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -187,7 +187,7 @@ jobs: # All builds: experimental SHA256 support - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" - id: xenial-clang-openssl + id: linux-sha256 os: ubuntu-latest container: name: xenial @@ -196,7 +196,7 @@ jobs: CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON - name: "macOS (SHA256)" - id: macos + id: macos-sha256 os: macos-12 setup-script: osx env: @@ -207,7 +207,7 @@ jobs: SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - name: "Windows (SHA256, amd64, Visual Studio)" - id: windows-amd64-vs + id: windows-sha256 os: windows-2019 env: ARCH: amd64 @@ -221,7 +221,7 @@ jobs: name: "Build: ${{ matrix.platform.name }}" steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 @@ -258,7 +258,7 @@ jobs: container-version: ${{ env.docker-registry-container-sha }} shell: ${{ matrix.platform.shell }} - name: Upload test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: success() || failure() with: name: test-results-${{ matrix.platform.id }} @@ -289,7 +289,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 @@ -316,7 +316,7 @@ jobs: cm doc api.docurium git checkout gh-pages zip --exclude .git/\* --exclude .gitignore --exclude .gitattributes -r api-documentation.zip . - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 name: Upload artifact with: name: api-documentation diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 779f66f586e..570b9aa6ab6 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -322,7 +322,7 @@ jobs: # All builds: experimental SHA256 support - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" - id: xenial-clang-openssl + id: linux-sha256 container: name: xenial env: @@ -331,7 +331,7 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON os: ubuntu-latest - name: "macOS (SHA256)" - id: macos + id: macos-sha256 os: macos-12 setup-script: osx env: @@ -341,7 +341,7 @@ jobs: SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - name: "Windows (SHA256, amd64, Visual Studio)" - id: windows-amd64-vs + id: windows-sha256 os: windows-2019 env: ARCH: amd64 @@ -355,7 +355,7 @@ jobs: name: "Build ${{ matrix.platform.name }}" steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 @@ -392,7 +392,7 @@ jobs: container-version: ${{ env.docker-registry-container-sha }} shell: ${{ matrix.platform.shell }} - name: Upload test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: success() || failure() with: name: test-results-${{ matrix.platform.id }} @@ -420,7 +420,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 @@ -451,7 +451,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 From cc7764f6a69c4b01c6e5e0b19e4177afb93d0620 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 17 Mar 2024 14:11:40 +0000 Subject: [PATCH 477/816] config: correct fetching the HIGHEST_LEVEL config Also, add a test for fetching the `GIT_CONFIG_HIGHEST_LEVEL`. --- src/libgit2/config.c | 26 ++++++-------------------- tests/libgit2/config/configlevel.c | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 21b9666db33..67ce6573801 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -241,7 +241,7 @@ static int find_backend_by_level( return GIT_ENOTFOUND; } - *out = entry->instance; + *out = found->instance; return 0; } @@ -430,27 +430,11 @@ typedef struct { size_t i; } all_iter; -static int find_next_backend(size_t *out, const git_config *config, size_t i) -{ - backend_entry *entry; - - for (; i > 0; --i) { - entry = git_vector_get(&config->readers, i - 1); - GIT_ASSERT(entry && entry->instance && entry->instance->backend); - - *out = i; - return 0; - } - - return -1; -} - static int all_iter_next(git_config_entry **out, git_config_iterator *_iter) { all_iter *iter = (all_iter *) _iter; backend_entry *entry; git_config_backend *backend; - size_t i; int error = 0; if (iter->current != NULL && @@ -462,12 +446,14 @@ static int all_iter_next(git_config_entry **out, git_config_iterator *_iter) return error; do { - if (find_next_backend(&i, iter->config, iter->i) < 0) + if (iter->i == 0) return GIT_ITEROVER; - entry = git_vector_get(&iter->config->readers, i - 1); + entry = git_vector_get(&iter->config->readers, iter->i - 1); + GIT_ASSERT(entry && entry->instance && entry->instance->backend); + backend = entry->instance->backend; - iter->i = i - 1; + iter->i--; if (iter->current) iter->current->free(iter->current); diff --git a/tests/libgit2/config/configlevel.c b/tests/libgit2/config/configlevel.c index 3534fbc2c84..0e31268b0c6 100644 --- a/tests/libgit2/config/configlevel.c +++ b/tests/libgit2/config/configlevel.c @@ -72,6 +72,29 @@ void test_config_configlevel__fetching_a_level_from_an_empty_compound_config_ret git_config_free(cfg); } +void test_config_configlevel__can_fetch_highest_level(void) +{ + git_config *cfg; + git_config *single_level_cfg; + git_buf buf = {0}; + + cl_git_pass(git_config_new(&cfg)); + cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); + cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), + GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); + + cl_git_pass(git_config_open_level(&single_level_cfg, cfg, GIT_CONFIG_HIGHEST_LEVEL)); + + git_config_free(cfg); + + cl_git_pass(git_config_get_string_buf(&buf, single_level_cfg, "core.stringglobal")); + cl_assert_equal_s("don't find me!", buf.ptr); + + git_buf_dispose(&buf); + git_config_free(single_level_cfg); +} + void test_config_configlevel__can_override_local_with_worktree(void) { git_config *cfg; From 2eb3fecd03376be3f72a2c41716ee89b2fccdcaa Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 17 Mar 2024 21:18:06 +0000 Subject: [PATCH 478/816] fetch: avoid API breaking-changes from v1.7 Update `git_fetch_options` to break out the fetch options into individual options. This prevents creating an API breaking change from v1.7.0. `git_remote_update_tips` retains the `update_flags` to also avoid an API breaking change. --- include/git2/remote.h | 9 +++++---- src/libgit2/clone.c | 2 +- src/libgit2/remote.c | 7 ++++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 7ad820ad3c3..7067c88b0b1 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -744,10 +744,10 @@ typedef struct { git_fetch_prune_t prune; /** - * How to handle reference updates; a combination of - * `git_remote_update_flags`. + * How to handle reference updates; see `git_remote_update_flags`. */ - unsigned int update_flags; + unsigned int update_fetchhead : 1, + report_unchanged : 1; /** * Determines how to behave regarding tags on the remote, such @@ -790,7 +790,8 @@ typedef struct { GIT_FETCH_OPTIONS_VERSION, \ GIT_REMOTE_CALLBACKS_INIT, \ GIT_FETCH_PRUNE_UNSPECIFIED, \ - GIT_REMOTE_UPDATE_FETCHHEAD, \ + 1, \ + 0, \ GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, \ GIT_PROXY_OPTIONS_INIT } diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index db9a898e34e..d62c77ac554 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -431,7 +431,7 @@ static int clone_into( return error; memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); - fetch_opts.update_flags = ~GIT_REMOTE_UPDATE_FETCHHEAD; + fetch_opts.update_fetchhead = 0; if (!opts->depth) fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 9eb4bac8b2f..8b07c83184a 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1376,7 +1376,12 @@ int git_remote_fetch( return error; if (opts) { - update_flags = opts->update_flags; + if (opts->update_fetchhead) + update_flags |= GIT_REMOTE_UPDATE_FETCHHEAD; + + if (opts->report_unchanged) + update_flags |= GIT_REMOTE_UPDATE_REPORT_UNCHANGED; + tagopt = opts->download_tags; } From dd35af37d8ef1fbed24511ba8258ef77e6b8a0cc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 17 Mar 2024 21:28:17 +0000 Subject: [PATCH 479/816] repository: rearrange `git_repository_item_t` values Update the ordering of `GIT_REPOSITORY_ITEM_WORKTREE_CONFIG` to avoid breaking the ABI unnecessarily. --- include/git2/repository.h | 2 +- src/libgit2/repository.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 9ad6176f940..0afda72d402 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -499,12 +499,12 @@ typedef enum { GIT_REPOSITORY_ITEM_PACKED_REFS, GIT_REPOSITORY_ITEM_REMOTES, GIT_REPOSITORY_ITEM_CONFIG, - GIT_REPOSITORY_ITEM_WORKTREE_CONFIG, GIT_REPOSITORY_ITEM_INFO, GIT_REPOSITORY_ITEM_HOOKS, GIT_REPOSITORY_ITEM_LOGS, GIT_REPOSITORY_ITEM_MODULES, GIT_REPOSITORY_ITEM_WORKTREES, + GIT_REPOSITORY_ITEM_WORKTREE_CONFIG, GIT_REPOSITORY_ITEM__LAST } git_repository_item_t; diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 06c653ea921..8e449a6df09 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -58,12 +58,12 @@ static const struct { { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "packed-refs", false }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "remotes", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config", false }, - { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM_GITDIR, "config.worktree", false }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "info", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "hooks", true }, { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "logs", true }, { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "modules", true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true } + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true }, + { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM_GITDIR, "config.worktree", false } }; static int check_repositoryformatversion(int *version, git_config *config); From 4504f2c5cf7ca6ca8b7af3b748b0ba09df7801dd Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 18 Mar 2024 10:33:27 +0000 Subject: [PATCH 480/816] valgrind: suppress OpenSSL warnings --- script/valgrind.supp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/script/valgrind.supp b/script/valgrind.supp index 8c4549f62be..12b6634d5fe 100644 --- a/script/valgrind.supp +++ b/script/valgrind.supp @@ -191,6 +191,16 @@ ... } +{ + ignore-openssl-undefined-in-connect + Memcheck:Cond + ... + obj:*libcrypto.so* + ... + fun:openssl_connect + ... +} + { ignore-libssh2-rsa-sha1-sign Memcheck:Leak From 647f8eb9879eb4fe0459658756fcf2d23982f40a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 19 Dec 2023 16:56:30 +0000 Subject: [PATCH 481/816] ctype: only use custom functions on Windows The Microsoft C runtime (MSVCRT) may take a heavy lock on the locale in order to figure out how the `ctype` functions work. This is deeply slow. Provide our own to avoid that. On POSIX, provide emulation for that functionality using the ctype functions, but compress the return value into a `bool`, and cast the value to an `unsigned char`. --- src/util/ctype_compat.h | 52 +++++++++++++++++++++++++++++++++++++++++ src/util/git2_util.h | 1 + src/util/util.h | 34 --------------------------- 3 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 src/util/ctype_compat.h diff --git a/src/util/ctype_compat.h b/src/util/ctype_compat.h new file mode 100644 index 00000000000..5b04a8dd42c --- /dev/null +++ b/src/util/ctype_compat.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_ctype_compat_h__ +#define INCLUDE_ctype_compat_h__ + +/* + * The Microsoft C runtime (MSVCRT) may take a heavy lock on the + * locale in order to figure out how the `ctype` functions work. + * This is deeply slow. Provide our own to avoid that. + */ + +#ifdef GIT_WIN32 + +GIT_INLINE(int) git__tolower(int c) +{ + return (c >= 'A' && c <= 'Z') ? (c + 32) : c; +} + +GIT_INLINE(bool) git__isalpha(int c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); +} + +GIT_INLINE(bool) git__isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} +- +GIT_INLINE(bool) git__isspace(int c) +{ + return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); +} + +GIT_INLINE(bool) git__isxdigit(int c) +{ + return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} + +#else +# define git__tolower(a) tolower((unsigned char)(a)) + +# define git__isalpha(a) (!!isalpha((unsigned char)(a))) +# define git__isdigit(a) (!!isdigit((unsigned char)(a))) +# define git__isspace(a) (!!isspace((unsigned char)(a))) +# define git__isxdigit(a) (!!isxdigit((unsigned char)(a))) +#endif + +#endif diff --git a/src/util/git2_util.h b/src/util/git2_util.h index 5ec9429344a..5bf09819956 100644 --- a/src/util/git2_util.h +++ b/src/util/git2_util.h @@ -165,5 +165,6 @@ typedef struct git_str git_str; if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; } #include "util.h" +#include "ctype_compat.h" #endif diff --git a/src/util/util.h b/src/util/util.h index 933644fd2b9..2ed005110ef 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -83,15 +83,6 @@ extern char *git__strsep(char **end, const char *sep); extern void git__strntolower(char *str, size_t len); extern void git__strtolower(char *str); -#ifdef GIT_WIN32 -GIT_INLINE(int) git__tolower(int c) -{ - return (c >= 'A' && c <= 'Z') ? (c + 32) : c; -} -#else -# define git__tolower(a) tolower((unsigned char)(a)) -#endif - extern size_t git__linenlen(const char *buffer, size_t buffer_len); GIT_INLINE(const char *) git__next_line(const char *s) @@ -249,26 +240,6 @@ GIT_INLINE(size_t) git__size_t_powerof2(size_t v) return git__size_t_bitmask(v) + 1; } -GIT_INLINE(bool) git__isupper(int c) -{ - return (c >= 'A' && c <= 'Z'); -} - -GIT_INLINE(bool) git__isalpha(int c) -{ - return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); -} - -GIT_INLINE(bool) git__isdigit(int c) -{ - return (c >= '0' && c <= '9'); -} - -GIT_INLINE(bool) git__isspace(int c) -{ - return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); -} - GIT_INLINE(bool) git__isspace_nonlf(int c) { return (c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\v'); @@ -279,11 +250,6 @@ GIT_INLINE(bool) git__iswildcard(int c) return (c == '*' || c == '?' || c == '['); } -GIT_INLINE(bool) git__isxdigit(int c) -{ - return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); -} - /* * Parse a string value as a boolean, just like Core Git does. * From 8e6beb3d16286f9647880ab6488ca7c2485d46cd Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 19 Dec 2023 17:09:16 +0000 Subject: [PATCH 482/816] ctype: switch to `git__` ctype functions Use the `git__` ctype functions (`git__isdigit` and friends) instead of explicitly casting. --- src/libgit2/config.c | 2 +- src/libgit2/config_parse.c | 4 ++-- src/libgit2/path.c | 2 +- src/libgit2/trailer.c | 10 +++++----- src/libgit2/transports/smart_pkt.c | 4 ++-- src/util/ctype_compat.h | 20 +++++++++++++++++++- src/util/date.c | 26 +++++++++++++------------- src/util/str.c | 4 ++-- tests/libgit2/repo/open.c | 2 +- 9 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 5c1c00f6cb7..cfc3a4b2e26 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -1447,7 +1447,7 @@ static int normalize_section(char *start, char *end) for (scan = start; *scan; ++scan) { if (end && scan >= end) break; - if (isalnum((unsigned char)*scan)) + if (git__isalnum(*scan)) *scan = (char)git__tolower(*scan); else if (*scan != '-' || scan == start) return GIT_EINVALIDSPEC; diff --git a/src/libgit2/config_parse.c b/src/libgit2/config_parse.c index 9ab78cc7f60..7f933db4885 100644 --- a/src/libgit2/config_parse.c +++ b/src/libgit2/config_parse.c @@ -27,7 +27,7 @@ static void set_parse_error(git_config_parser *reader, int col, const char *erro GIT_INLINE(int) config_keychar(char c) { - return isalnum((unsigned char)c) || c == '-'; + return git__isalnum(c) || c == '-'; } static int strip_comments(char *line, int in_quotes) @@ -383,7 +383,7 @@ static int parse_multiline_variable(git_config_parser *reader, git_str *value, i GIT_INLINE(bool) is_namechar(char c) { - return isalnum((unsigned char)c) || c == '-'; + return git__isalnum(c) || c == '-'; } static int parse_name( diff --git a/src/libgit2/path.c b/src/libgit2/path.c index 50181fdbff0..4b584fb8056 100644 --- a/src/libgit2/path.c +++ b/src/libgit2/path.c @@ -202,7 +202,7 @@ GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char * { size_t count = 0; - while (len > 0 && tolower((unsigned char)*str) == tolower((unsigned char)*prefix)) { + while (len > 0 && git__tolower(*str) == git__tolower(*prefix)) { count++; str++; prefix++; diff --git a/src/libgit2/trailer.c b/src/libgit2/trailer.c index 9fb16418413..6e37cfdcf2d 100644 --- a/src/libgit2/trailer.c +++ b/src/libgit2/trailer.c @@ -24,7 +24,7 @@ static const char *const git_generated_prefixes[] = { static int is_blank_line(const char *str) { const char *s = str; - while (*s && *s != '\n' && isspace((unsigned char)*s)) + while (*s && *s != '\n' && git__isspace(*s)) s++; return !*s || *s == '\n'; } @@ -93,7 +93,7 @@ static bool find_separator(size_t *out, const char *line, const char *separators return true; } - if (!whitespace_found && (isalnum((unsigned char)*c) || *c == '-')) + if (!whitespace_found && (git__isalnum(*c) || *c == '-')) continue; if (c != line && (*c == ' ' || *c == '\t')) { whitespace_found = 1; @@ -233,12 +233,12 @@ static size_t find_trailer_start(const char *buf, size_t len) } find_separator(&separator_pos, bol, TRAILER_SEPARATORS); - if (separator_pos >= 1 && !isspace((unsigned char)bol[0])) { + if (separator_pos >= 1 && !git__isspace(bol[0])) { trailer_lines++; possible_continuation_lines = 0; if (recognized_prefix) continue; - } else if (isspace((unsigned char)bol[0])) + } else if (git__isspace(bol[0])) possible_continuation_lines++; else { non_trailer_lines++; @@ -323,7 +323,7 @@ int git_message_trailers(git_message_trailer_array *trailer_arr, const char *mes goto ret; } - if (isalnum((unsigned char)*ptr) || *ptr == '-') { + if (git__isalnum(*ptr) || *ptr == '-') { /* legal key character */ NEXT(S_KEY); } diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 08cb7fbe5c2..6a3f903df15 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -535,10 +535,10 @@ static int parse_len(size_t *out, const char *line, size_t linelen) num[PKT_LEN_SIZE] = '\0'; for (i = 0; i < PKT_LEN_SIZE; ++i) { - if (!isxdigit((unsigned char)num[i])) { + if (!git__isxdigit(num[i])) { /* Make sure there are no special characters before passing to error message */ for (k = 0; k < PKT_LEN_SIZE; ++k) { - if(!isprint((unsigned char)num[k])) { + if(!git__isprint(num[k])) { num[k] = '.'; } } diff --git a/src/util/ctype_compat.h b/src/util/ctype_compat.h index 5b04a8dd42c..462c8a17f17 100644 --- a/src/util/ctype_compat.h +++ b/src/util/ctype_compat.h @@ -20,6 +20,11 @@ GIT_INLINE(int) git__tolower(int c) return (c >= 'A' && c <= 'Z') ? (c + 32) : c; } +GIT_INLINE(int) git__toupper(int c) +{ + return (c >= 'a' && c <= 'z') ? (c - 32) : c; +} + GIT_INLINE(bool) git__isalpha(int c) { return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); @@ -29,7 +34,12 @@ GIT_INLINE(bool) git__isdigit(int c) { return (c >= '0' && c <= '9'); } -- + +GIT_INLINE(bool) git__isalnum(int c) +{ + return git__isalpha(c) || git__isdigit(c); +} + GIT_INLINE(bool) git__isspace(int c) { return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); @@ -40,13 +50,21 @@ GIT_INLINE(bool) git__isxdigit(int c) return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } +GIT_INLINE(bool) git__isprint(int c) +{ + return (c >= ' ' && c <= '~'); +} + #else # define git__tolower(a) tolower((unsigned char)(a)) +# define git__toupper(a) toupper((unsigned char)(a)) # define git__isalpha(a) (!!isalpha((unsigned char)(a))) # define git__isdigit(a) (!!isdigit((unsigned char)(a))) +# define git__isalnum(a) (!!isalnum((unsigned char)(a))) # define git__isspace(a) (!!isspace((unsigned char)(a))) # define git__isxdigit(a) (!!isxdigit((unsigned char)(a))) +# define git__isprint(a) (!!isprint((unsigned char)(a))) #endif #endif diff --git a/src/util/date.c b/src/util/date.c index d54056842dd..872cb81f33c 100644 --- a/src/util/date.c +++ b/src/util/date.c @@ -129,9 +129,9 @@ static size_t match_string(const char *date, const char *str) for (i = 0; *date; date++, str++, i++) { if (*date == *str) continue; - if (toupper((unsigned char)*date) == toupper((unsigned char)*str)) + if (git__toupper(*date) == git__toupper(*str)) continue; - if (!isalnum((unsigned char)*date)) + if (!git__isalnum(*date)) break; return 0; } @@ -143,7 +143,7 @@ static int skip_alpha(const char *date) int i = 0; do { i++; - } while (isalpha((unsigned char)date[i])); + } while (git__isalpha(date[i])); return i; } @@ -251,7 +251,7 @@ static size_t match_multi_number(unsigned long num, char c, const char *date, ch num2 = strtol(end+1, &end, 10); num3 = -1; - if (*end == c && isdigit((unsigned char)end[1])) + if (*end == c && git__isdigit(end[1])) num3 = strtol(end+1, &end, 10); /* Time? Date? */ @@ -349,7 +349,7 @@ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_ case '.': case '/': case '-': - if (isdigit((unsigned char)end[1])) { + if (git__isdigit(end[1])) { size_t match = match_multi_number(num, *end, date, end, tm); if (match) return match; @@ -364,7 +364,7 @@ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_ n = 0; do { n++; - } while (isdigit((unsigned char)date[n])); + } while (git__isdigit(date[n])); /* Four-digit year or a timezone? */ if (n == 4) { @@ -514,11 +514,11 @@ static int parse_date_basic(const char *date, git_time_t *timestamp, int *offset if (!c || c == '\n') break; - if (isalpha(c)) + if (git__isalpha(c)) match = match_alpha(date, &tm, offset); - else if (isdigit(c)) + else if (git__isdigit(c)) match = match_digit(date, &tm, offset, &tm_gmt); - else if ((c == '-' || c == '+') && isdigit((unsigned char)date[1])) + else if ((c == '-' || c == '+') && git__isdigit(date[1])) match = match_tz(date, offset); if (!match) { @@ -682,7 +682,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm const char *end = date; int i; - while (isalpha((unsigned char)*++end)) + while (git__isalpha(*++end)) /* scan to non-alpha */; for (i = 0; i < 12; i++) { @@ -783,7 +783,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num) case '.': case '/': case '-': - if (isdigit((unsigned char)end[1])) { + if (git__isdigit(end[1])) { size_t match = match_multi_number(number, *end, date, end, tm); if (match) return date + match; @@ -843,13 +843,13 @@ static git_time_t approxidate_str(const char *date, if (!c) break; date++; - if (isdigit(c)) { + if (git__isdigit(c)) { pending_number(&tm, &number); date = approxidate_digit(date-1, &tm, &number); touched = 1; continue; } - if (isalpha(c)) + if (git__isalpha(c)) date = approxidate_alpha(date-1, &tm, &now, &number, &touched); } pending_number(&tm, &number); diff --git a/src/util/str.c b/src/util/str.c index 625faba06db..0b07c814702 100644 --- a/src/util/str.c +++ b/src/util/str.c @@ -485,8 +485,8 @@ int git_str_decode_percent( for (str_pos = 0; str_pos < str_len; buf->size++, str_pos++) { if (str[str_pos] == '%' && str_len > str_pos + 2 && - isxdigit((unsigned char)str[str_pos + 1]) && - isxdigit((unsigned char)str[str_pos + 2])) { + git__isxdigit(str[str_pos + 1]) && + git__isxdigit(str[str_pos + 2])) { buf->ptr[buf->size] = (HEX_DECODE(str[str_pos + 1]) << 4) + HEX_DECODE(str[str_pos + 2]); str_pos += 2; diff --git a/tests/libgit2/repo/open.c b/tests/libgit2/repo/open.c index 219612016b9..9eef7f5a7e8 100644 --- a/tests/libgit2/repo/open.c +++ b/tests/libgit2/repo/open.c @@ -316,7 +316,7 @@ static void unposix_path(git_str *path) src = tgt = path->ptr; /* convert "/d/..." to "d:\..." */ - if (src[0] == '/' && isalpha((unsigned char)src[1]) && src[2] == '/') { + if (src[0] == '/' && git__isalpha(src[1]) && src[2] == '/') { *tgt++ = src[1]; *tgt++ = ':'; *tgt++ = '\\'; From 467556993fa9d249294858c967f0b4a6359b9a3b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 18 Mar 2024 10:14:35 +0000 Subject: [PATCH 483/816] ntlmclient: use unsigned char for ctype functions --- deps/ntlmclient/ntlm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/ntlmclient/ntlm.c b/deps/ntlmclient/ntlm.c index ad4de5de56e..6094a4a3484 100644 --- a/deps/ntlmclient/ntlm.c +++ b/deps/ntlmclient/ntlm.c @@ -988,9 +988,9 @@ static inline bool generate_lm_hash( keystr2_len = (password_len > 7) ? MIN(14, password_len) - 7 : 0; for (i = 0; i < keystr1_len; i++) - keystr1[i] = (unsigned char)toupper(password[i]); + keystr1[i] = (unsigned char)toupper((unsigned char)password[i]); for (i = 0; i < keystr2_len; i++) - keystr2[i] = (unsigned char)toupper(password[i+7]); + keystr2[i] = (unsigned char)toupper((unsigned char)password[i+7]); /* DES encrypt the LM constant using the password as the key */ des_key_from_password(&key1, keystr1, keystr1_len); From 9288436e38b64ec86795f90710b79ccf8ceba1a6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 19 Mar 2024 07:01:01 +0000 Subject: [PATCH 484/816] ci: split SHA256 builds out into their own workflow Split the SHA256 builds into their own workflow; since they're experimental (and have proven to be flaky) they shouldn't be used as signal that there's a problem with a PR. --- .github/workflows/experimental.yml | 118 +++++++++++++++++++++++++++++ .github/workflows/main.yml | 31 -------- 2 files changed, 118 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/experimental.yml diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml new file mode 100644 index 00000000000..5bfea2c0028 --- /dev/null +++ b/.github/workflows/experimental.yml @@ -0,0 +1,118 @@ +# Validation builds for experimental features; these shouldn't be +# required for pull request approval. +name: Experimental Features + +on: + push: + branches: [ main, maint/* ] + pull_request: + branches: [ main, maint/* ] + workflow_dispatch: + +env: + docker-registry: ghcr.io + docker-config-path: ci/docker + +permissions: + contents: write + packages: write + +jobs: + # Run our CI/CD builds. We build a matrix with the various build targets + # and their details. Then we build either in a docker container (Linux) + # or on the actual hosts (macOS, Windows). + build: + strategy: + matrix: + platform: + # All builds: experimental SHA256 support + - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" + id: linux-sha256 + os: ubuntu-latest + container: + name: xenial + env: + CC: clang + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON + - name: "macOS (SHA256)" + id: macos-sha256 + os: macos-12 + setup-script: osx + env: + CC: clang + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_GENERATOR: Ninja + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (SHA256, amd64, Visual Studio)" + id: windows-sha256 + os: windows-2019 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + fail-fast: false + env: ${{ matrix.platform.env }} + runs-on: ${{ matrix.platform.os }} + name: "Build: ${{ matrix.platform.name }}" + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + path: source + fetch-depth: 0 + - name: Set up build environment + run: source/ci/setup-${{ matrix.platform.setup-script }}-build.sh + shell: bash + if: matrix.platform.setup-script != '' + - name: Setup QEMU + run: docker run --rm --privileged multiarch/qemu-user-static:register --reset + if: matrix.platform.container.qemu == true + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: ${{ matrix.platform.container.name }} + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} + if: matrix.platform.container.name != '' + - name: Prepare build + run: mkdir build + - name: Build + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/build.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Test + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/test.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Upload test results + uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: test-results-${{ matrix.platform.id }} + path: build/results_*.xml + + test_results: + name: Test results + needs: [ build ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Download test results + uses: actions/download-artifact@v3 + - name: Generate test summary + uses: test-summary/action@v2 + with: + paths: 'test-results-*/*.xml' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 236a7d13bb6..87e834f10db 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -184,37 +184,6 @@ jobs: ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1 - - # All builds: experimental SHA256 support - - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" - id: linux-sha256 - os: ubuntu-latest - container: - name: xenial - env: - CC: clang - CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON - - name: "macOS (SHA256)" - id: macos-sha256 - os: macos-12 - setup-script: osx - env: - CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON - CMAKE_GENERATOR: Ninja - PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (SHA256, amd64, Visual Studio)" - id: windows-sha256 - os: windows-2019 - env: - ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true fail-fast: false env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} From 7940f094a54765f277d5ce9bcb9d6ce6ea9d24e5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 21:41:59 +0000 Subject: [PATCH 485/816] v1.8: update COPYING file Include the ntlmclient dependency's license file. --- COPYING | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/COPYING b/COPYING index ff5e76857e3..bc94b9df9fa 100644 --- a/COPYING +++ b/COPYING @@ -1214,3 +1214,172 @@ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- + +The bundled ntlmclient code is licensed under the MIT license: + +Copyright (c) Edward Thomson. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +---------------------------------------------------------------------- + +Portions of this software derived from Team Explorer Everywhere: + +Copyright (c) Microsoft Corporation + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +--------------------------------------------------------------------------- + +Portions of this software derived from the LLVM Compiler Infrastructure: + +Copyright (c) 2003-2016 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +--------------------------------------------------------------------------- + +Portions of this software derived from Unicode, Inc: + +Copyright 2001-2004 Unicode, Inc. + +Disclaimer + +This source code is provided as is by Unicode, Inc. No claims are +made as to fitness for any particular purpose. No warranties of any +kind are expressed or implied. The recipient agrees to determine +applicability of information provided. If this file has been +purchased on magnetic or optical media from Unicode, Inc., the +sole remedy for any claim will be exchange of defective media +within 90 days of receipt. + +Limitations on Rights to Redistribute This Code + +Unicode, Inc. hereby grants the right to freely use the information +supplied in this file in the creation of products supporting the +Unicode Standard, and to make copies of this file in any form +for internal or external distribution as long as this notice +remains attached. + +--------------------------------------------------------------------------- + +Portions of this software derived from sheredom/utf8.h: + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +--------------------------------------------------------------------------- + +Portions of this software derived from RFC 1320: + +Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD4 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD4 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. From 5aa3ce722538bc898af09be332e8ccaa5d04232c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 20:07:30 +0000 Subject: [PATCH 486/816] v1.8: update version numbers --- README.md | 2 +- include/git2/version.h | 6 +++--- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f4dbc789154..77efdd4a688 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | | **main** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) | +| **v1.8 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.8) | | **v1.7 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.7) | -| **v1.6 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.6&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.6) | | **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/workflows/Nightly%20Build/badge.svg)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Nightly+Build%22) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | `libgit2` is a portable, pure C implementation of the Git core methods diff --git a/include/git2/version.h b/include/git2/version.h index 76cb0026fc2..010d4a224d9 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,7 +11,7 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.8.0-alpha" +#define LIBGIT2_VERSION "1.8.0" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 @@ -31,13 +31,13 @@ * a prerelease name like "beta" or "rc1". For final releases, this will * be `NULL`. */ -#define LIBGIT2_VER_PRERELEASE "alpha" +#define LIBGIT2_VER_PRERELEASE NULL /** * The library ABI soversion for this version of libgit2. This should * only be changed when the library has a breaking ABI change, and so * may trail the library's version number. */ -#define LIBGIT2_SOVERSION "1.7" +#define LIBGIT2_SOVERSION "1.8" #endif diff --git a/package.json b/package.json index 203e99b9bc6..2306e721853 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.8.0-alpha", + "version": "1.8.0", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From 69f257711014e738819feb13280d9428d0539339 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 17 Mar 2024 13:55:52 +0000 Subject: [PATCH 487/816] v1.8: update changelog --- docs/changelog.md | 317 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 317 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index f733102356a..7b118c798be 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,320 @@ +v1.8 +---- + +This is release v1.8.0, "Das Fliegende Klassenzimmer". This release +includes optional, experimental support for invoking OpenSSH to fetch +and push, an easier mechanism to perform the default behavior of +`git commit`, and has many improvements for worktrees. This release +also includes many other new features and bugfixes. + +## Major changes + +* **Executable SSH (OpenSSH) support** + libgit2 can now invoke the command-line OpenSSH to fetch from and push + to remotes over SSH. This support takes the place of libssh2 support. + To use it, configure libgit2 with `cmake -DUSE_SSH=exec`, and please + report any problems that you discover. By @ethomson in + https://github.com/libgit2/libgit2/pull/6617 + +* **Simplified commit creation** + The `git_commit_create_from_stage` API was introduced to allow users to + better emulate the behavior of `git commit` without needing to provide + unnecessary information. The current state of the index is committed to + the current branch. By @ethomson in + https://github.com/libgit2/libgit2/pull/6716 + +* **Worktree improvements** + A number of worktree improvements have been made for better + compatibility with core git. First, libgit2 now understands per-worktree + references, thanks to @csware in + https://github.com/libgit2/libgit2/pull/6387. Worktree-specific + configuration is now supported, thanks to @vermiculus in + https://github.com/libgit2/libgit2/pull/6202. And improved compatibility + with `git worktree add` is now supported, thanks to @herrerog in + https://github.com/libgit2/libgit2/pull/5319. + +## Breaking changes + +* **Adding `WORKTREE` configuration level** (ABI breaking change) + To support worktree configurations at the appropriate level (higher + priority than local configuration, but lower priority than app-specific + configuration), the `GIT_CONFIG_LEVEL_WORKTREE` level was introduced at + priority 6. `GIT_CONFIG_LEVEL_APP` now begins at priority 7. + +* **Changes to `git_config_entry`** (ABI breaking change) + The `git_config_entry` structure now contains information about the + `backend_type` and `origin_path`. The unused `payload` value has been + removed. + +* **`git_push_options` includes remote push options** (ABI breaking change) + The `git_push_options` structure now contains a value for remote push + options. + +## Other changes + +### New features + +* config: provide an "origin" for config entries by @ethomson in + https://github.com/libgit2/libgit2/pull/6615 +* cli: add a `git config` command by @ethomson in + https://github.com/libgit2/libgit2/pull/6616 +* Add OpenSSH support by @ethomson in + https://github.com/libgit2/libgit2/pull/6617 +* remote: optionally report unchanged tips by @ethomson in + https://github.com/libgit2/libgit2/pull/6645 +* Support setting oid type for in-memory repositories by @kcsaul in + https://github.com/libgit2/libgit2/pull/6671 +* cli: add `index-pack` command by @ethomson in + https://github.com/libgit2/libgit2/pull/6681 +* Add `git_repository_commit_parents` to identify the parents of the next + commit given the repository state by @ethomson in + https://github.com/libgit2/libgit2/pull/6707 +* commit: introduce `git_commit_create_from_stage` by @ethomson in + https://github.com/libgit2/libgit2/pull/6716 +* set SSH timeout by @vafada in + https://github.com/libgit2/libgit2/pull/6721 +* Implement push options on push by @russell in + https://github.com/libgit2/libgit2/pull/6439 +* Support index.skipHash true config by @parnic in + https://github.com/libgit2/libgit2/pull/6738 +* worktree: mimic 'git worktree add' behavior. by @herrerog in + https://github.com/libgit2/libgit2/pull/5319 +* Support the extension for worktree-specific config by @vermiculus in + https://github.com/libgit2/libgit2/pull/6202 +* Separate config reader and writer backend priorities (for worktree + configs) by @ethomson in https://github.com/libgit2/libgit2/pull/6756 +* fetch: enable deepening/shortening shallow clones by @kempniu in + https://github.com/libgit2/libgit2/pull/6662 + +### Bug fixes + +* repository: make cleanup safe for re-use with grafts by @carlosmn in + https://github.com/libgit2/libgit2/pull/6600 +* fix: Add missing include for `oidarray`. by @dvzrv in + https://github.com/libgit2/libgit2/pull/6608 +* ssh: fix `known_hosts` leak in `_git_ssh_setup_conn` by @steven9724 in + https://github.com/libgit2/libgit2/pull/6599 +* proxy: Return an error for invalid proxy URLs instead of crashing by + @lrm29 in https://github.com/libgit2/libgit2/pull/6597 +* errors: refactoring - never return `NULL` in `git_error_last()` by + @ethomson in https://github.com/libgit2/libgit2/pull/6625 +* Reject potential option injections over ssh by @carlosmn in + https://github.com/libgit2/libgit2/pull/6636 +* remote: fix memory leak in `git_remote_download()` by @7Ji in + https://github.com/libgit2/libgit2/pull/6651 +* git2: Fix crash when called w/o parameters by @csware in + https://github.com/libgit2/libgit2/pull/6673 +* Avoid macro redefinition of `ENABLE_INTSAFE_SIGNED_FUNCTIONS` by @csware + in https://github.com/libgit2/libgit2/pull/6666 +* util: suppress some uninitialized variable warnings by @boretrk in + https://github.com/libgit2/libgit2/pull/6659 +* push: set generic error in `push_negotiation` cb by @ethomson in + https://github.com/libgit2/libgit2/pull/6675 +* process: test `/usr/bin/false` on BSDs by @ethomson in + https://github.com/libgit2/libgit2/pull/6677 +* clone: don't mix up "http://url" with "http:/url" when figuring out if we + should do a local clone by @boretrk in + https://github.com/libgit2/libgit2/pull/6361 +* Several compatibility fixes by @ethomson in + https://github.com/libgit2/libgit2/pull/6678 +* Git blame buffer gives the wrong result in many cases where there are + by @thosey in https://github.com/libgit2/libgit2/pull/6572 +* Fix 'path cannot exist in repository' during diff for in-memory repository + by @kcsaul in https://github.com/libgit2/libgit2/pull/6683 +* process: don't try to close the status by @ethomson in + https://github.com/libgit2/libgit2/pull/6693 +* Minor bug fixes by @ethomson in + https://github.com/libgit2/libgit2/pull/6695 +* Bypass shallow clone support for in-memory repositories by @kcsaul in + https://github.com/libgit2/libgit2/pull/6684 +* examples: use `unsigned` int for bitfields by @ethomson in + https://github.com/libgit2/libgit2/pull/6699 +* Fix some bugs caught by UBscan by @ethomson in + https://github.com/libgit2/libgit2/pull/6700 +* `git_diff_find_similar` doesn't always remove unmodified deltas by @yori + in https://github.com/libgit2/libgit2/pull/6642 +* httpclient: clear `client->parser.data` after use by @ethomson in + https://github.com/libgit2/libgit2/pull/6705 +* Do not normalize `safe.directory` paths by @csware in + https://github.com/libgit2/libgit2/pull/6668 +* clone: don't swallow error in `should_checkout` by @ethomson in + https://github.com/libgit2/libgit2/pull/6727 +* Correct index add directory/file conflict detection by @ethomson in + https://github.com/libgit2/libgit2/pull/6729 +* Correct `git_revparse_single` and add revparse fuzzing by @ethomson in + https://github.com/libgit2/libgit2/pull/6730 +* config: properly delete or rename section containing multivars by + @samueltardieu in https://github.com/libgit2/libgit2/pull/6723 +* revparse: ensure bare '@' is truly bare by @ethomson in + https://github.com/libgit2/libgit2/pull/6742 +* repo: ensure we can initialize win32 paths by @ethomson in + https://github.com/libgit2/libgit2/pull/6743 +* Swap `GIT_DIFF_LINE_(ADD|DEL)_EOFNL` to match other Diffs by @xphoniex in + https://github.com/libgit2/libgit2/pull/6240 +* diff: fix test for SHA256 support in `diff_from_buffer` by @ethomson in + https://github.com/libgit2/libgit2/pull/6745 +* http: support empty http.proxy config setting by @ethomson in + https://github.com/libgit2/libgit2/pull/6744 +* More `safe.directory` improvements by @ethomson in + https://github.com/libgit2/libgit2/pull/6739 +* Ensure that completely ignored diff is empty by @ethomson in + https://github.com/libgit2/libgit2/pull/5893 +* Fix broken regexp that matches submodule names containing ".path" by + @csware in https://github.com/libgit2/libgit2/pull/6749 +* Fix memory leaks by @csware in + https://github.com/libgit2/libgit2/pull/6748 +* Make `refdb_fs` (hopefully) fully aware of per worktree refs by @csware in + https://github.com/libgit2/libgit2/pull/6387 +* fix log example by @albfan in https://github.com/libgit2/libgit2/pull/6359 +* fetch: fail on depth for local transport by @ethomson in + https://github.com/libgit2/libgit2/pull/6757 +* Fix message trailer parsing by @ethomson in + https://github.com/libgit2/libgit2/pull/6761 +* config: correct fetching the `HIGHEST_LEVEL` config by @ethomson in + https://github.com/libgit2/libgit2/pull/6766 +* Avoid some API breaking changes in v1.8 by @ethomson in + https://github.com/libgit2/libgit2/pull/6768 + +### Build and CI improvements + +* meta: update version numbers to v1.8 by @ethomson in + https://github.com/libgit2/libgit2/pull/6596 +* Revert "CMake: Search for ssh2 instead of libssh2." by @ethomson in + https://github.com/libgit2/libgit2/pull/6619 +* cmake: fix openssl build on win32 by @lazka in + https://github.com/libgit2/libgit2/pull/6626 +* ci: retry flaky online tests by @ethomson in + https://github.com/libgit2/libgit2/pull/6628 +* ci: update to macOS 12 by @ethomson in + https://github.com/libgit2/libgit2/pull/6629 +* Use `#!/bin/bash` for script with bash-specific commands by @roehling in + https://github.com/libgit2/libgit2/pull/6581 +* ci: overwrite nonsense in `/usr/local` during macOS setup by @ethomson in + https://github.com/libgit2/libgit2/pull/6664 +* release: add a compatibility label by @ethomson in + https://github.com/libgit2/libgit2/pull/6676 +* actions: set permissions by @ethomson in + https://github.com/libgit2/libgit2/pull/6680 +* cmake: rename FindIconv to avoid collision with cmake by @ethomson in + https://github.com/libgit2/libgit2/pull/6682 +* ci: allow workflows to read and write packages by @ethomson in + https://github.com/libgit2/libgit2/pull/6687 +* ci: allow workflows to push changes by @ethomson in + https://github.com/libgit2/libgit2/pull/6688 +* tests: remove test for strcasecmp by @boretrk in + https://github.com/libgit2/libgit2/pull/6691 +* CI fixes by @ethomson in + https://github.com/libgit2/libgit2/pull/6694 +* ci: improvements to prepare for Cygwin support by @ethomson in + https://github.com/libgit2/libgit2/pull/6696 +* Yet more CI improvements by @ethomson in + https://github.com/libgit2/libgit2/pull/6697 +* Fix nightly builds by @ethomson in + https://github.com/libgit2/libgit2/pull/6709 +* Benchmarks: add a site to view results by @ethomson in + https://github.com/libgit2/libgit2/pull/6715 +* `GIT_RAND_GETENTROPY`: do not include `sys/random.h` by @semarie in + https://github.com/libgit2/libgit2/pull/6736 +* add dl to `LIBGIT2_SYSTEM_LIBS` by @christopherfujino in + https://github.com/libgit2/libgit2/pull/6631 +* meta: add dependency tag to release.yml by @ethomson in + https://github.com/libgit2/libgit2/pull/6740 +* CI: fix our nightlies by @ethomson in + https://github.com/libgit2/libgit2/pull/6751 +* trace: Re-enable tests as tracing is now enabled by default by @lrm29 in + https://github.com/libgit2/libgit2/pull/6752 +* tests: don't free an unininitialized repo by @ethomson in + https://github.com/libgit2/libgit2/pull/6763 +* ci: reduce ASLR randomization for TSAN by @ethomson in + https://github.com/libgit2/libgit2/pull/6764 +* packbuilder: adjust nondeterministic tests by @ethomson in + https://github.com/libgit2/libgit2/pull/6762 +* Allow libgit2 to be compiled with mbedtls3. by @adamharrison in + https://github.com/libgit2/libgit2/pull/6759 +* build: update to latest actions versions by @ethomson in + https://github.com/libgit2/libgit2/pull/6765 +* ctype: cast characters to unsigned when classifying characters by + @boretrk in https://github.com/libgit2/libgit2/pull/6679 and + @ethomson in https://github.com/libgit2/libgit2/pull/6770 +* valgrind: suppress OpenSSL warnings by @ethomson in https://github.com/libgit2/libgit2/pull/6769 + +### Documentation improvements + +* README.md: Fix link to conan packages by @lrm29 in + https://github.com/libgit2/libgit2/pull/6621 +* README: replace gmaster with GitButler by @ethomson in + https://github.com/libgit2/libgit2/pull/6692 +* blame example: Fix support for line range in CLI by @wetneb in + https://github.com/libgit2/libgit2/pull/6638 +* Support authentication in push example by @pluehne in + https://github.com/libgit2/libgit2/pull/5904 +* docs: fix mistake in attr.h by @DavHau in + https://github.com/libgit2/libgit2/pull/6714 +* Fix broken links by @csware in + https://github.com/libgit2/libgit2/pull/6747 + +### Platform compatibility fixes + +* stransport: macOS: replace `errSSLNetworkTimeout`, with hard-coded + value by @mascguy in https://github.com/libgit2/libgit2/pull/6610 + +### Git compatibility fixes + +* Do not trim dots from usernames by @georgthegreat in + https://github.com/libgit2/libgit2/pull/6657 +* merge: fix incorrect rename detection for empty files by @herrerog in + https://github.com/libgit2/libgit2/pull/6717 + +### Dependency updates + +* zlib: upgrade bundled zlib to v1.3 by @ethomson in + https://github.com/libgit2/libgit2/pull/6698 +* ntlmclient: update to latest upstream ntlmclient by @ethomson in + https://github.com/libgit2/libgit2/pull/6704 + +## New Contributors + +* @dvzrv made their first contribution in + https://github.com/libgit2/libgit2/pull/6608 +* @mascguy made their first contribution in + https://github.com/libgit2/libgit2/pull/6610 +* @steven9724 made their first contribution in + https://github.com/libgit2/libgit2/pull/6599 +* @lazka made their first contribution in + https://github.com/libgit2/libgit2/pull/6626 +* @roehling made their first contribution in + https://github.com/libgit2/libgit2/pull/6581 +* @7Ji made their first contribution in + https://github.com/libgit2/libgit2/pull/6651 +* @kempniu made their first contribution in + https://github.com/libgit2/libgit2/pull/6662 +* @thosey made their first contribution in + https://github.com/libgit2/libgit2/pull/6572 +* @wetneb made their first contribution in + https://github.com/libgit2/libgit2/pull/6638 +* @yori made their first contribution in + https://github.com/libgit2/libgit2/pull/6642 +* @pluehne made their first contribution in + https://github.com/libgit2/libgit2/pull/5904 +* @DavHau made their first contribution in + https://github.com/libgit2/libgit2/pull/6714 +* @vafada made their first contribution in + https://github.com/libgit2/libgit2/pull/6721 +* @semarie made their first contribution in + https://github.com/libgit2/libgit2/pull/6736 +* @christopherfujino made their first contribution in + https://github.com/libgit2/libgit2/pull/6631 +* @parnic made their first contribution in + https://github.com/libgit2/libgit2/pull/6738 +* @samueltardieu made their first contribution in + https://github.com/libgit2/libgit2/pull/6723 +* @xphoniex made their first contribution in + https://github.com/libgit2/libgit2/pull/6240 +* @adamharrison made their first contribution in + https://github.com/libgit2/libgit2/pull/6759 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.7.0...v1.8.0 + v1.7 ---- From 9b29a5d30d1ea993498b9f9c91855ed0d56eea6a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 20 Mar 2024 09:25:14 +0000 Subject: [PATCH 488/816] ci: update nightly workflows Update the nightly and benchmark workflows to only run steps in libgit2/libgit2 by default. Also update the benchmark workflow to use the latest download-artifact version. --- .github/workflows/benchmark.yml | 4 ++-- .github/workflows/nightly.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 51a5fc1c083..6ee492ac443 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -89,7 +89,7 @@ jobs: publish: name: Publish results needs: [ build ] - if: always() + if: ${{ always() && github.repository == 'libgit2/libgit2' }} runs-on: ubuntu-latest steps: - name: Check out benchmark repository @@ -100,7 +100,7 @@ jobs: fetch-depth: 0 ssh-key: ${{ secrets.BENCHMARKS_PUBLISH_KEY }} - name: Download test results - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Publish API run: | # Move today's benchmark run into the right place diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 570b9aa6ab6..33155c9e447 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -401,7 +401,7 @@ jobs: test_results: name: Test results needs: [ build ] - if: always() + if: ${{ always() && github.repository == 'libgit2/libgit2' }} runs-on: ubuntu-latest steps: - name: Download test results From 34073bf2e53eedc83f301ded79361ec0e506ca20 Mon Sep 17 00:00:00 2001 From: Florian Pircher Date: Sun, 24 Mar 2024 23:11:41 +0100 Subject: [PATCH 489/816] commit: Fix git_commit_create_from_stage without author and committer --- src/libgit2/commit.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 5582a65aadf..47f6fed892f 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -1107,8 +1107,10 @@ int git_commit_create_from_stage( if (given_opts) memcpy(&opts, given_opts, sizeof(git_commit_create_options)); - if ((author = opts.author) == NULL || - (committer = opts.committer) == NULL) { + author = opts.author; + committer = opts.committer; + + if (!author || !committer) { if (git_signature_default(&default_signature, repo) < 0) goto done; From dd79fbb5abee81fc232e92cc4bbd1b11647ec092 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 26 Mar 2024 20:56:07 +0000 Subject: [PATCH 490/816] ci: give all nightly builds a unique id The new upload-artifact action fails on conflicting names; ensure that we give each artifact a unique name (keyed off the id). --- .github/workflows/nightly.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 33155c9e447..1888e5e174e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -215,6 +215,7 @@ jobs: ARCH: x86 - name: "Linux (Bionic, GCC, dynamically-loaded OpenSSL)" + id: bionic-gcc-dynamicopenssl container: name: bionic dockerfile: bionic @@ -226,6 +227,7 @@ jobs: SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (x86, Bionic, Clang, OpenSSL)" + id: bionic-x86-clang-openssl container: name: bionic-x86 dockerfile: bionic @@ -238,6 +240,7 @@ jobs: SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (x86, Bionic, GCC, OpenSSL)" + id: bionic-x86-gcc-openssl container: name: bionic-x86 dockerfile: bionic @@ -249,6 +252,7 @@ jobs: SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (arm32, Bionic, GCC, OpenSSL)" + id: bionic-arm32-gcc-openssl container: name: bionic-arm32 dockerfile: bionic @@ -263,6 +267,7 @@ jobs: GITTEST_FLAKY_STAT: true os: ubuntu-latest - name: "Linux (arm64, Bionic, GCC, OpenSSL)" + id: bionic-arm64-gcc-openssl container: name: bionic-arm64 dockerfile: bionic @@ -300,6 +305,7 @@ jobs: SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - name: "Windows (no mmap)" + id: windows-nommap os: windows-2019 env: ARCH: amd64 From 4d19e8c9c5113fc68dde130af3f6e66c2bd00f65 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 27 Mar 2024 09:59:48 +0000 Subject: [PATCH 491/816] settings: pull settings out into its own file --- src/libgit2/libgit2.c | 392 +------------------------------ src/libgit2/libgit2.h | 15 -- src/libgit2/settings.c | 408 +++++++++++++++++++++++++++++++++ src/libgit2/settings.h | 7 +- src/libgit2/streams/openssl.c | 4 +- src/libgit2/transports/http.h | 2 +- tests/libgit2/core/useragent.c | 4 +- 7 files changed, 422 insertions(+), 410 deletions(-) delete mode 100644 src/libgit2/libgit2.h create mode 100644 src/libgit2/settings.c diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 777dcbbb558..1b6f1a1f846 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -5,25 +5,19 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "libgit2.h" - #include #include "alloc.h" #include "buf.h" -#include "cache.h" #include "common.h" #include "filter.h" -#include "grafts.h" #include "hash.h" -#include "index.h" #include "merge_driver.h" #include "pool.h" #include "mwindow.h" -#include "object.h" -#include "odb.h" +#include "oid.h" #include "rand.h" -#include "refs.h" #include "runtime.h" +#include "settings.h" #include "sysdir.h" #include "thread.h" #include "git2/global.h" @@ -31,40 +25,12 @@ #include "streams/mbedtls.h" #include "streams/openssl.h" #include "streams/socket.h" -#include "transports/smart.h" -#include "transports/http.h" #include "transports/ssh_libssh2.h" #ifdef GIT_WIN32 # include "win32/w32_leakcheck.h" #endif -/* Declarations for tuneable settings */ -extern size_t git_mwindow__window_size; -extern size_t git_mwindow__mapped_limit; -extern size_t git_mwindow__file_limit; -extern size_t git_indexer__max_objects; -extern bool git_disable_pack_keep_file_checks; -extern int git_odb__packed_priority; -extern int git_odb__loose_priority; -extern int git_socket_stream__connect_timeout; -extern int git_socket_stream__timeout; - -char *git__user_agent; -char *git__ssl_ciphers; - -static void libgit2_settings_global_shutdown(void) -{ - git__free(git__user_agent); - git__free(git__ssl_ciphers); - git_repository__free_extensions(); -} - -static int git_libgit2_settings_global_init(void) -{ - return git_runtime_shutdown_register(libgit2_settings_global_shutdown); -} - int git_libgit2_init(void) { static git_runtime_init_fn init_fns[] = { @@ -87,17 +53,12 @@ int git_libgit2_init(void) git_mbedtls_stream_global_init, git_mwindow_global_init, git_pool_global_init, - git_libgit2_settings_global_init + git_settings_global_init }; return git_runtime_init(init_fns, ARRAY_SIZE(init_fns)); } -int git_libgit2_init_count(void) -{ - return git_runtime_init_count(); -} - int git_libgit2_shutdown(void) { return git_runtime_shutdown(); @@ -134,350 +95,3 @@ int git_libgit2_features(void) #endif ; } - -static int config_level_to_sysdir(int *out, int config_level) -{ - switch (config_level) { - case GIT_CONFIG_LEVEL_SYSTEM: - *out = GIT_SYSDIR_SYSTEM; - return 0; - case GIT_CONFIG_LEVEL_XDG: - *out = GIT_SYSDIR_XDG; - return 0; - case GIT_CONFIG_LEVEL_GLOBAL: - *out = GIT_SYSDIR_GLOBAL; - return 0; - case GIT_CONFIG_LEVEL_PROGRAMDATA: - *out = GIT_SYSDIR_PROGRAMDATA; - return 0; - default: - break; - } - - git_error_set( - GIT_ERROR_INVALID, "invalid config path selector %d", config_level); - return -1; -} - -const char *git_libgit2__user_agent(void) -{ - return git__user_agent; -} - -const char *git_libgit2__ssl_ciphers(void) -{ - return git__ssl_ciphers; -} - -int git_libgit2_opts(int key, ...) -{ - int error = 0; - va_list ap; - - va_start(ap, key); - - switch (key) { - case GIT_OPT_SET_MWINDOW_SIZE: - git_mwindow__window_size = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_MWINDOW_SIZE: - *(va_arg(ap, size_t *)) = git_mwindow__window_size; - break; - - case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT: - git_mwindow__mapped_limit = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT: - *(va_arg(ap, size_t *)) = git_mwindow__mapped_limit; - break; - - case GIT_OPT_SET_MWINDOW_FILE_LIMIT: - git_mwindow__file_limit = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_MWINDOW_FILE_LIMIT: - *(va_arg(ap, size_t *)) = git_mwindow__file_limit; - break; - - case GIT_OPT_GET_SEARCH_PATH: - { - int sysdir = va_arg(ap, int); - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - const git_str *tmp; - int level; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = config_level_to_sysdir(&level, sysdir)) < 0 || - (error = git_sysdir_get(&tmp, level)) < 0 || - (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - - case GIT_OPT_SET_SEARCH_PATH: - { - int level; - - if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0) - error = git_sysdir_set(level, va_arg(ap, const char *)); - } - break; - - case GIT_OPT_SET_CACHE_OBJECT_LIMIT: - { - git_object_t type = (git_object_t)va_arg(ap, int); - size_t size = va_arg(ap, size_t); - error = git_cache_set_max_object_size(type, size); - break; - } - - case GIT_OPT_SET_CACHE_MAX_SIZE: - git_cache__max_storage = va_arg(ap, ssize_t); - break; - - case GIT_OPT_ENABLE_CACHING: - git_cache__enabled = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_GET_CACHED_MEMORY: - *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; - *(va_arg(ap, ssize_t *)) = git_cache__max_storage; - break; - - case GIT_OPT_GET_TEMPLATE_PATH: - { - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - const git_str *tmp; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0 || - (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - - case GIT_OPT_SET_TEMPLATE_PATH: - error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *)); - break; - - case GIT_OPT_SET_SSL_CERT_LOCATIONS: -#ifdef GIT_OPENSSL - { - const char *file = va_arg(ap, const char *); - const char *path = va_arg(ap, const char *); - error = git_openssl__set_cert_location(file, path); - } -#elif defined(GIT_MBEDTLS) - { - const char *file = va_arg(ap, const char *); - const char *path = va_arg(ap, const char *); - error = git_mbedtls__set_cert_location(file, path); - } -#else - git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations"); - error = -1; -#endif - break; - case GIT_OPT_SET_USER_AGENT: - git__free(git__user_agent); - git__user_agent = git__strdup(va_arg(ap, const char *)); - if (!git__user_agent) { - git_error_set_oom(); - error = -1; - } - - break; - - case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION: - git_object__strict_input_validation = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: - git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_SSL_CIPHERS: -#if (GIT_OPENSSL || GIT_MBEDTLS) - { - git__free(git__ssl_ciphers); - git__ssl_ciphers = git__strdup(va_arg(ap, const char *)); - if (!git__ssl_ciphers) { - git_error_set_oom(); - error = -1; - } - } -#else - git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers"); - error = -1; -#endif - break; - - case GIT_OPT_GET_USER_AGENT: - { - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = git_str_puts(&str, git__user_agent)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - - case GIT_OPT_ENABLE_OFS_DELTA: - git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_ENABLE_FSYNC_GITDIR: - git_repository__fsync_gitdir = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_GET_WINDOWS_SHAREMODE: -#ifdef GIT_WIN32 - *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode; -#endif - break; - - case GIT_OPT_SET_WINDOWS_SHAREMODE: -#ifdef GIT_WIN32 - git_win32__createfile_sharemode = va_arg(ap, unsigned long); -#endif - break; - - case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION: - git_odb__strict_hash_verification = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_ALLOCATOR: - error = git_allocator_setup(va_arg(ap, git_allocator *)); - break; - - case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY: - git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_PACK_MAX_OBJECTS: - git_indexer__max_objects = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_PACK_MAX_OBJECTS: - *(va_arg(ap, size_t *)) = git_indexer__max_objects; - break; - - case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS: - git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE: - git_http__expect_continue = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_ODB_PACKED_PRIORITY: - git_odb__packed_priority = va_arg(ap, int); - break; - - case GIT_OPT_SET_ODB_LOOSE_PRIORITY: - git_odb__loose_priority = va_arg(ap, int); - break; - - case GIT_OPT_SET_EXTENSIONS: - { - const char **extensions = va_arg(ap, const char **); - size_t len = va_arg(ap, size_t); - error = git_repository__set_extensions(extensions, len); - } - break; - - case GIT_OPT_GET_EXTENSIONS: - { - git_strarray *out = va_arg(ap, git_strarray *); - char **extensions; - size_t len; - - if ((error = git_repository__extensions(&extensions, &len)) < 0) - break; - - out->strings = extensions; - out->count = len; - } - break; - - case GIT_OPT_GET_OWNER_VALIDATION: - *(va_arg(ap, int *)) = git_repository__validate_ownership; - break; - - case GIT_OPT_SET_OWNER_VALIDATION: - git_repository__validate_ownership = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_GET_HOMEDIR: - { - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - const git_str *tmp; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = git_sysdir_get(&tmp, GIT_SYSDIR_HOME)) < 0 || - (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - - case GIT_OPT_SET_HOMEDIR: - error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *)); - break; - - case GIT_OPT_GET_SERVER_CONNECT_TIMEOUT: - *(va_arg(ap, int *)) = git_socket_stream__connect_timeout; - break; - - case GIT_OPT_SET_SERVER_CONNECT_TIMEOUT: - { - int timeout = va_arg(ap, int); - - if (timeout < 0) { - git_error_set(GIT_ERROR_INVALID, "invalid connect timeout"); - error = -1; - } else { - git_socket_stream__connect_timeout = timeout; - } - } - break; - - case GIT_OPT_GET_SERVER_TIMEOUT: - *(va_arg(ap, int *)) = git_socket_stream__timeout; - break; - - case GIT_OPT_SET_SERVER_TIMEOUT: - { - int timeout = va_arg(ap, int); - - if (timeout < 0) { - git_error_set(GIT_ERROR_INVALID, "invalid timeout"); - error = -1; - } else { - git_socket_stream__timeout = timeout; - } - } - break; - - default: - git_error_set(GIT_ERROR_INVALID, "invalid option key"); - error = -1; - } - - va_end(ap); - - return error; -} diff --git a/src/libgit2/libgit2.h b/src/libgit2/libgit2.h deleted file mode 100644 index a898367ae37..00000000000 --- a/src/libgit2/libgit2.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_libgit2_h__ -#define INCLUDE_libgit2_h__ - -extern int git_libgit2_init_count(void); - -extern const char *git_libgit2__user_agent(void); -extern const char *git_libgit2__ssl_ciphers(void); - -#endif diff --git a/src/libgit2/settings.c b/src/libgit2/settings.c new file mode 100644 index 00000000000..96a910d70cd --- /dev/null +++ b/src/libgit2/settings.c @@ -0,0 +1,408 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "settings.h" + +#include +#include "alloc.h" +#include "buf.h" +#include "cache.h" +#include "common.h" +#include "filter.h" +#include "grafts.h" +#include "hash.h" +#include "index.h" +#include "merge_driver.h" +#include "pool.h" +#include "mwindow.h" +#include "object.h" +#include "odb.h" +#include "rand.h" +#include "refs.h" +#include "runtime.h" +#include "sysdir.h" +#include "thread.h" +#include "git2/global.h" +#include "streams/registry.h" +#include "streams/mbedtls.h" +#include "streams/openssl.h" +#include "streams/socket.h" +#include "transports/smart.h" +#include "transports/http.h" +#include "transports/ssh_libssh2.h" + +#ifdef GIT_WIN32 +# include "win32/w32_leakcheck.h" +#endif + +/* Declarations for tuneable settings */ +extern size_t git_mwindow__window_size; +extern size_t git_mwindow__mapped_limit; +extern size_t git_mwindow__file_limit; +extern size_t git_indexer__max_objects; +extern bool git_disable_pack_keep_file_checks; +extern int git_odb__packed_priority; +extern int git_odb__loose_priority; +extern int git_socket_stream__connect_timeout; +extern int git_socket_stream__timeout; + +char *git__user_agent; +char *git__ssl_ciphers; + +static void settings_global_shutdown(void) +{ + git__free(git__user_agent); + git__free(git__ssl_ciphers); + git_repository__free_extensions(); +} + +int git_settings_global_init(void) +{ + return git_runtime_shutdown_register(settings_global_shutdown); +} + +static int config_level_to_sysdir(int *out, int config_level) +{ + switch (config_level) { + case GIT_CONFIG_LEVEL_SYSTEM: + *out = GIT_SYSDIR_SYSTEM; + return 0; + case GIT_CONFIG_LEVEL_XDG: + *out = GIT_SYSDIR_XDG; + return 0; + case GIT_CONFIG_LEVEL_GLOBAL: + *out = GIT_SYSDIR_GLOBAL; + return 0; + case GIT_CONFIG_LEVEL_PROGRAMDATA: + *out = GIT_SYSDIR_PROGRAMDATA; + return 0; + default: + break; + } + + git_error_set( + GIT_ERROR_INVALID, "invalid config path selector %d", config_level); + return -1; +} + +const char *git_settings__user_agent(void) +{ + return git__user_agent; +} + +int git_libgit2_opts(int key, ...) +{ + int error = 0; + va_list ap; + + va_start(ap, key); + + switch (key) { + case GIT_OPT_SET_MWINDOW_SIZE: + git_mwindow__window_size = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_MWINDOW_SIZE: + *(va_arg(ap, size_t *)) = git_mwindow__window_size; + break; + + case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT: + git_mwindow__mapped_limit = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT: + *(va_arg(ap, size_t *)) = git_mwindow__mapped_limit; + break; + + case GIT_OPT_SET_MWINDOW_FILE_LIMIT: + git_mwindow__file_limit = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_MWINDOW_FILE_LIMIT: + *(va_arg(ap, size_t *)) = git_mwindow__file_limit; + break; + + case GIT_OPT_GET_SEARCH_PATH: + { + int sysdir = va_arg(ap, int); + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + const git_str *tmp; + int level; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = config_level_to_sysdir(&level, sysdir)) < 0 || + (error = git_sysdir_get(&tmp, level)) < 0 || + (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_SEARCH_PATH: + { + int level; + + if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0) + error = git_sysdir_set(level, va_arg(ap, const char *)); + } + break; + + case GIT_OPT_SET_CACHE_OBJECT_LIMIT: + { + git_object_t type = (git_object_t)va_arg(ap, int); + size_t size = va_arg(ap, size_t); + error = git_cache_set_max_object_size(type, size); + break; + } + + case GIT_OPT_SET_CACHE_MAX_SIZE: + git_cache__max_storage = va_arg(ap, ssize_t); + break; + + case GIT_OPT_ENABLE_CACHING: + git_cache__enabled = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_GET_CACHED_MEMORY: + *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; + *(va_arg(ap, ssize_t *)) = git_cache__max_storage; + break; + + case GIT_OPT_GET_TEMPLATE_PATH: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + const git_str *tmp; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0 || + (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_TEMPLATE_PATH: + error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *)); + break; + + case GIT_OPT_SET_SSL_CERT_LOCATIONS: +#ifdef GIT_OPENSSL + { + const char *file = va_arg(ap, const char *); + const char *path = va_arg(ap, const char *); + error = git_openssl__set_cert_location(file, path); + } +#elif defined(GIT_MBEDTLS) + { + const char *file = va_arg(ap, const char *); + const char *path = va_arg(ap, const char *); + error = git_mbedtls__set_cert_location(file, path); + } +#else + git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations"); + error = -1; +#endif + break; + case GIT_OPT_SET_USER_AGENT: + git__free(git__user_agent); + git__user_agent = git__strdup(va_arg(ap, const char *)); + if (!git__user_agent) { + git_error_set_oom(); + error = -1; + } + + break; + + case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION: + git_object__strict_input_validation = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: + git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_SSL_CIPHERS: +#if (GIT_OPENSSL || GIT_MBEDTLS) + { + git__free(git__ssl_ciphers); + git__ssl_ciphers = git__strdup(va_arg(ap, const char *)); + if (!git__ssl_ciphers) { + git_error_set_oom(); + error = -1; + } + } +#else + git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers"); + error = -1; +#endif + break; + + case GIT_OPT_GET_USER_AGENT: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_str_puts(&str, git__user_agent)) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_ENABLE_OFS_DELTA: + git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_ENABLE_FSYNC_GITDIR: + git_repository__fsync_gitdir = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_GET_WINDOWS_SHAREMODE: +#ifdef GIT_WIN32 + *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode; +#endif + break; + + case GIT_OPT_SET_WINDOWS_SHAREMODE: +#ifdef GIT_WIN32 + git_win32__createfile_sharemode = va_arg(ap, unsigned long); +#endif + break; + + case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION: + git_odb__strict_hash_verification = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_ALLOCATOR: + error = git_allocator_setup(va_arg(ap, git_allocator *)); + break; + + case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY: + git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_PACK_MAX_OBJECTS: + git_indexer__max_objects = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_PACK_MAX_OBJECTS: + *(va_arg(ap, size_t *)) = git_indexer__max_objects; + break; + + case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS: + git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE: + git_http__expect_continue = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_ODB_PACKED_PRIORITY: + git_odb__packed_priority = va_arg(ap, int); + break; + + case GIT_OPT_SET_ODB_LOOSE_PRIORITY: + git_odb__loose_priority = va_arg(ap, int); + break; + + case GIT_OPT_SET_EXTENSIONS: + { + const char **extensions = va_arg(ap, const char **); + size_t len = va_arg(ap, size_t); + error = git_repository__set_extensions(extensions, len); + } + break; + + case GIT_OPT_GET_EXTENSIONS: + { + git_strarray *out = va_arg(ap, git_strarray *); + char **extensions; + size_t len; + + if ((error = git_repository__extensions(&extensions, &len)) < 0) + break; + + out->strings = extensions; + out->count = len; + } + break; + + case GIT_OPT_GET_OWNER_VALIDATION: + *(va_arg(ap, int *)) = git_repository__validate_ownership; + break; + + case GIT_OPT_SET_OWNER_VALIDATION: + git_repository__validate_ownership = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_GET_HOMEDIR: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + const git_str *tmp; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_sysdir_get(&tmp, GIT_SYSDIR_HOME)) < 0 || + (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_HOMEDIR: + error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *)); + break; + + case GIT_OPT_GET_SERVER_CONNECT_TIMEOUT: + *(va_arg(ap, int *)) = git_socket_stream__connect_timeout; + break; + + case GIT_OPT_SET_SERVER_CONNECT_TIMEOUT: + { + int timeout = va_arg(ap, int); + + if (timeout < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid connect timeout"); + error = -1; + } else { + git_socket_stream__connect_timeout = timeout; + } + } + break; + + case GIT_OPT_GET_SERVER_TIMEOUT: + *(va_arg(ap, int *)) = git_socket_stream__timeout; + break; + + case GIT_OPT_SET_SERVER_TIMEOUT: + { + int timeout = va_arg(ap, int); + + if (timeout < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid timeout"); + error = -1; + } else { + git_socket_stream__timeout = timeout; + } + } + break; + + default: + git_error_set(GIT_ERROR_INVALID, "invalid option key"); + error = -1; + } + + va_end(ap); + + return error; +} diff --git a/src/libgit2/settings.h b/src/libgit2/settings.h index dc42ce93952..18ee5280ac7 100644 --- a/src/libgit2/settings.h +++ b/src/libgit2/settings.h @@ -4,8 +4,11 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ +#ifndef INCLUDE_settings_h__ +#define INCLUDE_settings_h__ extern int git_settings_global_init(void); -extern const char *git_libgit2__user_agent(void); -extern const char *git_libgit2__ssl_ciphers(void); +extern const char *git_settings__user_agent(void); + +#endif diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index 9db911e39b3..7cb8f7f927c 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -36,6 +36,8 @@ # include #endif +extern char *git__ssl_ciphers; + SSL_CTX *git__ssl_ctx; #define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" @@ -105,7 +107,7 @@ static void git_openssl_free(void *mem) static int openssl_init(void) { long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; - const char *ciphers = git_libgit2__ssl_ciphers(); + const char *ciphers = git__ssl_ciphers; #ifdef VALGRIND static bool allocators_initialized = false; #endif diff --git a/src/libgit2/transports/http.h b/src/libgit2/transports/http.h index 8e8e7226ed2..3d73237dd0f 100644 --- a/src/libgit2/transports/http.h +++ b/src/libgit2/transports/http.h @@ -17,7 +17,7 @@ extern bool git_http__expect_continue; GIT_INLINE(int) git_http__user_agent(git_str *buf) { - const char *ua = git_libgit2__user_agent(); + const char *ua = git_settings__user_agent(); if (!ua) ua = "libgit2 " LIBGIT2_VERSION; diff --git a/tests/libgit2/core/useragent.c b/tests/libgit2/core/useragent.c index a4ece902fd9..697f7440db6 100644 --- a/tests/libgit2/core/useragent.c +++ b/tests/libgit2/core/useragent.c @@ -6,9 +6,9 @@ void test_core_useragent__get(void) const char *custom_name = "super duper git"; git_str buf = GIT_STR_INIT; - cl_assert_equal_p(NULL, git_libgit2__user_agent()); + cl_assert_equal_p(NULL, git_settings__user_agent()); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, custom_name)); - cl_assert_equal_s(custom_name, git_libgit2__user_agent()); + cl_assert_equal_s(custom_name, git_settings__user_agent()); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_USER_AGENT, &buf)); cl_assert_equal_s(custom_name, buf.ptr); From 4839f4fbfc3bfd9e19ac140ed9b5654861b97596 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 27 Mar 2024 11:56:45 +0000 Subject: [PATCH 492/816] http: allow users more control over user-agent Users can now override the "product" portion of the user-agent (via GIT_OPT_SET_USER_AGENT_PRODUCT). This continues to default to "git/2.0", but users may define their own string, or may opt out of sending a user-agent entirely (by passing an empty string). Similarly, users may now also opt-out of sending any additional "comment" information by setting the GIT_OPT_SET_USER_AGENT value to an empty string. --- include/git2/common.h | 41 ++++++++++---- src/libgit2/settings.c | 86 ++++++++++++++++++++++------- src/libgit2/settings.h | 1 + src/libgit2/transports/http.h | 10 ---- src/libgit2/transports/httpclient.c | 32 +++++++++-- src/libgit2/transports/winhttp.c | 34 +++++++++++- tests/libgit2/core/useragent.c | 53 +++++++++++++++--- 7 files changed, 200 insertions(+), 57 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 0f42c34f683..b7cf20b31c9 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -228,7 +228,9 @@ typedef enum { GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, GIT_OPT_GET_SERVER_CONNECT_TIMEOUT, GIT_OPT_SET_SERVER_TIMEOUT, - GIT_OPT_GET_SERVER_TIMEOUT + GIT_OPT_GET_SERVER_TIMEOUT, + GIT_OPT_SET_USER_AGENT_PRODUCT, + GIT_OPT_GET_USER_AGENT_PRODUCT } git_libgit2_opt_t; /** @@ -337,11 +339,35 @@ typedef enum { * * * opts(GIT_OPT_SET_USER_AGENT, const char *user_agent) * - * > Set the value of the User-Agent header. This value will be - * > appended to "git/1.0", for compatibility with other git clients. + * > Set the value of the comment section of the User-Agent header. + * > This can be information about your product and its version. + * > By default this is "libgit2" followed by the libgit2 version. * > - * > - `user_agent` is the value that will be delivered as the - * > User-Agent header on HTTP requests. + * > This value will be appended to User-Agent _product_, which + * > is typically set to "git/2.0". + * > + * > Set to the empty string ("") to not send any information in the + * > comment section, or set to NULL to restore the default. + * + * * opts(GIT_OPT_GET_USER_AGENT, git_buf *out) + * + * > Get the value of the User-Agent header. + * > The User-Agent is written to the `out` buffer. + * + * * opts(GIT_OPT_SET_USER_AGENT_PRODUCT, const char *user_agent_product) + * + * > Set the value of the product portion of the User-Agent header. + * > This defaults to "git/2.0", for compatibility with other git + * > clients. It is recommended to keep this as git/ for + * > compatibility with servers that do user-agent detection. + * > + * > Set to the empty string ("") to not send any user-agent string, + * > or set to NULL to restore the default. + * + * * opts(GIT_OPT_GET_USER_AGENT_PRODUCT, git_buf *out) + * + * > Get the value of the User-Agent product header. + * > The User-Agent product is written to the `out` buffer. * * * opts(GIT_OPT_SET_WINDOWS_SHAREMODE, unsigned long value) * @@ -377,11 +403,6 @@ typedef enum { * > * > - `ciphers` is the list of ciphers that are eanbled. * - * * opts(GIT_OPT_GET_USER_AGENT, git_buf *out) - * - * > Get the value of the User-Agent header. - * > The User-Agent is written to the `out` buffer. - * * * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled) * * > Enable or disable the use of "offset deltas" when creating packfiles, diff --git a/src/libgit2/settings.c b/src/libgit2/settings.c index 96a910d70cd..4a41830b8fd 100644 --- a/src/libgit2/settings.c +++ b/src/libgit2/settings.c @@ -51,11 +51,14 @@ extern int git_socket_stream__connect_timeout; extern int git_socket_stream__timeout; char *git__user_agent; +char *git__user_agent_product; char *git__ssl_ciphers; static void settings_global_shutdown(void) { git__free(git__user_agent); + git__free(git__user_agent_product); + git__free(git__ssl_ciphers); git_repository__free_extensions(); } @@ -89,9 +92,16 @@ static int config_level_to_sysdir(int *out, int config_level) return -1; } +const char *git_settings__user_agent_product(void) +{ + return git__user_agent_product ? git__user_agent_product : + "git/2.0"; +} + const char *git_settings__user_agent(void) { - return git__user_agent; + return git__user_agent ? git__user_agent : + "libgit2 " LIBGIT2_VERSION; } int git_libgit2_opts(int key, ...) @@ -211,14 +221,65 @@ int git_libgit2_opts(int key, ...) error = -1; #endif break; + case GIT_OPT_SET_USER_AGENT: - git__free(git__user_agent); - git__user_agent = git__strdup(va_arg(ap, const char *)); - if (!git__user_agent) { - git_error_set_oom(); - error = -1; + { + const char *new_agent = va_arg(ap, const char *); + + git__free(git__user_agent); + + if (new_agent) { + git__user_agent= git__strdup(new_agent); + + if (!git__user_agent) + error = -1; + } else { + git__user_agent = NULL; + } + } + break; + + case GIT_OPT_GET_USER_AGENT: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_str_puts(&str, git_settings__user_agent())) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_USER_AGENT_PRODUCT: + { + const char *new_agent = va_arg(ap, const char *); + + git__free(git__user_agent_product); + + if (new_agent) { + git__user_agent_product = git__strdup(new_agent); + + if (!git__user_agent_product) + error = -1; + } else { + git__user_agent_product = NULL; + } } + break; + + case GIT_OPT_GET_USER_AGENT_PRODUCT: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_str_puts(&str, git_settings__user_agent_product())) < 0) + break; + + error = git_buf_fromstr(out, &str); + } break; case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION: @@ -245,19 +306,6 @@ int git_libgit2_opts(int key, ...) #endif break; - case GIT_OPT_GET_USER_AGENT: - { - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = git_str_puts(&str, git__user_agent)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - case GIT_OPT_ENABLE_OFS_DELTA: git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0); break; diff --git a/src/libgit2/settings.h b/src/libgit2/settings.h index 18ee5280ac7..292936676aa 100644 --- a/src/libgit2/settings.h +++ b/src/libgit2/settings.h @@ -10,5 +10,6 @@ extern int git_settings_global_init(void); extern const char *git_settings__user_agent(void); +extern const char *git_settings__user_agent_product(void); #endif diff --git a/src/libgit2/transports/http.h b/src/libgit2/transports/http.h index 3d73237dd0f..7410202a820 100644 --- a/src/libgit2/transports/http.h +++ b/src/libgit2/transports/http.h @@ -15,14 +15,4 @@ extern bool git_http__expect_continue; -GIT_INLINE(int) git_http__user_agent(git_str *buf) -{ - const char *ua = git_settings__user_agent(); - - if (!ua) - ua = "libgit2 " LIBGIT2_VERSION; - - return git_str_printf(buf, "git/2.0 (%s)", ua); -} - #endif diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index e22a07ba1a0..2c2e36859a7 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -651,6 +651,30 @@ static int puts_host_and_port(git_str *buf, git_net_url *url, bool force_port) return git_str_oom(buf) ? -1 : 0; } +static int append_user_agent(git_str *buf) +{ + const char *product = git_settings__user_agent_product(); + const char *comment = git_settings__user_agent(); + + GIT_ASSERT(product && comment); + + if (!*product) + return 0; + + git_str_puts(buf, "User-Agent: "); + git_str_puts(buf, product); + + if (*comment) { + git_str_puts(buf, " ("); + git_str_puts(buf, comment); + git_str_puts(buf, ")"); + } + + git_str_puts(buf, "\r\n"); + + return git_str_oom(buf) ? -1 : 0; +} + static int generate_connect_request( git_http_client *client, git_http_request *request) @@ -665,9 +689,7 @@ static int generate_connect_request( puts_host_and_port(buf, &client->server.url, true); git_str_puts(buf, " HTTP/1.1\r\n"); - git_str_puts(buf, "User-Agent: "); - git_http__user_agent(buf); - git_str_puts(buf, "\r\n"); + append_user_agent(buf); git_str_puts(buf, "Host: "); puts_host_and_port(buf, &client->server.url, true); @@ -711,9 +733,7 @@ static int generate_request( git_str_puts(buf, " HTTP/1.1\r\n"); - git_str_puts(buf, "User-Agent: "); - git_http__user_agent(buf); - git_str_puts(buf, "\r\n"); + append_user_agent(buf); git_str_puts(buf, "Host: "); puts_host_and_port(buf, request->url, false); diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index 031ff3f70b0..7eca4b7443b 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -746,6 +746,33 @@ static void CALLBACK winhttp_status( } } +static int user_agent(bool *exists, git_str *out) +{ + const char *product = git_settings__user_agent_product(); + const char *comment = git_settings__user_agent(); + + GIT_ASSERT(product && comment); + + if (!*product) { + *exists = false; + return 0; + } + + git_str_puts(out, product); + + if (*comment) { + git_str_puts(out, " ("); + git_str_puts(out, comment); + git_str_puts(out, ")"); + } + + if (git_str_oom(out)) + return -1; + + *exists = true; + return 0; +} + static int winhttp_connect( winhttp_subtransport *t) { @@ -757,6 +784,7 @@ static int winhttp_connect( int error = -1; int default_timeout = TIMEOUT_INFINITE; int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT; + bool has_ua = true; DWORD protocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | @@ -787,11 +815,11 @@ static int winhttp_connect( goto on_error; } - - if (git_http__user_agent(&ua) < 0) + if (user_agent(&has_ua, &ua) < 0) goto on_error; - if (git_utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) { + if (has_ua && + git_utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) { git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters"); goto on_error; } diff --git a/tests/libgit2/core/useragent.c b/tests/libgit2/core/useragent.c index 697f7440db6..2e119de4490 100644 --- a/tests/libgit2/core/useragent.c +++ b/tests/libgit2/core/useragent.c @@ -1,17 +1,52 @@ #include "clar_libgit2.h" #include "settings.h" -void test_core_useragent__get(void) +static git_buf default_ua = GIT_BUF_INIT; +static git_buf default_product = GIT_BUF_INIT; + +void test_core_useragent__initialize(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_GET_USER_AGENT, &default_ua)); + cl_git_pass(git_libgit2_opts(GIT_OPT_GET_USER_AGENT_PRODUCT, &default_product)); +} + +void test_core_useragent__cleanup(void) +{ + git_libgit2_opts(GIT_OPT_SET_USER_AGENT, NULL); + git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, NULL); + + git_buf_dispose(&default_ua); + git_buf_dispose(&default_product); +} + +void test_core_useragent__get_default(void) +{ + cl_assert(default_ua.size); + cl_assert(default_ua.ptr); + cl_assert(git__prefixcmp(default_ua.ptr, "libgit2 ") == 0); + + cl_assert(default_product.size); + cl_assert(default_product.ptr); + cl_assert(git__prefixcmp(default_product.ptr, "git/") == 0); +} + +void test_core_useragent__set(void) { - const char *custom_name = "super duper git"; - git_str buf = GIT_STR_INIT; + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, "foo bar 4.24")); + cl_assert_equal_s("foo bar 4.24", git_settings__user_agent()); + cl_assert_equal_s(default_product.ptr, git_settings__user_agent_product()); - cl_assert_equal_p(NULL, git_settings__user_agent()); - cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, custom_name)); - cl_assert_equal_s(custom_name, git_settings__user_agent()); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, "baz/2.2.3")); + cl_assert_equal_s("foo bar 4.24", git_settings__user_agent()); + cl_assert_equal_s("baz/2.2.3", git_settings__user_agent_product()); - cl_git_pass(git_libgit2_opts(GIT_OPT_GET_USER_AGENT, &buf)); - cl_assert_equal_s(custom_name, buf.ptr); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, "")); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, "")); + cl_assert_equal_s("", git_settings__user_agent()); + cl_assert_equal_s("", git_settings__user_agent_product()); - git_str_dispose(&buf); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, NULL)); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, NULL)); + cl_assert_equal_s(default_ua.ptr, git_settings__user_agent()); + cl_assert_equal_s(default_product.ptr, git_settings__user_agent_product()); } From 6bed71e05d77566423756060032e4cdd467085f8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 2 Apr 2024 22:08:50 +0100 Subject: [PATCH 493/816] docs: update includes Update our headers so that they can include the necessary definitions. Docs generators (in particular, `clang -Xclang -ast-dump`) were unable to see the necessary definitions. --- include/git2/email.h | 1 + include/git2/sys/email.h | 5 +++++ include/git2/worktree.h | 1 + 3 files changed, 7 insertions(+) diff --git a/include/git2/email.h b/include/git2/email.h index 20393653e9f..3389353e796 100644 --- a/include/git2/email.h +++ b/include/git2/email.h @@ -8,6 +8,7 @@ #define INCLUDE_git_email_h__ #include "common.h" +#include "diff.h" /** * @file git2/email.h diff --git a/include/git2/sys/email.h b/include/git2/sys/email.h index 6f4a2866209..5029f9a532c 100644 --- a/include/git2/sys/email.h +++ b/include/git2/sys/email.h @@ -7,6 +7,11 @@ #ifndef INCLUDE_sys_git_email_h__ #define INCLUDE_sys_git_email_h__ +#include "git2/common.h" +#include "git2/diff.h" +#include "git2/email.h" +#include "git2/types.h" + /** * @file git2/sys/email.h * @brief Advanced git email creation routines diff --git a/include/git2/worktree.h b/include/git2/worktree.h index 1af4c038573..a6e5d17c4b1 100644 --- a/include/git2/worktree.h +++ b/include/git2/worktree.h @@ -11,6 +11,7 @@ #include "buffer.h" #include "types.h" #include "strarray.h" +#include "checkout.h" /** * @file git2/worktrees.h From 6122f008c6f247a4729d246d9c469c2f1d3bf685 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 2 Apr 2024 22:13:24 +0100 Subject: [PATCH 494/816] docs: it's _return_ not _returns_ --- include/git2/refspec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/git2/refspec.h b/include/git2/refspec.h index eaf7747465c..e7087132b04 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -58,7 +58,7 @@ GIT_EXTERN(const char *) git_refspec_dst(const git_refspec *refspec); * Get the refspec's string * * @param refspec the refspec - * @returns the refspec's original string + * @return the refspec's original string */ GIT_EXTERN(const char *) git_refspec_string(const git_refspec *refspec); From cc2a01524d7ff0cbab60b4c68908a364ea960360 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 2 Apr 2024 22:13:53 +0100 Subject: [PATCH 495/816] docs: document `git_remote_capability_t` --- include/git2/sys/remote.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/git2/sys/remote.h b/include/git2/sys/remote.h index 07309ab09b6..58950e1ec77 100644 --- a/include/git2/sys/remote.h +++ b/include/git2/sys/remote.h @@ -20,6 +20,9 @@ GIT_BEGIN_DECL +/** + * A remote's capabilities. + */ typedef enum { /** Remote supports fetching an advertised object by ID. */ GIT_REMOTE_CAPABILITY_TIP_OID = (1 << 0), From 4b043541ab480aaa083707c134c23d17be5baafc Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 8 Apr 2024 03:46:17 +0800 Subject: [PATCH 496/816] process.c: fix environ for macOS --- src/util/unix/process.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 15092cb217f..68c0384a4c4 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -15,7 +15,12 @@ #include "process.h" #include "strlist.h" -extern char **environ; +#ifdef __APPLE__ + #include + #define environ (*_NSGetEnviron()) +#else + extern char **environ; +#endif struct git_process { char **args; From 387d01c18633175adb05aaad1f0428dcf6a5c254 Mon Sep 17 00:00:00 2001 From: Jason Haslam Date: Wed, 10 Apr 2024 21:29:54 -0600 Subject: [PATCH 497/816] cmake: remove workaround that isn't compatible with Windows on ARM --- src/libgit2/CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index 876a703e857..bc7cb5b3597 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -65,12 +65,6 @@ set_target_properties(libgit2package PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJE set_target_properties(libgit2package PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set_target_properties(libgit2package PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) -# Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240) -# Win64+MSVC+static libs = linker error -if(MSVC AND GIT_ARCH_64 AND NOT BUILD_SHARED_LIBS) - set_target_properties(libgit2package PROPERTIES STATIC_LIBRARY_FLAGS "/MACHINE:x64") -endif() - ide_split_sources(libgit2package) if(SONAME) From 6e8227ab38952cf3575eb76f64f80dc536d36ec9 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 15 Apr 2024 09:36:12 -0600 Subject: [PATCH 498/816] Bounds check for pack index read Fixes: https://github.com/libgit2/libgit2/issues/6795 Co-Authored-By: Bennet --- src/libgit2/pack.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index eff73988278..566f8c51ae5 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -1525,6 +1525,14 @@ static int pack_entry_find_offset( if (p->index_version > 1) { level1_ofs += 2; index += 8; + + if ((int)short_oid->id[0] + 2 >= p->index_map.len) { + git_error_set(GIT_ERROR_INTERNAL, "internal error: p->short_oid->[0] out of bounds"); + goto cleanup; + } + } else if ((int)short_oid->id[0] >= p->index_map.len) { + git_error_set(GIT_ERROR_INTERNAL, "internal error: p->short_oid->[0] out of bounds"); + goto cleanup; } index += 4 * 256; From 06cafdf9d8ff70d78a82223fe87d1ad3b83fde29 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 Apr 2024 09:58:47 +0100 Subject: [PATCH 499/816] pack: upcast to `size_t` for bounds checking --- src/libgit2/pack.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index 566f8c51ae5..1ff0eb0c9d9 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -1499,6 +1499,7 @@ static int pack_entry_find_offset( size_t len) { const uint32_t *level1_ofs; + size_t ofs_delta = 0; const unsigned char *index; unsigned hi, lo, stride; int pos, found = 0; @@ -1524,13 +1525,11 @@ static int pack_entry_find_offset( if (p->index_version > 1) { level1_ofs += 2; + ofs_delta = 2; index += 8; + } - if ((int)short_oid->id[0] + 2 >= p->index_map.len) { - git_error_set(GIT_ERROR_INTERNAL, "internal error: p->short_oid->[0] out of bounds"); - goto cleanup; - } - } else if ((int)short_oid->id[0] >= p->index_map.len) { + if ((size_t)short_oid->id[0] + ofs_delta >= p->index_map.len) { git_error_set(GIT_ERROR_INTERNAL, "internal error: p->short_oid->[0] out of bounds"); goto cleanup; } From 3599de9073ed46ed6da5e8b56aa32d1092bfc8e7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 Apr 2024 13:16:37 +0100 Subject: [PATCH 500/816] http: add llhttp as a bundled dependency Include llhttp as a bundled dependency with the aim to use it as our default http parser, removing the now-unmaintained Node.js http-parser. --- COPYING | 25 + deps/llhttp/CMakeLists.txt | 8 + deps/llhttp/LICENSE-MIT | 22 + deps/llhttp/api.c | 510 ++ deps/llhttp/http.c | 170 + deps/llhttp/llhttp.c | 10168 +++++++++++++++++++++++++++++++++++ deps/llhttp/llhttp.h | 897 +++ 7 files changed, 11800 insertions(+) create mode 100644 deps/llhttp/CMakeLists.txt create mode 100644 deps/llhttp/LICENSE-MIT create mode 100644 deps/llhttp/api.c create mode 100644 deps/llhttp/http.c create mode 100644 deps/llhttp/llhttp.c create mode 100644 deps/llhttp/llhttp.h diff --git a/COPYING b/COPYING index ff5e76857e3..32c851f68da 100644 --- a/COPYING +++ b/COPYING @@ -1214,3 +1214,28 @@ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- + +The bundled llhttp dependency is licensed under the MIT license: + +Copyright Fedor Indutny, 2018. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/deps/llhttp/CMakeLists.txt b/deps/llhttp/CMakeLists.txt new file mode 100644 index 00000000000..89daa87c8de --- /dev/null +++ b/deps/llhttp/CMakeLists.txt @@ -0,0 +1,8 @@ +file(GLOB SRC_HTTP "*.c" "*.h") +list(SORT SRC_HTTP) + +add_library(llhttp OBJECT ${SRC_HTTP}) + +if(NOT MSVC) + set_source_files_properties(api.c http.c llhttp.c PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter -Wno-missing-declarations") +endif() diff --git a/deps/llhttp/LICENSE-MIT b/deps/llhttp/LICENSE-MIT new file mode 100644 index 00000000000..6c1512dd6bc --- /dev/null +++ b/deps/llhttp/LICENSE-MIT @@ -0,0 +1,22 @@ +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2018. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/deps/llhttp/api.c b/deps/llhttp/api.c new file mode 100644 index 00000000000..8c2ce3dc5c4 --- /dev/null +++ b/deps/llhttp/api.c @@ -0,0 +1,510 @@ +#include +#include +#include + +#include "llhttp.h" + +#define CALLBACK_MAYBE(PARSER, NAME) \ + do { \ + const llhttp_settings_t* settings; \ + settings = (const llhttp_settings_t*) (PARSER)->settings; \ + if (settings == NULL || settings->NAME == NULL) { \ + err = 0; \ + break; \ + } \ + err = settings->NAME((PARSER)); \ + } while (0) + +#define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN) \ + do { \ + const llhttp_settings_t* settings; \ + settings = (const llhttp_settings_t*) (PARSER)->settings; \ + if (settings == NULL || settings->NAME == NULL) { \ + err = 0; \ + break; \ + } \ + err = settings->NAME((PARSER), (START), (LEN)); \ + if (err == -1) { \ + err = HPE_USER; \ + llhttp_set_error_reason((PARSER), "Span callback error in " #NAME); \ + } \ + } while (0) + +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings) { + llhttp__internal_init(parser); + + parser->type = type; + parser->settings = (void*) settings; +} + + +#if defined(__wasm__) + +extern int wasm_on_message_begin(llhttp_t * p); +extern int wasm_on_url(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_status(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_headers_complete(llhttp_t * p, int status_code, + uint8_t upgrade, int should_keep_alive); +extern int wasm_on_body(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_message_complete(llhttp_t * p); + +static int wasm_on_headers_complete_wrap(llhttp_t* p) { + return wasm_on_headers_complete(p, p->status_code, p->upgrade, + llhttp_should_keep_alive(p)); +} + +const llhttp_settings_t wasm_settings = { + wasm_on_message_begin, + wasm_on_url, + wasm_on_status, + NULL, + NULL, + wasm_on_header_field, + wasm_on_header_value, + NULL, + NULL, + wasm_on_headers_complete_wrap, + wasm_on_body, + wasm_on_message_complete, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + + +llhttp_t* llhttp_alloc(llhttp_type_t type) { + llhttp_t* parser = malloc(sizeof(llhttp_t)); + llhttp_init(parser, type, &wasm_settings); + return parser; +} + +void llhttp_free(llhttp_t* parser) { + free(parser); +} + +#endif // defined(__wasm__) + +/* Some getters required to get stuff from the parser */ + +uint8_t llhttp_get_type(llhttp_t* parser) { + return parser->type; +} + +uint8_t llhttp_get_http_major(llhttp_t* parser) { + return parser->http_major; +} + +uint8_t llhttp_get_http_minor(llhttp_t* parser) { + return parser->http_minor; +} + +uint8_t llhttp_get_method(llhttp_t* parser) { + return parser->method; +} + +int llhttp_get_status_code(llhttp_t* parser) { + return parser->status_code; +} + +uint8_t llhttp_get_upgrade(llhttp_t* parser) { + return parser->upgrade; +} + + +void llhttp_reset(llhttp_t* parser) { + llhttp_type_t type = parser->type; + const llhttp_settings_t* settings = parser->settings; + void* data = parser->data; + uint16_t lenient_flags = parser->lenient_flags; + + llhttp__internal_init(parser); + + parser->type = type; + parser->settings = (void*) settings; + parser->data = data; + parser->lenient_flags = lenient_flags; +} + + +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) { + return llhttp__internal_execute(parser, data, data + len); +} + + +void llhttp_settings_init(llhttp_settings_t* settings) { + memset(settings, 0, sizeof(*settings)); +} + + +llhttp_errno_t llhttp_finish(llhttp_t* parser) { + int err; + + /* We're in an error state. Don't bother doing anything. */ + if (parser->error != 0) { + return 0; + } + + switch (parser->finish) { + case HTTP_FINISH_SAFE_WITH_CB: + CALLBACK_MAYBE(parser, on_message_complete); + if (err != HPE_OK) return err; + + /* FALLTHROUGH */ + case HTTP_FINISH_SAFE: + return HPE_OK; + case HTTP_FINISH_UNSAFE: + parser->reason = "Invalid EOF state"; + return HPE_INVALID_EOF_STATE; + default: + abort(); + } +} + + +void llhttp_pause(llhttp_t* parser) { + if (parser->error != HPE_OK) { + return; + } + + parser->error = HPE_PAUSED; + parser->reason = "Paused"; +} + + +void llhttp_resume(llhttp_t* parser) { + if (parser->error != HPE_PAUSED) { + return; + } + + parser->error = 0; +} + + +void llhttp_resume_after_upgrade(llhttp_t* parser) { + if (parser->error != HPE_PAUSED_UPGRADE) { + return; + } + + parser->error = 0; +} + + +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) { + return parser->error; +} + + +const char* llhttp_get_error_reason(const llhttp_t* parser) { + return parser->reason; +} + + +void llhttp_set_error_reason(llhttp_t* parser, const char* reason) { + parser->reason = reason; +} + + +const char* llhttp_get_error_pos(const llhttp_t* parser) { + return parser->error_pos; +} + + +const char* llhttp_errno_name(llhttp_errno_t err) { +#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME; + switch (err) { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) + default: abort(); + } +#undef HTTP_ERRNO_GEN +} + + +const char* llhttp_method_name(llhttp_method_t method) { +#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING; + switch (method) { + HTTP_ALL_METHOD_MAP(HTTP_METHOD_GEN) + default: abort(); + } +#undef HTTP_METHOD_GEN +} + +const char* llhttp_status_name(llhttp_status_t status) { +#define HTTP_STATUS_GEN(NUM, NAME, STRING) case HTTP_STATUS_##NAME: return #STRING; + switch (status) { + HTTP_STATUS_MAP(HTTP_STATUS_GEN) + default: abort(); + } +#undef HTTP_STATUS_GEN +} + + +void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_HEADERS; + } else { + parser->lenient_flags &= ~LENIENT_HEADERS; + } +} + + +void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_CHUNKED_LENGTH; + } else { + parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH; + } +} + + +void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_KEEP_ALIVE; + } else { + parser->lenient_flags &= ~LENIENT_KEEP_ALIVE; + } +} + +void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_TRANSFER_ENCODING; + } else { + parser->lenient_flags &= ~LENIENT_TRANSFER_ENCODING; + } +} + +void llhttp_set_lenient_version(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_VERSION; + } else { + parser->lenient_flags &= ~LENIENT_VERSION; + } +} + +void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_DATA_AFTER_CLOSE; + } else { + parser->lenient_flags &= ~LENIENT_DATA_AFTER_CLOSE; + } +} + +void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_OPTIONAL_LF_AFTER_CR; + } else { + parser->lenient_flags &= ~LENIENT_OPTIONAL_LF_AFTER_CR; + } +} + +void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_OPTIONAL_CRLF_AFTER_CHUNK; + } else { + parser->lenient_flags &= ~LENIENT_OPTIONAL_CRLF_AFTER_CHUNK; + } +} + +void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_OPTIONAL_CR_BEFORE_LF; + } else { + parser->lenient_flags &= ~LENIENT_OPTIONAL_CR_BEFORE_LF; + } +} + +void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_SPACES_AFTER_CHUNK_SIZE; + } else { + parser->lenient_flags &= ~LENIENT_SPACES_AFTER_CHUNK_SIZE; + } +} + +/* Callbacks */ + + +int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_begin); + return err; +} + + +int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p); + return err; +} + + +int llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_url_complete); + return err; +} + + +int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_status, p, endp - p); + return err; +} + + +int llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_status_complete); + return err; +} + + +int llhttp__on_method(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_method, p, endp - p); + return err; +} + + +int llhttp__on_method_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_method_complete); + return err; +} + + +int llhttp__on_version(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_version, p, endp - p); + return err; +} + + +int llhttp__on_version_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_version_complete); + return err; +} + + +int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_header_field, p, endp - p); + return err; +} + + +int llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_field_complete); + return err; +} + + +int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_header_value, p, endp - p); + return err; +} + + +int llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_value_complete); + return err; +} + + +int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_headers_complete); + return err; +} + + +int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_complete); + return err; +} + + +int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_body, p, endp - p); + return err; +} + + +int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_header); + return err; +} + + +int llhttp__on_chunk_extension_name(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_chunk_extension_name, p, endp - p); + return err; +} + + +int llhttp__on_chunk_extension_name_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_extension_name_complete); + return err; +} + + +int llhttp__on_chunk_extension_value(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_chunk_extension_value, p, endp - p); + return err; +} + + +int llhttp__on_chunk_extension_value_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_extension_value_complete); + return err; +} + + +int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_complete); + return err; +} + + +int llhttp__on_reset(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_reset); + return err; +} + + +/* Private */ + + +void llhttp__debug(llhttp_t* s, const char* p, const char* endp, + const char* msg) { + if (p == endp) { + fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type, + s->flags, msg); + } else { + fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s, + s->type, s->flags, *p, msg); + } +} diff --git a/deps/llhttp/http.c b/deps/llhttp/http.c new file mode 100644 index 00000000000..1ab91a55796 --- /dev/null +++ b/deps/llhttp/http.c @@ -0,0 +1,170 @@ +#include +#ifndef LLHTTP__TEST +# include "llhttp.h" +#else +# define llhttp_t llparse_t +#endif /* */ + +int llhttp_message_needs_eof(const llhttp_t* parser); +int llhttp_should_keep_alive(const llhttp_t* parser); + +int llhttp__before_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + /* Set this here so that on_headers_complete() callbacks can see it */ + if ((parser->flags & F_UPGRADE) && + (parser->flags & F_CONNECTION_UPGRADE)) { + /* For responses, "Upgrade: foo" and "Connection: upgrade" are + * mandatory only when it is a 101 Switching Protocols response, + * otherwise it is purely informational, to announce support. + */ + parser->upgrade = + (parser->type == HTTP_REQUEST || parser->status_code == 101); + } else { + parser->upgrade = (parser->method == HTTP_CONNECT); + } + return 0; +} + + +/* Return values: + * 0 - No body, `restart`, message_complete + * 1 - CONNECT request, `restart`, message_complete, and pause + * 2 - chunk_size_start + * 3 - body_identity + * 4 - body_identity_eof + * 5 - invalid transfer-encoding for request + */ +int llhttp__after_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + int hasBody; + + hasBody = parser->flags & F_CHUNKED || parser->content_length > 0; + if ( + (parser->upgrade && (parser->method == HTTP_CONNECT || + (parser->flags & F_SKIPBODY) || !hasBody)) || + /* See RFC 2616 section 4.4 - 1xx e.g. Continue */ + (parser->type == HTTP_RESPONSE && parser->status_code == 101) + ) { + /* Exit, the rest of the message is in a different protocol. */ + return 1; + } + + if (parser->type == HTTP_RESPONSE && parser->status_code == 100) { + /* No body, restart as the message is complete */ + return 0; + } + + /* See RFC 2616 section 4.4 */ + if ( + parser->flags & F_SKIPBODY || /* response to a HEAD request */ + ( + parser->type == HTTP_RESPONSE && ( + parser->status_code == 102 || /* Processing */ + parser->status_code == 103 || /* Early Hints */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 /* Not Modified */ + ) + ) + ) { + return 0; + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header, prepare for a chunk */ + return 2; + } else if (parser->flags & F_TRANSFER_ENCODING) { + if (parser->type == HTTP_REQUEST && + (parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0 && + (parser->lenient_flags & LENIENT_TRANSFER_ENCODING) == 0) { + /* RFC 7230 3.3.3 */ + + /* If a Transfer-Encoding header field + * is present in a request and the chunked transfer coding is not + * the final encoding, the message body length cannot be determined + * reliably; the server MUST respond with the 400 (Bad Request) + * status code and then close the connection. + */ + return 5; + } else { + /* RFC 7230 3.3.3 */ + + /* If a Transfer-Encoding header field is present in a response and + * the chunked transfer coding is not the final encoding, the + * message body length is determined by reading the connection until + * it is closed by the server. + */ + return 4; + } + } else { + if (!(parser->flags & F_CONTENT_LENGTH)) { + if (!llhttp_message_needs_eof(parser)) { + /* Assume content-length 0 - read the next */ + return 0; + } else { + /* Read body until EOF */ + return 4; + } + } else if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + return 0; + } else { + /* Content-Length header given and non-zero */ + return 3; + } + } +} + + +int llhttp__after_message_complete(llhttp_t* parser, const char* p, + const char* endp) { + int should_keep_alive; + + should_keep_alive = llhttp_should_keep_alive(parser); + parser->finish = HTTP_FINISH_SAFE; + parser->flags = 0; + + /* NOTE: this is ignored in loose parsing mode */ + return should_keep_alive; +} + + +int llhttp_message_needs_eof(const llhttp_t* parser) { + if (parser->type == HTTP_REQUEST) { + return 0; + } + + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + (parser->flags & F_SKIPBODY)) { /* response to a HEAD request */ + return 0; + } + + /* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */ + if ((parser->flags & F_TRANSFER_ENCODING) && + (parser->flags & F_CHUNKED) == 0) { + return 1; + } + + if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) { + return 0; + } + + return 1; +} + + +int llhttp_should_keep_alive(const llhttp_t* parser) { + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } + } else { + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { + return 0; + } + } + + return !llhttp_message_needs_eof(parser); +} diff --git a/deps/llhttp/llhttp.c b/deps/llhttp/llhttp.c new file mode 100644 index 00000000000..3ef3b817f3d --- /dev/null +++ b/deps/llhttp/llhttp.c @@ -0,0 +1,10168 @@ +#include +#include +#include + +#ifdef __SSE4_2__ + #ifdef _MSC_VER + #include + #else /* !_MSC_VER */ + #include + #endif /* _MSC_VER */ +#endif /* __SSE4_2__ */ + +#ifdef _MSC_VER + #define ALIGN(n) _declspec(align(n)) +#else /* !_MSC_VER */ + #define ALIGN(n) __attribute__((aligned(n))) +#endif /* _MSC_VER */ + +#include "llhttp.h" + +typedef int (*llhttp__internal__span_cb)( + llhttp__internal_t*, const char*, const char*); + +static const unsigned char llparse_blob0[] = { + 'o', 'n' +}; +static const unsigned char llparse_blob1[] = { + 'e', 'c', 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob2[] = { + 'l', 'o', 's', 'e' +}; +static const unsigned char llparse_blob3[] = { + 'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e' +}; +static const unsigned char llparse_blob4[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob5[] = { + 'c', 'h', 'u', 'n', 'k', 'e', 'd' +}; +#ifdef __SSE4_2__ +static const unsigned char ALIGN(16) llparse_blob6[] = { + 0x9, 0x9, ' ', '~', 0x80, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0 +}; +#endif /* __SSE4_2__ */ +#ifdef __SSE4_2__ +static const unsigned char ALIGN(16) llparse_blob7[] = { + '!', '!', '#', '\'', '*', '+', '-', '.', '0', '9', 'A', + 'Z', '^', 'z', '|', '|' +}; +#endif /* __SSE4_2__ */ +#ifdef __SSE4_2__ +static const unsigned char ALIGN(16) llparse_blob8[] = { + '~', '~', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0 +}; +#endif /* __SSE4_2__ */ +static const unsigned char llparse_blob9[] = { + 'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h' +}; +static const unsigned char llparse_blob10[] = { + 'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c', + 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob11[] = { + 'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c', + 'o', 'd', 'i', 'n', 'g' +}; +static const unsigned char llparse_blob12[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob13[] = { + 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob14[] = { + 0xd, 0xa, 0xd, 0xa, 'S', 'M', 0xd, 0xa, 0xd, 0xa +}; +static const unsigned char llparse_blob15[] = { + 'C', 'E', '/' +}; +static const unsigned char llparse_blob16[] = { + 'T', 'S', 'P', '/' +}; +static const unsigned char llparse_blob17[] = { + 'N', 'O', 'U', 'N', 'C', 'E' +}; +static const unsigned char llparse_blob18[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob19[] = { + 'E', 'C', 'K', 'O', 'U', 'T' +}; +static const unsigned char llparse_blob20[] = { + 'N', 'E', 'C', 'T' +}; +static const unsigned char llparse_blob21[] = { + 'E', 'T', 'E' +}; +static const unsigned char llparse_blob22[] = { + 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob23[] = { + 'L', 'U', 'S', 'H' +}; +static const unsigned char llparse_blob24[] = { + 'E', 'T' +}; +static const unsigned char llparse_blob25[] = { + 'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R' +}; +static const unsigned char llparse_blob26[] = { + 'E', 'A', 'D' +}; +static const unsigned char llparse_blob27[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob28[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob29[] = { + 'S', 'E', 'A', 'R', 'C', 'H' +}; +static const unsigned char llparse_blob30[] = { + 'R', 'G', 'E' +}; +static const unsigned char llparse_blob31[] = { + 'C', 'T', 'I', 'V', 'I', 'T', 'Y' +}; +static const unsigned char llparse_blob32[] = { + 'L', 'E', 'N', 'D', 'A', 'R' +}; +static const unsigned char llparse_blob33[] = { + 'V', 'E' +}; +static const unsigned char llparse_blob34[] = { + 'O', 'T', 'I', 'F', 'Y' +}; +static const unsigned char llparse_blob35[] = { + 'P', 'T', 'I', 'O', 'N', 'S' +}; +static const unsigned char llparse_blob36[] = { + 'C', 'H' +}; +static const unsigned char llparse_blob37[] = { + 'S', 'E' +}; +static const unsigned char llparse_blob38[] = { + 'A', 'Y' +}; +static const unsigned char llparse_blob39[] = { + 'S', 'T' +}; +static const unsigned char llparse_blob40[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob41[] = { + 'A', 'T', 'C', 'H' +}; +static const unsigned char llparse_blob42[] = { + 'G', 'E' +}; +static const unsigned char llparse_blob43[] = { + 'U', 'E', 'R', 'Y' +}; +static const unsigned char llparse_blob44[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob45[] = { + 'O', 'R', 'D' +}; +static const unsigned char llparse_blob46[] = { + 'I', 'R', 'E', 'C', 'T' +}; +static const unsigned char llparse_blob47[] = { + 'O', 'R', 'T' +}; +static const unsigned char llparse_blob48[] = { + 'R', 'C', 'H' +}; +static const unsigned char llparse_blob49[] = { + 'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R' +}; +static const unsigned char llparse_blob50[] = { + 'U', 'R', 'C', 'E' +}; +static const unsigned char llparse_blob51[] = { + 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob52[] = { + 'A', 'R', 'D', 'O', 'W', 'N' +}; +static const unsigned char llparse_blob53[] = { + 'A', 'C', 'E' +}; +static const unsigned char llparse_blob54[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob55[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob56[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob57[] = { + 'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob58[] = { + 'H', 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob59[] = { + 'A', 'D' +}; +static const unsigned char llparse_blob60[] = { + 'T', 'P', '/' +}; + +enum llparse_match_status_e { + kMatchComplete, + kMatchPause, + kMatchMismatch +}; +typedef enum llparse_match_status_e llparse_match_status_t; + +struct llparse_match_s { + llparse_match_status_t status; + const unsigned char* current; +}; +typedef struct llparse_match_s llparse_match_t; + +static llparse_match_t llparse__match_sequence_to_lower( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = ((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p)); + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +static llparse_match_t llparse__match_sequence_to_lower_unsafe( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = ((*p) | 0x20); + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +static llparse_match_t llparse__match_sequence_id( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = *p; + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +enum llparse_state_e { + s_error, + s_n_llhttp__internal__n_closed, + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete, + s_n_llhttp__internal__n_pause_1, + s_n_llhttp__internal__n_invoke_is_equal_upgrade, + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2, + s_n_llhttp__internal__n_chunk_data_almost_done_1, + s_n_llhttp__internal__n_chunk_data_almost_done, + s_n_llhttp__internal__n_consume_content_length, + s_n_llhttp__internal__n_span_start_llhttp__on_body, + s_n_llhttp__internal__n_invoke_is_equal_content_length, + s_n_llhttp__internal__n_chunk_size_almost_done, + s_n_llhttp__internal__n_invoke_test_lenient_flags_9, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2, + s_n_llhttp__internal__n_invoke_test_lenient_flags_10, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1, + s_n_llhttp__internal__n_chunk_extension_quoted_value_done, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2, + s_n_llhttp__internal__n_error_30, + s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair, + s_n_llhttp__internal__n_error_31, + s_n_llhttp__internal__n_chunk_extension_quoted_value, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3, + s_n_llhttp__internal__n_error_33, + s_n_llhttp__internal__n_chunk_extension_value, + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value, + s_n_llhttp__internal__n_error_34, + s_n_llhttp__internal__n_chunk_extension_name, + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name, + s_n_llhttp__internal__n_chunk_extensions, + s_n_llhttp__internal__n_chunk_size_otherwise, + s_n_llhttp__internal__n_chunk_size, + s_n_llhttp__internal__n_chunk_size_digit, + s_n_llhttp__internal__n_invoke_update_content_length_1, + s_n_llhttp__internal__n_consume_content_length_1, + s_n_llhttp__internal__n_span_start_llhttp__on_body_1, + s_n_llhttp__internal__n_eof, + s_n_llhttp__internal__n_span_start_llhttp__on_body_2, + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete, + s_n_llhttp__internal__n_error_5, + s_n_llhttp__internal__n_headers_almost_done, + s_n_llhttp__internal__n_header_field_colon_discard_ws, + s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value, + s_n_llhttp__internal__n_header_value_discard_lws, + s_n_llhttp__internal__n_header_value_discard_ws_almost_done, + s_n_llhttp__internal__n_header_value_lws, + s_n_llhttp__internal__n_header_value_almost_done, + s_n_llhttp__internal__n_invoke_test_lenient_flags_17, + s_n_llhttp__internal__n_header_value_lenient, + s_n_llhttp__internal__n_error_54, + s_n_llhttp__internal__n_header_value_otherwise, + s_n_llhttp__internal__n_header_value_connection_token, + s_n_llhttp__internal__n_header_value_connection_ws, + s_n_llhttp__internal__n_header_value_connection_1, + s_n_llhttp__internal__n_header_value_connection_2, + s_n_llhttp__internal__n_header_value_connection_3, + s_n_llhttp__internal__n_header_value_connection, + s_n_llhttp__internal__n_error_56, + s_n_llhttp__internal__n_error_57, + s_n_llhttp__internal__n_header_value_content_length_ws, + s_n_llhttp__internal__n_header_value_content_length, + s_n_llhttp__internal__n_error_59, + s_n_llhttp__internal__n_error_58, + s_n_llhttp__internal__n_header_value_te_token_ows, + s_n_llhttp__internal__n_header_value, + s_n_llhttp__internal__n_header_value_te_token, + s_n_llhttp__internal__n_header_value_te_chunked_last, + s_n_llhttp__internal__n_header_value_te_chunked, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1, + s_n_llhttp__internal__n_header_value_discard_ws, + s_n_llhttp__internal__n_invoke_load_header_state, + s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete, + s_n_llhttp__internal__n_header_field_general_otherwise, + s_n_llhttp__internal__n_header_field_general, + s_n_llhttp__internal__n_header_field_colon, + s_n_llhttp__internal__n_header_field_3, + s_n_llhttp__internal__n_header_field_4, + s_n_llhttp__internal__n_header_field_2, + s_n_llhttp__internal__n_header_field_1, + s_n_llhttp__internal__n_header_field_5, + s_n_llhttp__internal__n_header_field_6, + s_n_llhttp__internal__n_header_field_7, + s_n_llhttp__internal__n_header_field, + s_n_llhttp__internal__n_span_start_llhttp__on_header_field, + s_n_llhttp__internal__n_header_field_start, + s_n_llhttp__internal__n_headers_start, + s_n_llhttp__internal__n_url_to_http_09, + s_n_llhttp__internal__n_url_skip_to_http09, + s_n_llhttp__internal__n_url_skip_lf_to_http09_1, + s_n_llhttp__internal__n_url_skip_lf_to_http09, + s_n_llhttp__internal__n_req_pri_upgrade, + s_n_llhttp__internal__n_req_http_complete_crlf, + s_n_llhttp__internal__n_req_http_complete, + s_n_llhttp__internal__n_invoke_load_method_1, + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete, + s_n_llhttp__internal__n_error_66, + s_n_llhttp__internal__n_error_73, + s_n_llhttp__internal__n_req_http_minor, + s_n_llhttp__internal__n_error_74, + s_n_llhttp__internal__n_req_http_dot, + s_n_llhttp__internal__n_error_75, + s_n_llhttp__internal__n_req_http_major, + s_n_llhttp__internal__n_span_start_llhttp__on_version, + s_n_llhttp__internal__n_req_http_start_1, + s_n_llhttp__internal__n_req_http_start_2, + s_n_llhttp__internal__n_req_http_start_3, + s_n_llhttp__internal__n_req_http_start, + s_n_llhttp__internal__n_url_to_http, + s_n_llhttp__internal__n_url_skip_to_http, + s_n_llhttp__internal__n_url_fragment, + s_n_llhttp__internal__n_span_end_stub_query_3, + s_n_llhttp__internal__n_url_query, + s_n_llhttp__internal__n_url_query_or_fragment, + s_n_llhttp__internal__n_url_path, + s_n_llhttp__internal__n_span_start_stub_path_2, + s_n_llhttp__internal__n_span_start_stub_path, + s_n_llhttp__internal__n_span_start_stub_path_1, + s_n_llhttp__internal__n_url_server_with_at, + s_n_llhttp__internal__n_url_server, + s_n_llhttp__internal__n_url_schema_delim_1, + s_n_llhttp__internal__n_url_schema_delim, + s_n_llhttp__internal__n_span_end_stub_schema, + s_n_llhttp__internal__n_url_schema, + s_n_llhttp__internal__n_url_start, + s_n_llhttp__internal__n_span_start_llhttp__on_url_1, + s_n_llhttp__internal__n_url_entry_normal, + s_n_llhttp__internal__n_span_start_llhttp__on_url, + s_n_llhttp__internal__n_url_entry_connect, + s_n_llhttp__internal__n_req_spaces_before_url, + s_n_llhttp__internal__n_req_first_space_before_url, + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1, + s_n_llhttp__internal__n_after_start_req_2, + s_n_llhttp__internal__n_after_start_req_3, + s_n_llhttp__internal__n_after_start_req_1, + s_n_llhttp__internal__n_after_start_req_4, + s_n_llhttp__internal__n_after_start_req_6, + s_n_llhttp__internal__n_after_start_req_8, + s_n_llhttp__internal__n_after_start_req_9, + s_n_llhttp__internal__n_after_start_req_7, + s_n_llhttp__internal__n_after_start_req_5, + s_n_llhttp__internal__n_after_start_req_12, + s_n_llhttp__internal__n_after_start_req_13, + s_n_llhttp__internal__n_after_start_req_11, + s_n_llhttp__internal__n_after_start_req_10, + s_n_llhttp__internal__n_after_start_req_14, + s_n_llhttp__internal__n_after_start_req_17, + s_n_llhttp__internal__n_after_start_req_16, + s_n_llhttp__internal__n_after_start_req_15, + s_n_llhttp__internal__n_after_start_req_18, + s_n_llhttp__internal__n_after_start_req_20, + s_n_llhttp__internal__n_after_start_req_21, + s_n_llhttp__internal__n_after_start_req_19, + s_n_llhttp__internal__n_after_start_req_23, + s_n_llhttp__internal__n_after_start_req_24, + s_n_llhttp__internal__n_after_start_req_26, + s_n_llhttp__internal__n_after_start_req_28, + s_n_llhttp__internal__n_after_start_req_29, + s_n_llhttp__internal__n_after_start_req_27, + s_n_llhttp__internal__n_after_start_req_25, + s_n_llhttp__internal__n_after_start_req_30, + s_n_llhttp__internal__n_after_start_req_22, + s_n_llhttp__internal__n_after_start_req_31, + s_n_llhttp__internal__n_after_start_req_32, + s_n_llhttp__internal__n_after_start_req_35, + s_n_llhttp__internal__n_after_start_req_36, + s_n_llhttp__internal__n_after_start_req_34, + s_n_llhttp__internal__n_after_start_req_37, + s_n_llhttp__internal__n_after_start_req_38, + s_n_llhttp__internal__n_after_start_req_42, + s_n_llhttp__internal__n_after_start_req_43, + s_n_llhttp__internal__n_after_start_req_41, + s_n_llhttp__internal__n_after_start_req_40, + s_n_llhttp__internal__n_after_start_req_39, + s_n_llhttp__internal__n_after_start_req_45, + s_n_llhttp__internal__n_after_start_req_44, + s_n_llhttp__internal__n_after_start_req_33, + s_n_llhttp__internal__n_after_start_req_46, + s_n_llhttp__internal__n_after_start_req_49, + s_n_llhttp__internal__n_after_start_req_50, + s_n_llhttp__internal__n_after_start_req_51, + s_n_llhttp__internal__n_after_start_req_52, + s_n_llhttp__internal__n_after_start_req_48, + s_n_llhttp__internal__n_after_start_req_47, + s_n_llhttp__internal__n_after_start_req_55, + s_n_llhttp__internal__n_after_start_req_57, + s_n_llhttp__internal__n_after_start_req_58, + s_n_llhttp__internal__n_after_start_req_56, + s_n_llhttp__internal__n_after_start_req_54, + s_n_llhttp__internal__n_after_start_req_59, + s_n_llhttp__internal__n_after_start_req_60, + s_n_llhttp__internal__n_after_start_req_53, + s_n_llhttp__internal__n_after_start_req_62, + s_n_llhttp__internal__n_after_start_req_63, + s_n_llhttp__internal__n_after_start_req_61, + s_n_llhttp__internal__n_after_start_req_66, + s_n_llhttp__internal__n_after_start_req_68, + s_n_llhttp__internal__n_after_start_req_69, + s_n_llhttp__internal__n_after_start_req_67, + s_n_llhttp__internal__n_after_start_req_70, + s_n_llhttp__internal__n_after_start_req_65, + s_n_llhttp__internal__n_after_start_req_64, + s_n_llhttp__internal__n_after_start_req, + s_n_llhttp__internal__n_span_start_llhttp__on_method_1, + s_n_llhttp__internal__n_res_line_almost_done, + s_n_llhttp__internal__n_invoke_test_lenient_flags_30, + s_n_llhttp__internal__n_res_status, + s_n_llhttp__internal__n_span_start_llhttp__on_status, + s_n_llhttp__internal__n_res_status_code_otherwise, + s_n_llhttp__internal__n_res_status_code_digit_3, + s_n_llhttp__internal__n_res_status_code_digit_2, + s_n_llhttp__internal__n_res_status_code_digit_1, + s_n_llhttp__internal__n_res_after_version, + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1, + s_n_llhttp__internal__n_error_89, + s_n_llhttp__internal__n_error_103, + s_n_llhttp__internal__n_res_http_minor, + s_n_llhttp__internal__n_error_104, + s_n_llhttp__internal__n_res_http_dot, + s_n_llhttp__internal__n_error_105, + s_n_llhttp__internal__n_res_http_major, + s_n_llhttp__internal__n_span_start_llhttp__on_version_1, + s_n_llhttp__internal__n_start_res, + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete, + s_n_llhttp__internal__n_req_or_res_method_2, + s_n_llhttp__internal__n_invoke_update_type_1, + s_n_llhttp__internal__n_req_or_res_method_3, + s_n_llhttp__internal__n_req_or_res_method_1, + s_n_llhttp__internal__n_req_or_res_method, + s_n_llhttp__internal__n_span_start_llhttp__on_method, + s_n_llhttp__internal__n_start_req_or_res, + s_n_llhttp__internal__n_invoke_load_type, + s_n_llhttp__internal__n_invoke_update_finish, + s_n_llhttp__internal__n_start, +}; +typedef enum llparse_state_e llparse_state_t; + +int llhttp__on_method( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_url( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_version( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_field( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_value( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_body( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_chunk_extension_name( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_chunk_extension_value( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_status( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_initial_message_completed( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->initial_message_completed; +} + +int llhttp__on_reset( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_finish( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 2; + return 0; +} + +int llhttp__on_message_begin( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->type; +} + +int llhttp__internal__c_store_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->method = match; + return 0; +} + +int llhttp__on_method_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method == 5; +} + +int llhttp__internal__c_update_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_major = 0; + return 0; +} + +int llhttp__internal__c_update_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_minor = 9; + return 0; +} + +int llhttp__on_url_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_test_lenient_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 1) == 1; +} + +int llhttp__internal__c_test_lenient_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 256) == 256; +} + +int llhttp__internal__c_test_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 128) == 128; +} + +int llhttp__on_chunk_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->upgrade == 1; +} + +int llhttp__after_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->content_length = 0; + return 0; +} + +int llhttp__internal__c_update_initial_message_completed( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->initial_message_completed = 1; + return 0; +} + +int llhttp__internal__c_update_finish_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 0; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 4) == 4; +} + +int llhttp__internal__c_test_lenient_flags_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 32) == 32; +} + +int llhttp__before_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__after_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_mul_add_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 16) { + return 1; + } + + state->content_length *= 16; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 512) == 512; +} + +int llhttp__on_chunk_header( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->content_length == 0; +} + +int llhttp__internal__c_test_lenient_flags_7( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 128) == 128; +} + +int llhttp__internal__c_or_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 128; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 64) == 64; +} + +int llhttp__on_chunk_extension_name_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_chunk_extension_value_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_finish_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 1; + return 0; +} + +int llhttp__internal__c_or_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 64; + return 0; +} + +int llhttp__internal__c_update_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->upgrade = 1; + return 0; +} + +int llhttp__internal__c_store_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->header_state = match; + return 0; +} + +int llhttp__on_header_field_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->header_state; +} + +int llhttp__internal__c_test_flags_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 512) == 512; +} + +int llhttp__internal__c_test_lenient_flags_22( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 2) == 2; +} + +int llhttp__internal__c_or_flags_5( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 1; + return 0; +} + +int llhttp__internal__c_update_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 1; + return 0; +} + +int llhttp__on_header_value_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_or_flags_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 2; + return 0; +} + +int llhttp__internal__c_or_flags_7( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 4; + return 0; +} + +int llhttp__internal__c_or_flags_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 8; + return 0; +} + +int llhttp__internal__c_update_header_state_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 6; + return 0; +} + +int llhttp__internal__c_update_header_state_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 0; + return 0; +} + +int llhttp__internal__c_update_header_state_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 5; + return 0; +} + +int llhttp__internal__c_update_header_state_7( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 7; + return 0; +} + +int llhttp__internal__c_test_flags_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 32) == 32; +} + +int llhttp__internal__c_mul_add_content_length_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 10) { + return 1; + } + + state->content_length *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__internal__c_or_flags_17( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 32; + return 0; +} + +int llhttp__internal__c_test_flags_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 8) == 8; +} + +int llhttp__internal__c_test_lenient_flags_20( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 8) == 8; +} + +int llhttp__internal__c_or_flags_18( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 512; + return 0; +} + +int llhttp__internal__c_and_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags &= -9; + return 0; +} + +int llhttp__internal__c_update_header_state_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 8; + return 0; +} + +int llhttp__internal__c_or_flags_20( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 16; + return 0; +} + +int llhttp__internal__c_load_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method; +} + +int llhttp__internal__c_store_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_major = match; + return 0; +} + +int llhttp__internal__c_store_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_minor = match; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_24( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 16) == 16; +} + +int llhttp__on_version_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->http_major; +} + +int llhttp__internal__c_load_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->http_minor; +} + +int llhttp__internal__c_update_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->status_code = 0; + return 0; +} + +int llhttp__internal__c_mul_add_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->status_code > 0xffff / 10) { + return 1; + } + + state->status_code *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->status_code > 0xffff - match) { + return 1; + } + } else { + if (state->status_code < 0 - match) { + return 1; + } + } + state->status_code += match; + return 0; +} + +int llhttp__on_status_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 1; + return 0; +} + +int llhttp__internal__c_update_type_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 2; + return 0; +} + +int llhttp__internal_init(llhttp__internal_t* state) { + memset(state, 0, sizeof(*state)); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start; + return 0; +} + +static llparse_state_t llhttp__internal__run( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + int match; + switch ((llparse_state_t) (intptr_t) state->_current) { + case s_n_llhttp__internal__n_closed: + s_n_llhttp__internal__n_closed: { + if (p == endp) { + return s_n_llhttp__internal__n_closed; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_closed; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_closed; + } + default: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_3; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: { + switch (llhttp__after_message_complete(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_update_content_length; + default: + goto s_n_llhttp__internal__n_invoke_update_finish_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_pause_1: + s_n_llhttp__internal__n_pause_1: { + state->error = 0x16; + state->reason = "Pause on CONNECT/Upgrade"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_upgrade: + s_n_llhttp__internal__n_invoke_is_equal_upgrade: { + switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + default: + goto s_n_llhttp__internal__n_pause_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_upgrade; + case 21: + goto s_n_llhttp__internal__n_pause_13; + default: + goto s_n_llhttp__internal__n_error_38; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done_1: + s_n_llhttp__internal__n_chunk_data_almost_done_1: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done_1; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done: + s_n_llhttp__internal__n_chunk_data_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_6; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_data_almost_done_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length: + s_n_llhttp__internal__n_consume_content_length: { + size_t avail; + uint64_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body: + s_n_llhttp__internal__n_span_start_llhttp__on_body: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_content_length: + s_n_llhttp__internal__n_invoke_is_equal_content_length: { + switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body; + default: + goto s_n_llhttp__internal__n_invoke_or_flags; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_almost_done: + s_n_llhttp__internal__n_chunk_size_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_8; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_9: + s_n_llhttp__internal__n_invoke_test_lenient_flags_9: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_20; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_9; + case 21: + goto s_n_llhttp__internal__n_pause_5; + default: + goto s_n_llhttp__internal__n_error_19; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + case 21: + goto s_n_llhttp__internal__n_pause_6; + default: + goto s_n_llhttp__internal__n_error_21; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extensions; + case 21: + goto s_n_llhttp__internal__n_pause_7; + default: + goto s_n_llhttp__internal__n_error_22; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_10: + s_n_llhttp__internal__n_invoke_test_lenient_flags_10: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_25; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_10; + case 21: + goto s_n_llhttp__internal__n_pause_8; + default: + goto s_n_llhttp__internal__n_error_24; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + case 21: + goto s_n_llhttp__internal__n_pause_9; + default: + goto s_n_llhttp__internal__n_error_26; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_quoted_value_done: + s_n_llhttp__internal__n_chunk_extension_quoted_value_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_quoted_value_done; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_11; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + case ';': { + p++; + goto s_n_llhttp__internal__n_chunk_extensions; + } + default: { + goto s_n_llhttp__internal__n_error_29; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extension_quoted_value_done; + case 21: + goto s_n_llhttp__internal__n_pause_10; + default: + goto s_n_llhttp__internal__n_error_27; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_30: + s_n_llhttp__internal__n_error_30: { + state->error = 0x2; + state->reason = "Invalid quoted-pair in chunk extensions quoted value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: + s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_31: + s_n_llhttp__internal__n_error_31: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions quoted value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_quoted_value: + s_n_llhttp__internal__n_chunk_extension_quoted_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extensions; + case 21: + goto s_n_llhttp__internal__n_pause_11; + default: + goto s_n_llhttp__internal__n_error_32; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_33: + s_n_llhttp__internal__n_error_33: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_value: + s_n_llhttp__internal__n_chunk_extension_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 4, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 5, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_value; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_value; + } + case 4: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + case 5: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_chunk_extension_value; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_34: + s_n_llhttp__internal__n_error_34: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions name"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_name: + s_n_llhttp__internal__n_chunk_extension_name: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 4, 0, 5, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_name; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_name; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2; + } + case 5: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_chunk_extension_name; + goto s_n_llhttp__internal__n_chunk_extension_name; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extensions: + s_n_llhttp__internal__n_chunk_extensions: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extensions; + } + switch (*p) { + case 13: { + p++; + goto s_n_llhttp__internal__n_error_17; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_error_18; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_otherwise: + s_n_llhttp__internal__n_chunk_size_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_otherwise; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_4; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_5; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_4; + } + case ';': { + p++; + goto s_n_llhttp__internal__n_chunk_extensions; + } + default: { + goto s_n_llhttp__internal__n_error_35; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size: + s_n_llhttp__internal__n_chunk_size: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'A': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'B': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'C': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'D': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'E': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'F': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'a': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'b': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'c': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'd': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'e': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'f': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + default: { + goto s_n_llhttp__internal__n_chunk_size_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_digit: + s_n_llhttp__internal__n_chunk_size_digit: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_digit; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'A': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'B': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'C': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'D': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'E': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'F': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'a': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'b': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'c': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'd': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'e': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'f': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + default: { + goto s_n_llhttp__internal__n_error_37; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_content_length_1: + s_n_llhttp__internal__n_invoke_update_content_length_1: { + switch (llhttp__internal__c_update_content_length(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_chunk_size_digit; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length_1: + s_n_llhttp__internal__n_consume_content_length_1: { + size_t avail; + uint64_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_1: + s_n_llhttp__internal__n_span_start_llhttp__on_body_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_eof: + s_n_llhttp__internal__n_eof: { + if (p == endp) { + return s_n_llhttp__internal__n_eof; + } + p++; + goto s_n_llhttp__internal__n_eof; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_2: + s_n_llhttp__internal__n_span_start_llhttp__on_body_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_eof; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: { + switch (llhttp__after_headers_complete(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_content_length_1; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + case 4: + goto s_n_llhttp__internal__n_invoke_update_finish_3; + case 5: + goto s_n_llhttp__internal__n_error_39; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_5: + s_n_llhttp__internal__n_error_5: { + state->error = 0xa; + state->reason = "Invalid header field char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_headers_almost_done: + s_n_llhttp__internal__n_headers_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_headers_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_flags_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_12; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_colon_discard_ws: + s_n_llhttp__internal__n_header_field_colon_discard_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_colon_discard_ws; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_field_colon_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_header_field_colon; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: { + switch (llhttp__on_header_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_header_field_start; + case 21: + goto s_n_llhttp__internal__n_pause_18; + default: + goto s_n_llhttp__internal__n_error_48; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_lws: + s_n_llhttp__internal__n_header_value_discard_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_lws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_15; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_15; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws_almost_done: + s_n_llhttp__internal__n_header_value_discard_ws_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_lws; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_16; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_lws: + s_n_llhttp__internal__n_header_value_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_lws; + } + switch (*p) { + case 9: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_18; + } + case ' ': { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_18; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state_5; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_almost_done: + s_n_llhttp__internal__n_header_value_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_lws; + } + default: { + goto s_n_llhttp__internal__n_error_53; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_17: + s_n_llhttp__internal__n_invoke_test_lenient_flags_17: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_almost_done; + default: + goto s_n_llhttp__internal__n_error_51; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_lenient: + s_n_llhttp__internal__n_header_value_lenient: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_lenient; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5; + } + default: { + p++; + goto s_n_llhttp__internal__n_header_value_lenient; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_54: + s_n_llhttp__internal__n_error_54: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_otherwise: + s_n_llhttp__internal__n_header_value_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_otherwise; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_19; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_token: + s_n_llhttp__internal__n_header_value_connection_token: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_token; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value_connection_token; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_ws: + s_n_llhttp__internal__n_header_value_connection_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + case ',': { + p++; + goto s_n_llhttp__internal__n_invoke_load_header_state_6; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_5; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_1: + s_n_llhttp__internal__n_header_value_connection_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_1; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob2, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_2: + s_n_llhttp__internal__n_header_value_connection_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_2; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob3, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_6; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_3: + s_n_llhttp__internal__n_header_value_connection_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_3; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob4, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection: + s_n_llhttp__internal__n_header_value_connection: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection; + } + switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_1; + } + case 'k': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_2; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_3; + } + default: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_56: + s_n_llhttp__internal__n_error_56: { + state->error = 0xb; + state->reason = "Content-Length overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_57: + s_n_llhttp__internal__n_error_57: { + state->error = 0xb; + state->reason = "Invalid character in Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length_ws: + s_n_llhttp__internal__n_header_value_content_length_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_or_flags_17; + } + case 13: { + goto s_n_llhttp__internal__n_invoke_or_flags_17; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length: + s_n_llhttp__internal__n_header_value_content_length: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + default: { + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_59: + s_n_llhttp__internal__n_error_59: { + state->error = 0xf; + state->reason = "Invalid `Transfer-Encoding` header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_58: + s_n_llhttp__internal__n_error_58: { + state->error = 0xf; + state->reason = "Invalid `Transfer-Encoding` header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_token_ows: + s_n_llhttp__internal__n_header_value_te_token_ows: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_token_ows; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_te_token_ows; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_te_token_ows; + } + default: { + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value: + s_n_llhttp__internal__n_header_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value; + } + #ifdef __SSE4_2__ + if (endp - p >= 16) { + __m128i ranges; + __m128i input; + int avail; + int match_len; + + /* Load input */ + input = _mm_loadu_si128((__m128i const*) p); + ranges = _mm_loadu_si128((__m128i const*) llparse_blob6); + + /* Find first character that does not match `ranges` */ + match_len = _mm_cmpestri(ranges, 6, + input, 16, + _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | + _SIDD_NEGATIVE_POLARITY); + + if (match_len != 0) { + p += match_len; + goto s_n_llhttp__internal__n_header_value; + } + goto s_n_llhttp__internal__n_header_value_otherwise; + } + #endif /* __SSE4_2__ */ + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_token: + s_n_llhttp__internal__n_header_value_te_token: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_token; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value_te_token; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_header_value_te_token_ows; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_9; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked_last: + s_n_llhttp__internal__n_header_value_te_chunked_last: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked_last; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_update_header_state_8; + } + case 13: { + goto s_n_llhttp__internal__n_invoke_update_header_state_8; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_te_chunked_last; + } + case ',': { + goto s_n_llhttp__internal__n_invoke_load_type_1; + } + default: { + goto s_n_llhttp__internal__n_header_value_te_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked: + s_n_llhttp__internal__n_header_value_te_chunked: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_header_value_te_chunked_last; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_te_chunked; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_te_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_invoke_load_header_state_3; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws: + s_n_llhttp__internal__n_header_value_discard_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_14; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_header_state: + s_n_llhttp__internal__n_invoke_load_header_state: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 2: + goto s_n_llhttp__internal__n_invoke_test_flags_4; + case 3: + goto s_n_llhttp__internal__n_invoke_test_flags_5; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: { + switch (llhttp__on_header_field_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_header_state; + case 21: + goto s_n_llhttp__internal__n_pause_19; + default: + goto s_n_llhttp__internal__n_error_45; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general_otherwise: + s_n_llhttp__internal__n_header_field_general_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general_otherwise; + } + switch (*p) { + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2; + } + default: { + goto s_n_llhttp__internal__n_error_62; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general: + s_n_llhttp__internal__n_header_field_general: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general; + } + #ifdef __SSE4_2__ + if (endp - p >= 16) { + __m128i ranges; + __m128i input; + int avail; + int match_len; + + /* Load input */ + input = _mm_loadu_si128((__m128i const*) p); + ranges = _mm_loadu_si128((__m128i const*) llparse_blob7); + + /* Find first character that does not match `ranges` */ + match_len = _mm_cmpestri(ranges, 16, + input, 16, + _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | + _SIDD_NEGATIVE_POLARITY); + + if (match_len != 0) { + p += match_len; + goto s_n_llhttp__internal__n_header_field_general; + } + ranges = _mm_loadu_si128((__m128i const*) llparse_blob8); + + /* Find first character that does not match `ranges` */ + match_len = _mm_cmpestri(ranges, 2, + input, 16, + _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | + _SIDD_NEGATIVE_POLARITY); + + if (match_len != 0) { + p += match_len; + goto s_n_llhttp__internal__n_header_field_general; + } + goto s_n_llhttp__internal__n_header_field_general_otherwise; + } + #endif /* __SSE4_2__ */ + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_field_general; + } + default: { + goto s_n_llhttp__internal__n_header_field_general_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_colon: + s_n_llhttp__internal__n_header_field_colon: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_colon; + } + switch (*p) { + case ' ': { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_13; + } + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_3: + s_n_llhttp__internal__n_header_field_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_3; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob1, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_4: + s_n_llhttp__internal__n_header_field_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_4; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob9, 10); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_2: + s_n_llhttp__internal__n_header_field_2: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_2; + } + switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { + case 'n': { + p++; + goto s_n_llhttp__internal__n_header_field_3; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_4; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_1: + s_n_llhttp__internal__n_header_field_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_1; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob0, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_header_field_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_5: + s_n_llhttp__internal__n_header_field_5: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_5; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob10, 15); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_5; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_6: + s_n_llhttp__internal__n_header_field_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_6; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob11, 16); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_7: + s_n_llhttp__internal__n_header_field_7: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_7; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob12, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_7; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field: + s_n_llhttp__internal__n_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field; + } + switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_field_1; + } + case 'p': { + p++; + goto s_n_llhttp__internal__n_header_field_5; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_6; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_field_7; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_field: + s_n_llhttp__internal__n_span_start_llhttp__on_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_field; + goto s_n_llhttp__internal__n_header_field; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_start: + s_n_llhttp__internal__n_header_field_start: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_1; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_headers_almost_done; + } + case ':': { + goto s_n_llhttp__internal__n_error_44; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_headers_start: + s_n_llhttp__internal__n_headers_start: { + if (p == endp) { + return s_n_llhttp__internal__n_headers_start; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags; + } + default: { + goto s_n_llhttp__internal__n_header_field_start; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_to_http_09: + s_n_llhttp__internal__n_url_to_http_09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_to_http_09; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_http_major; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http09: + s_n_llhttp__internal__n_url_skip_to_http09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http09; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + p++; + goto s_n_llhttp__internal__n_url_to_http_09; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_lf_to_http09_1: + s_n_llhttp__internal__n_url_skip_lf_to_http09_1: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_lf_to_http09_1; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_url_to_http_09; + } + default: { + goto s_n_llhttp__internal__n_error_63; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_lf_to_http09: + s_n_llhttp__internal__n_url_skip_lf_to_http09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_lf_to_http09; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_url_skip_lf_to_http09_1; + } + default: { + goto s_n_llhttp__internal__n_error_63; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_pri_upgrade: + s_n_llhttp__internal__n_req_pri_upgrade: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_pri_upgrade; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 10); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_error_71; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_pri_upgrade; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_72; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_complete_crlf: + s_n_llhttp__internal__n_req_http_complete_crlf: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_complete_crlf; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_headers_start; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_26; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_complete: + s_n_llhttp__internal__n_req_http_complete: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_complete; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_25; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_req_http_complete_crlf; + } + default: { + goto s_n_llhttp__internal__n_error_70; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_method_1: + s_n_llhttp__internal__n_invoke_load_method_1: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 34: + goto s_n_llhttp__internal__n_req_pri_upgrade; + default: + goto s_n_llhttp__internal__n_req_http_complete; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: { + switch (llhttp__on_version_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_method_1; + case 21: + goto s_n_llhttp__internal__n_pause_21; + default: + goto s_n_llhttp__internal__n_error_67; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_66: + s_n_llhttp__internal__n_error_66: { + state->error = 0x9; + state->reason = "Invalid HTTP version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_73: + s_n_llhttp__internal__n_error_73: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_minor: + s_n_llhttp__internal__n_req_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_74: + s_n_llhttp__internal__n_error_74: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_dot: + s_n_llhttp__internal__n_req_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_req_http_minor; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_3; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_75: + s_n_llhttp__internal__n_error_75: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_major: + s_n_llhttp__internal__n_req_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_version: + s_n_llhttp__internal__n_span_start_llhttp__on_version: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_version; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_version; + goto s_n_llhttp__internal__n_req_http_major; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_1: + s_n_llhttp__internal__n_req_http_start_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_1; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_load_method; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_2: + s_n_llhttp__internal__n_req_http_start_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_load_method_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_3: + s_n_llhttp__internal__n_req_http_start_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_load_method_3; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start: + s_n_llhttp__internal__n_req_http_start: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_http_start; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_http_start_1; + } + case 'I': { + p++; + goto s_n_llhttp__internal__n_req_http_start_2; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_req_http_start_3; + } + default: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_to_http: + s_n_llhttp__internal__n_url_to_http: { + if (p == endp) { + return s_n_llhttp__internal__n_url_to_http; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http: + s_n_llhttp__internal__n_url_skip_to_http: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + p++; + goto s_n_llhttp__internal__n_url_to_http; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_fragment: + s_n_llhttp__internal__n_url_fragment: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_fragment; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + default: { + goto s_n_llhttp__internal__n_error_79; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_query_3: + s_n_llhttp__internal__n_span_end_stub_query_3: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_query_3; + } + p++; + goto s_n_llhttp__internal__n_url_fragment; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query: + s_n_llhttp__internal__n_url_query: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_query; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 6: { + goto s_n_llhttp__internal__n_span_end_stub_query_3; + } + default: { + goto s_n_llhttp__internal__n_error_80; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query_or_fragment: + s_n_llhttp__internal__n_url_query_or_fragment: { + if (p == endp) { + return s_n_llhttp__internal__n_url_query_or_fragment; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4; + } + case ' ': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5; + } + case '#': { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + case '?': { + p++; + goto s_n_llhttp__internal__n_url_query; + } + default: { + goto s_n_llhttp__internal__n_error_81; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_path: + s_n_llhttp__internal__n_url_path: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_path; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_url_path; + } + default: { + goto s_n_llhttp__internal__n_url_query_or_fragment; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_2: + s_n_llhttp__internal__n_span_start_stub_path_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_2; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path: + s_n_llhttp__internal__n_span_start_stub_path: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_1: + s_n_llhttp__internal__n_span_start_stub_path_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_1; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server_with_at: + s_n_llhttp__internal__n_url_server_with_at: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7, + 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server_with_at; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 6: { + goto s_n_llhttp__internal__n_span_start_stub_path_1; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 8: { + p++; + goto s_n_llhttp__internal__n_error_82; + } + default: { + goto s_n_llhttp__internal__n_error_83; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server: + s_n_llhttp__internal__n_url_server: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7, + 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 6: { + goto s_n_llhttp__internal__n_span_start_stub_path; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 8: { + p++; + goto s_n_llhttp__internal__n_url_server_with_at; + } + default: { + goto s_n_llhttp__internal__n_error_84; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim_1: + s_n_llhttp__internal__n_url_schema_delim_1: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim_1; + } + switch (*p) { + case '/': { + p++; + goto s_n_llhttp__internal__n_url_server; + } + default: { + goto s_n_llhttp__internal__n_error_85; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim: + s_n_llhttp__internal__n_url_schema_delim: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case '/': { + p++; + goto s_n_llhttp__internal__n_url_schema_delim_1; + } + default: { + goto s_n_llhttp__internal__n_error_85; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_schema: + s_n_llhttp__internal__n_span_end_stub_schema: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_schema; + } + p++; + goto s_n_llhttp__internal__n_url_schema_delim; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema: + s_n_llhttp__internal__n_url_schema: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_schema; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_stub_schema; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_86; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_start: + s_n_llhttp__internal__n_url_start: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_start; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_start_stub_path_2; + } + case 3: { + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_87; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url_1: + s_n_llhttp__internal__n_span_start_llhttp__on_url_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_entry_normal: + s_n_llhttp__internal__n_url_entry_normal: { + if (p == endp) { + return s_n_llhttp__internal__n_url_entry_normal; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url: + s_n_llhttp__internal__n_span_start_llhttp__on_url: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_server; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_entry_connect: + s_n_llhttp__internal__n_url_entry_connect: { + if (p == endp) { + return s_n_llhttp__internal__n_url_entry_connect; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_spaces_before_url: + s_n_llhttp__internal__n_req_spaces_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_spaces_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_invoke_is_equal_method; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_first_space_before_url: + s_n_llhttp__internal__n_req_first_space_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_first_space_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_error_88; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: { + switch (llhttp__on_method_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_req_first_space_before_url; + case 21: + goto s_n_llhttp__internal__n_pause_26; + default: + goto s_n_llhttp__internal__n_error_107; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_2: + s_n_llhttp__internal__n_after_start_req_2: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_2; + } + switch (*p) { + case 'L': { + p++; + match = 19; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_3: + s_n_llhttp__internal__n_after_start_req_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 36; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_1: + s_n_llhttp__internal__n_after_start_req_1: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_1; + } + switch (*p) { + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_2; + } + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_3; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_4: + s_n_llhttp__internal__n_after_start_req_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_4; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 16; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_6: + s_n_llhttp__internal__n_after_start_req_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_6; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 22; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_8: + s_n_llhttp__internal__n_after_start_req_8: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_8; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_8; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_9: + s_n_llhttp__internal__n_after_start_req_9: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_9; + } + switch (*p) { + case 'Y': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_7: + s_n_llhttp__internal__n_after_start_req_7: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_7; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_8; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_9; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_5: + s_n_llhttp__internal__n_after_start_req_5: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_5; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_after_start_req_6; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_7; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_12: + s_n_llhttp__internal__n_after_start_req_12: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_12; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_12; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_13: + s_n_llhttp__internal__n_after_start_req_13: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_13; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 35; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_13; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_11: + s_n_llhttp__internal__n_after_start_req_11: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_11; + } + switch (*p) { + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_12; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_after_start_req_13; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_10: + s_n_llhttp__internal__n_after_start_req_10: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_10; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_11; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_14: + s_n_llhttp__internal__n_after_start_req_14: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_14; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 45; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_14; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_17: + s_n_llhttp__internal__n_after_start_req_17: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_17; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 41; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_17; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_16: + s_n_llhttp__internal__n_after_start_req_16: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_16; + } + switch (*p) { + case '_': { + p++; + goto s_n_llhttp__internal__n_after_start_req_17; + } + default: { + match = 1; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_15: + s_n_llhttp__internal__n_after_start_req_15: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_15; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_after_start_req_16; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_15; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_18: + s_n_llhttp__internal__n_after_start_req_18: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_18; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_18; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_20: + s_n_llhttp__internal__n_after_start_req_20: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_20; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 31; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_20; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_21: + s_n_llhttp__internal__n_after_start_req_21: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_21; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_21; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_19: + s_n_llhttp__internal__n_after_start_req_19: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_19; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_after_start_req_20; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_21; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_23: + s_n_llhttp__internal__n_after_start_req_23: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_23; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 24; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_23; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_24: + s_n_llhttp__internal__n_after_start_req_24: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_24; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 23; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_24; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_26: + s_n_llhttp__internal__n_after_start_req_26: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_26; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 21; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_26; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_28: + s_n_llhttp__internal__n_after_start_req_28: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_28; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 30; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_28; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_29: + s_n_llhttp__internal__n_after_start_req_29: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_29; + } + switch (*p) { + case 'L': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_27: + s_n_llhttp__internal__n_after_start_req_27: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_27; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_28; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_29; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_25: + s_n_llhttp__internal__n_after_start_req_25: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_25; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_26; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_27; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_30: + s_n_llhttp__internal__n_after_start_req_30: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_30; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_30; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_22: + s_n_llhttp__internal__n_after_start_req_22: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_22; + } + switch (*p) { + case '-': { + p++; + goto s_n_llhttp__internal__n_after_start_req_23; + } + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_24; + } + case 'K': { + p++; + goto s_n_llhttp__internal__n_after_start_req_25; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_30; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_31: + s_n_llhttp__internal__n_after_start_req_31: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_31; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 25; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_31; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_32: + s_n_llhttp__internal__n_after_start_req_32: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_32; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_32; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_35: + s_n_llhttp__internal__n_after_start_req_35: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_35; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 28; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_35; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_36: + s_n_llhttp__internal__n_after_start_req_36: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_36; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 39; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_36; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_34: + s_n_llhttp__internal__n_after_start_req_34: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_34; + } + switch (*p) { + case 'T': { + p++; + goto s_n_llhttp__internal__n_after_start_req_35; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_36; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_37: + s_n_llhttp__internal__n_after_start_req_37: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_37; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 38; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_37; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_38: + s_n_llhttp__internal__n_after_start_req_38: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_38; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_38; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_42: + s_n_llhttp__internal__n_after_start_req_42: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_42; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_42; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_43: + s_n_llhttp__internal__n_after_start_req_43: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_43; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_43; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_41: + s_n_llhttp__internal__n_after_start_req_41: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_41; + } + switch (*p) { + case 'F': { + p++; + goto s_n_llhttp__internal__n_after_start_req_42; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_43; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_40: + s_n_llhttp__internal__n_after_start_req_40: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_40; + } + switch (*p) { + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_41; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_39: + s_n_llhttp__internal__n_after_start_req_39: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_39; + } + switch (*p) { + case 'I': { + p++; + match = 34; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_40; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_45: + s_n_llhttp__internal__n_after_start_req_45: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_45; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 29; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_45; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_44: + s_n_llhttp__internal__n_after_start_req_44: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_44; + } + switch (*p) { + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_45; + } + case 'T': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_33: + s_n_llhttp__internal__n_after_start_req_33: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_33; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_34; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_37; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_38; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_39; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_44; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_46: + s_n_llhttp__internal__n_after_start_req_46: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_46; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 46; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_46; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_49: + s_n_llhttp__internal__n_after_start_req_49: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_49; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 17; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_49; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_50: + s_n_llhttp__internal__n_after_start_req_50: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_50; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 44; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_50; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_51: + s_n_llhttp__internal__n_after_start_req_51: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_51; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 43; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_51; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_52: + s_n_llhttp__internal__n_after_start_req_52: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_52; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 20; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_52; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_48: + s_n_llhttp__internal__n_after_start_req_48: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_48; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_after_start_req_49; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_50; + } + case 'D': { + p++; + goto s_n_llhttp__internal__n_after_start_req_51; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_52; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_47: + s_n_llhttp__internal__n_after_start_req_47: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_47; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_48; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_55: + s_n_llhttp__internal__n_after_start_req_55: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_55; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob48, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_55; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_57: + s_n_llhttp__internal__n_after_start_req_57: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_57; + } + switch (*p) { + case 'P': { + p++; + match = 37; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_58: + s_n_llhttp__internal__n_after_start_req_58: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_58; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob49, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 42; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_58; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_56: + s_n_llhttp__internal__n_after_start_req_56: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_56; + } + switch (*p) { + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_57; + } + case '_': { + p++; + goto s_n_llhttp__internal__n_after_start_req_58; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_54: + s_n_llhttp__internal__n_after_start_req_54: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_54; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_55; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_after_start_req_56; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_59: + s_n_llhttp__internal__n_after_start_req_59: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_59; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob50, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 33; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_59; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_60: + s_n_llhttp__internal__n_after_start_req_60: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_60; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob51, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 26; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_60; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_53: + s_n_llhttp__internal__n_after_start_req_53: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_53; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_54; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_59; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_60; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_62: + s_n_llhttp__internal__n_after_start_req_62: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_62; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob52, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 40; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_62; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_63: + s_n_llhttp__internal__n_after_start_req_63: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_63; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob53, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_63; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_61: + s_n_llhttp__internal__n_after_start_req_61: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_61; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_62; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_63; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_66: + s_n_llhttp__internal__n_after_start_req_66: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_66; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob54, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 18; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_66; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_68: + s_n_llhttp__internal__n_after_start_req_68: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_68; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob55, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 32; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_68; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_69: + s_n_llhttp__internal__n_after_start_req_69: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_69; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob56, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_69; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_67: + s_n_llhttp__internal__n_after_start_req_67: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_67; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_after_start_req_68; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_69; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_70: + s_n_llhttp__internal__n_after_start_req_70: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_70; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob57, 8); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 27; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_70; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_65: + s_n_llhttp__internal__n_after_start_req_65: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_65; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_after_start_req_66; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_67; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_after_start_req_70; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_64: + s_n_llhttp__internal__n_after_start_req_64: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_64; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_65; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req: + s_n_llhttp__internal__n_after_start_req: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_1; + } + case 'B': { + p++; + goto s_n_llhttp__internal__n_after_start_req_4; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_5; + } + case 'D': { + p++; + goto s_n_llhttp__internal__n_after_start_req_10; + } + case 'F': { + p++; + goto s_n_llhttp__internal__n_after_start_req_14; + } + case 'G': { + p++; + goto s_n_llhttp__internal__n_after_start_req_15; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_after_start_req_18; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_19; + } + case 'M': { + p++; + goto s_n_llhttp__internal__n_after_start_req_22; + } + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_31; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_32; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_33; + } + case 'Q': { + p++; + goto s_n_llhttp__internal__n_after_start_req_46; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_47; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_after_start_req_53; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_after_start_req_61; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_64; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_method_1: + s_n_llhttp__internal__n_span_start_llhttp__on_method_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_method_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_method; + goto s_n_llhttp__internal__n_after_start_req; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_line_almost_done: + s_n_llhttp__internal__n_res_line_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_res_line_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_29; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_30: + s_n_llhttp__internal__n_invoke_test_lenient_flags_30: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + default: + goto s_n_llhttp__internal__n_error_94; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status: + s_n_llhttp__internal__n_res_status: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1; + } + default: { + p++; + goto s_n_llhttp__internal__n_res_status; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_status: + s_n_llhttp__internal__n_span_start_llhttp__on_status: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_status; + goto s_n_llhttp__internal__n_res_status; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_otherwise: + s_n_llhttp__internal__n_res_status_code_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_otherwise; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_28; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + default: { + goto s_n_llhttp__internal__n_error_95; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_digit_3: + s_n_llhttp__internal__n_res_status_code_digit_3: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_digit_3; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + default: { + goto s_n_llhttp__internal__n_error_97; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_digit_2: + s_n_llhttp__internal__n_res_status_code_digit_2: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_digit_2; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + default: { + goto s_n_llhttp__internal__n_error_99; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_digit_1: + s_n_llhttp__internal__n_res_status_code_digit_1: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_digit_1; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + default: { + goto s_n_llhttp__internal__n_error_101; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_after_version: + s_n_llhttp__internal__n_res_after_version: { + if (p == endp) { + return s_n_llhttp__internal__n_res_after_version; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_update_status_code; + } + default: { + goto s_n_llhttp__internal__n_error_102; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: { + switch (llhttp__on_version_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_res_after_version; + case 21: + goto s_n_llhttp__internal__n_pause_25; + default: + goto s_n_llhttp__internal__n_error_90; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_89: + s_n_llhttp__internal__n_error_89: { + state->error = 0x9; + state->reason = "Invalid HTTP version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_103: + s_n_llhttp__internal__n_error_103: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_minor: + s_n_llhttp__internal__n_res_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_104: + s_n_llhttp__internal__n_error_104: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_dot: + s_n_llhttp__internal__n_res_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_res_http_minor; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_8; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_105: + s_n_llhttp__internal__n_error_105: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_major: + s_n_llhttp__internal__n_res_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_9; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_version_1: + s_n_llhttp__internal__n_span_start_llhttp__on_version_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_version; + goto s_n_llhttp__internal__n_res_http_major; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_res: + s_n_llhttp__internal__n_start_res: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_res; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_res; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_109; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: { + switch (llhttp__on_method_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_req_first_space_before_url; + case 21: + goto s_n_llhttp__internal__n_pause_23; + default: + goto s_n_llhttp__internal__n_error_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_2: + s_n_llhttp__internal__n_req_or_res_method_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_type_1: + s_n_llhttp__internal__n_invoke_update_type_1: { + switch (llhttp__internal__c_update_type_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_3: + s_n_llhttp__internal__n_req_or_res_method_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_span_end_llhttp__on_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_1: + s_n_llhttp__internal__n_req_or_res_method_1: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_1; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_2; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_3; + } + default: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method: + s_n_llhttp__internal__n_req_or_res_method: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_method: + s_n_llhttp__internal__n_span_start_llhttp__on_method: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_method; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_method; + goto s_n_llhttp__internal__n_req_or_res_method; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_or_res: + s_n_llhttp__internal__n_start_req_or_res: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_or_res; + } + switch (*p) { + case 'H': { + goto s_n_llhttp__internal__n_span_start_llhttp__on_method; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_type_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_type: + s_n_llhttp__internal__n_invoke_load_type: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; + case 2: + goto s_n_llhttp__internal__n_start_res; + default: + goto s_n_llhttp__internal__n_start_req_or_res; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_finish: + s_n_llhttp__internal__n_invoke_update_finish: { + switch (llhttp__internal__c_update_finish(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start: + s_n_llhttp__internal__n_start: { + if (p == endp) { + return s_n_llhttp__internal__n_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_start; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_initial_message_completed; + } + } + /* UNREACHABLE */; + abort(); + } + default: + /* UNREACHABLE */ + abort(); + } + s_n_llhttp__internal__n_error_2: { + state->error = 0x7; + state->reason = "Invalid characters in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_2: { + switch (llhttp__internal__c_update_finish_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_initial_message_completed: { + switch (llhttp__internal__c_update_initial_message_completed(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_finish_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_content_length: { + switch (llhttp__internal__c_update_content_length(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_initial_message_completed; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_8: { + state->error = 0x5; + state->reason = "Data after `Connection: close`"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_3: { + switch (llhttp__internal__c_test_lenient_flags_3(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_closed; + default: + goto s_n_llhttp__internal__n_error_8; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_2: { + switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_update_initial_message_completed; + default: + goto s_n_llhttp__internal__n_closed; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_1: { + switch (llhttp__internal__c_update_finish_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_13: { + state->error = 0x15; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_38: { + state->error = 0x12; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_15: { + state->error = 0x15; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_40: { + state->error = 0x14; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + case 21: + goto s_n_llhttp__internal__n_pause_15; + default: + goto s_n_llhttp__internal__n_error_40; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_2: { + state->error = 0x15; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_9: { + state->error = 0x12; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_pause_1; + case 21: + goto s_n_llhttp__internal__n_pause_2; + default: + goto s_n_llhttp__internal__n_error_9; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_36: { + state->error = 0xc; + state->reason = "Chunk size overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_10: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_4: { + switch (llhttp__internal__c_test_lenient_flags_4(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_otherwise; + default: + goto s_n_llhttp__internal__n_error_10; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_3: { + state->error = 0x15; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_14: { + state->error = 0x14; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_update_content_length_1; + case 21: + goto s_n_llhttp__internal__n_pause_3; + default: + goto s_n_llhttp__internal__n_error_14; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_13: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk data"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_6: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + default: + goto s_n_llhttp__internal__n_error_13; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_15: { + state->error = 0x2; + state->reason = "Expected LF after chunk data"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_7: { + switch (llhttp__internal__c_test_lenient_flags_7(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + default: + goto s_n_llhttp__internal__n_error_15; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_chunk_data_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags: { + switch (llhttp__internal__c_or_flags(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_4: { + state->error = 0x15; + state->reason = "on_chunk_header pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_12: { + state->error = 0x13; + state->reason = "`on_chunk_header` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: { + switch (llhttp__on_chunk_header(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_content_length; + case 21: + goto s_n_llhttp__internal__n_pause_4; + default: + goto s_n_llhttp__internal__n_error_12; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_16: { + state->error = 0x2; + state->reason = "Expected LF after chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_8: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; + default: + goto s_n_llhttp__internal__n_error_16; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_11: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_5: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_11; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_17: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_18: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_20: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk extension name"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_5: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_9; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_19: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_6: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_21: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_7: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_22: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_25: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk extension value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_8: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_10; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_24: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_9: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_26: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_28: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk extension value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_11: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_28; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_29: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions quote value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_10: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_quoted_value_done; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_27: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_30; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_30; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_31; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_31; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_11: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_32: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_33; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_33; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_12: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_value; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_23: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extension_value; + case 21: + goto s_n_llhttp__internal__n_pause_12; + default: + goto s_n_llhttp__internal__n_error_23; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_34; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_34; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_35: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length: { + switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_36; + default: + goto s_n_llhttp__internal__n_chunk_size; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_37: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_3: { + switch (llhttp__internal__c_update_finish_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_39: { + state->error = 0xf; + state->reason = "Request has invalid `Transfer-Encoding`"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause: { + state->error = 0x15; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_7: { + state->error = 0x12; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + case 21: + goto s_n_llhttp__internal__n_pause; + default: + goto s_n_llhttp__internal__n_error_7; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_1: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_2: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_upgrade: { + switch (llhttp__internal__c_update_upgrade(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_or_flags_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_14: { + state->error = 0x15; + state->reason = "Paused by on_headers_complete"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_6: { + state->error = 0x11; + state->reason = "User callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: { + switch (llhttp__on_headers_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + case 1: + goto s_n_llhttp__internal__n_invoke_or_flags_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_upgrade; + case 21: + goto s_n_llhttp__internal__n_pause_14; + default: + goto s_n_llhttp__internal__n_error_6; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: { + switch (llhttp__before_headers_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags: { + switch (llhttp__internal__c_test_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_1: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_flags; + default: + goto s_n_llhttp__internal__n_error_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_17: { + state->error = 0x15; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_42: { + state->error = 0x14; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + case 21: + goto s_n_llhttp__internal__n_pause_17; + default: + goto s_n_llhttp__internal__n_error_42; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_3: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_4: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_upgrade_1: { + switch (llhttp__internal__c_update_upgrade(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_or_flags_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_16: { + state->error = 0x15; + state->reason = "Paused by on_headers_complete"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_41: { + state->error = 0x11; + state->reason = "User callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1: { + switch (llhttp__on_headers_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + case 1: + goto s_n_llhttp__internal__n_invoke_or_flags_3; + case 2: + goto s_n_llhttp__internal__n_invoke_update_upgrade_1; + case 21: + goto s_n_llhttp__internal__n_pause_16; + default: + goto s_n_llhttp__internal__n_error_41; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1: { + switch (llhttp__before_headers_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_1: { + switch (llhttp__internal__c_test_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_43: { + state->error = 0x2; + state->reason = "Expected LF after headers"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_12: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_flags_1; + default: + goto s_n_llhttp__internal__n_error_43; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_44: { + state->error = 0xa; + state->reason = "Invalid header token"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_5; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_5; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_13: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_field_colon_discard_ws; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_60: { + state->error = 0xb; + state->reason = "Content-Length can't be present with Transfer-Encoding"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_47: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_15: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_discard_ws; + default: + goto s_n_llhttp__internal__n_error_47; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_49: { + state->error = 0xb; + state->reason = "Empty Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_18: { + state->error = 0x15; + state->reason = "on_header_value_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_48: { + state->error = 0x1d; + state->reason = "`on_header_value_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_5: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_6: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_7: { + switch (llhttp__internal__c_or_flags_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_8: { + switch (llhttp__internal__c_or_flags_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_2: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_5; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_6; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_7; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_8; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_1: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 2: + goto s_n_llhttp__internal__n_error_49; + default: + goto s_n_llhttp__internal__n_invoke_load_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_46: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_14: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_discard_lws; + default: + goto s_n_llhttp__internal__n_error_46; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_50: { + state->error = 0x2; + state->reason = "Expected LF after CR"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_16: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_discard_lws; + default: + goto s_n_llhttp__internal__n_error_50; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_1: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_4: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 8: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_52: { + state->error = 0xa; + state->reason = "Unexpected whitespace after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_18: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_load_header_state_4; + default: + goto s_n_llhttp__internal__n_error_52; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_2: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_9: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_10: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_11: { + switch (llhttp__internal__c_or_flags_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_12: { + switch (llhttp__internal__c_or_flags_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_5: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_9; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_10; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_11; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_12; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_53: { + state->error = 0x3; + state->reason = "Missing expected LF after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_51: { + state->error = 0x19; + state->reason = "Missing expected CR after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_17; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_17; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_54; + return s_error; + } + goto s_n_llhttp__internal__n_error_54; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_19: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_lenient; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_4: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_13: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_14: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_15: { + switch (llhttp__internal__c_or_flags_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_16: { + switch (llhttp__internal__c_or_flags_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_6: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_13; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_14; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_15; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_16; + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_5: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_token; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_3: { + switch (llhttp__internal__c_update_header_state_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_6: { + switch (llhttp__internal__c_update_header_state_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_7: { + switch (llhttp__internal__c_update_header_state_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_56; + return s_error; + } + goto s_n_llhttp__internal__n_error_56; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length_1: { + switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6; + default: + goto s_n_llhttp__internal__n_header_value_content_length; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_17: { + switch (llhttp__internal__c_or_flags_17(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_otherwise; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_57; + return s_error; + } + goto s_n_llhttp__internal__n_error_57; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_55: { + state->error = 0x4; + state->reason = "Duplicate Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_2: { + switch (llhttp__internal__c_test_flags_2(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_header_value_content_length; + default: + goto s_n_llhttp__internal__n_error_55; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_59; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_59; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_8: { + switch (llhttp__internal__c_update_header_state_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_otherwise; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_58; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_58; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_20: { + switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8; + default: + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_type_1: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_20; + default: + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_9: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_and_flags: { + switch (llhttp__internal__c_and_flags(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_19: { + switch (llhttp__internal__c_or_flags_18(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_and_flags; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_21: { + switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9; + default: + goto s_n_llhttp__internal__n_invoke_or_flags_19; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_type_2: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_21; + default: + goto s_n_llhttp__internal__n_invoke_or_flags_19; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_18: { + switch (llhttp__internal__c_or_flags_18(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_and_flags; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_3: { + switch (llhttp__internal__c_test_flags_3(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_load_type_2; + default: + goto s_n_llhttp__internal__n_invoke_or_flags_18; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_20: { + switch (llhttp__internal__c_or_flags_20(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_9; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_3: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_connection; + case 2: + goto s_n_llhttp__internal__n_invoke_test_flags_2; + case 3: + goto s_n_llhttp__internal__n_invoke_test_flags_3; + case 4: + goto s_n_llhttp__internal__n_invoke_or_flags_20; + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_22: { + switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_error_60; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_4: { + switch (llhttp__internal__c_test_flags_4(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_22; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_61: { + state->error = 0xf; + state->reason = "Transfer-Encoding can't be present with Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_23: { + switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_error_61; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_5: { + switch (llhttp__internal__c_test_flags_2(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_23; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_19: { + state->error = 0x15; + state->reason = "on_header_field_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_header_state; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_45: { + state->error = 0x1c; + state->reason = "`on_header_field_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_62: { + state->error = 0xa; + state->reason = "Invalid header token"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_10: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_header_state: { + switch (llhttp__internal__c_store_header_state(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_header_field_colon; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_11: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_4: { + state->error = 0x1e; + state->reason = "Unexpected space after start line"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_field_start; + default: + goto s_n_llhttp__internal__n_error_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_20: { + state->error = 0x15; + state->reason = "on_url_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_3: { + state->error = 0x1a; + state->reason = "`on_url_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_url_complete: { + switch (llhttp__on_url_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_headers_start; + case 21: + goto s_n_llhttp__internal__n_pause_20; + default: + goto s_n_llhttp__internal__n_error_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_minor: { + switch (llhttp__internal__c_update_http_minor(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_major: { + switch (llhttp__internal__c_update_http_major(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_http_minor; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_63: { + state->error = 0x7; + state->reason = "Expected CRLF"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_71: { + state->error = 0x17; + state->reason = "Pause on PRI/Upgrade"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_72: { + state->error = 0x9; + state->reason = "Expected HTTP/2 Connection Preface"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_69: { + state->error = 0x2; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_26: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_headers_start; + default: + goto s_n_llhttp__internal__n_error_69; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_68: { + state->error = 0x9; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_25: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_req_http_complete_crlf; + default: + goto s_n_llhttp__internal__n_error_68; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_70: { + state->error = 0x9; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_21: { + state->error = 0x15; + state->reason = "on_version_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_67: { + state->error = 0x21; + state->reason = "`on_version_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_version_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_66; + return s_error; + } + goto s_n_llhttp__internal__n_error_66; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 9: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_1: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_2: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_major: { + switch (llhttp__internal__c_load_http_major(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_http_minor; + case 1: + goto s_n_llhttp__internal__n_invoke_load_http_minor_1; + case 2: + goto s_n_llhttp__internal__n_invoke_load_http_minor_2; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_24: { + switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_invoke_load_http_major; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_24; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_73; + return s_error; + } + goto s_n_llhttp__internal__n_error_73; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_74; + return s_error; + } + goto s_n_llhttp__internal__n_error_74; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_75; + return s_error; + } + goto s_n_llhttp__internal__n_error_75; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_65: { + state->error = 0x8; + state->reason = "Invalid method for HTTP/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_method: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 1: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 2: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 4: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 5: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 6: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 7: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 8: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 9: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 10: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 11: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 12: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 13: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 14: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 15: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 16: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 17: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 18: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 19: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 20: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 21: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 22: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 23: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 24: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 25: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 26: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 27: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 28: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 29: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 30: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 31: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 32: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 33: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 34: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 46: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + default: + goto s_n_llhttp__internal__n_error_65; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_78: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_76: { + state->error = 0x8; + state->reason = "Expected SOURCE method for ICE/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_method_2: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 33: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + default: + goto s_n_llhttp__internal__n_error_76; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_77: { + state->error = 0x8; + state->reason = "Invalid method for RTSP/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_method_3: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 6: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 35: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 36: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 37: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 38: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 39: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 40: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 41: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 42: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 43: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 44: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 45: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + default: + goto s_n_llhttp__internal__n_error_77; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_22: { + state->error = 0x15; + state->reason = "on_url_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_http_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_64: { + state->error = 0x1a; + state->reason = "`on_url_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1: { + switch (llhttp__on_url_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_req_http_start; + case 21: + goto s_n_llhttp__internal__n_pause_22; + default: + goto s_n_llhttp__internal__n_error_64; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_79: { + state->error = 0x7; + state->reason = "Invalid char in url fragment start"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_10: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_11: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_80: { + state->error = 0x7; + state->reason = "Invalid char in url query"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_81: { + state->error = 0x7; + state->reason = "Invalid char in url path"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_12: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_13: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_14: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_82: { + state->error = 0x7; + state->reason = "Double @ in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_83: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_84: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_85: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_86: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_87: { + state->error = 0x7; + state->reason = "Unexpected start char in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_is_equal_method: { + switch (llhttp__internal__c_is_equal_method(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_url_entry_normal; + default: + goto s_n_llhttp__internal__n_url_entry_connect; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_88: { + state->error = 0x6; + state->reason = "Expected space after method"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_26: { + state->error = 0x15; + state->reason = "on_method_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_107: { + state->error = 0x20; + state->reason = "`on_method_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_method_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_method(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method_1: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_method_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_108: { + state->error = 0x6; + state->reason = "Invalid method encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_100: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_98: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_96: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_24: { + state->error = 0x15; + state->reason = "on_status_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_92: { + state->error = 0x1b; + state->reason = "`on_status_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_status_complete: { + switch (llhttp__on_status_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_headers_start; + case 21: + goto s_n_llhttp__internal__n_pause_24; + default: + goto s_n_llhttp__internal__n_error_92; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_91: { + state->error = 0xd; + state->reason = "Invalid response status"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_28: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + default: + goto s_n_llhttp__internal__n_error_91; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_93: { + state->error = 0x2; + state->reason = "Expected LF after CR"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_29: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + default: + goto s_n_llhttp__internal__n_error_93; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_94: { + state->error = 0x19; + state->reason = "Missing expected CR after response line"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_30; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_30; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_95: { + state->error = 0xd; + state->reason = "Invalid response status"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code_2: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_96; + default: + goto s_n_llhttp__internal__n_res_status_code_otherwise; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_97: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code_1: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_98; + default: + goto s_n_llhttp__internal__n_res_status_code_digit_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_99: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_100; + default: + goto s_n_llhttp__internal__n_res_status_code_digit_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_101: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_status_code: { + switch (llhttp__internal__c_update_status_code(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_res_status_code_digit_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_102: { + state->error = 0x9; + state->reason = "Expected space after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_25: { + state->error = 0x15; + state->reason = "on_version_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_after_version; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_90: { + state->error = 0x21; + state->reason = "`on_version_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_89; + return s_error; + } + goto s_n_llhttp__internal__n_error_89; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_3: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 9: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_4: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_5: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_major_1: { + switch (llhttp__internal__c_load_http_major(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_http_minor_3; + case 1: + goto s_n_llhttp__internal__n_invoke_load_http_minor_4; + case 2: + goto s_n_llhttp__internal__n_invoke_load_http_minor_5; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_27: { + switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_invoke_load_http_major_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor_1: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_27; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_103; + return s_error; + } + goto s_n_llhttp__internal__n_error_103; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_104; + return s_error; + } + goto s_n_llhttp__internal__n_error_104; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major_1: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_res_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_105; + return s_error; + } + goto s_n_llhttp__internal__n_error_105; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_109: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_23: { + state->error = 0x15; + state->reason = "on_method_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_1: { + state->error = 0x20; + state->reason = "`on_method_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_method: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_method(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_method_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_method; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_update_type; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_106: { + state->error = 0x8; + state->reason = "Invalid word encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_method_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_method(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_type_1; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_update_type_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type_2: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_27: { + state->error = 0x15; + state->reason = "on_message_begin pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error: { + state->error = 0x10; + state->reason = "`on_message_begin` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: { + switch (llhttp__on_message_begin(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_type; + case 21: + goto s_n_llhttp__internal__n_pause_27; + default: + goto s_n_llhttp__internal__n_error; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_28: { + state->error = 0x15; + state->reason = "on_reset pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_finish; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_110: { + state->error = 0x1f; + state->reason = "`on_reset` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_reset: { + switch (llhttp__on_reset(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_update_finish; + case 21: + goto s_n_llhttp__internal__n_pause_28; + default: + goto s_n_llhttp__internal__n_error_110; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_initial_message_completed: { + switch (llhttp__internal__c_load_initial_message_completed(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_reset; + default: + goto s_n_llhttp__internal__n_invoke_update_finish; + } + /* UNREACHABLE */; + abort(); + } +} + +int llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) { + llparse_state_t next; + + /* check lingering errors */ + if (state->error != 0) { + return state->error; + } + + /* restart spans */ + if (state->_span_pos0 != NULL) { + state->_span_pos0 = (void*) p; + } + + next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp); + if (next == s_error) { + return state->error; + } + state->_current = (void*) (intptr_t) next; + + /* execute spans */ + if (state->_span_pos0 != NULL) { + int error; + + error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp); + if (error != 0) { + state->error = error; + state->error_pos = endp; + return error; + } + } + + return 0; +} \ No newline at end of file diff --git a/deps/llhttp/llhttp.h b/deps/llhttp/llhttp.h new file mode 100644 index 00000000000..26f01c32cc7 --- /dev/null +++ b/deps/llhttp/llhttp.h @@ -0,0 +1,897 @@ + +#ifndef INCLUDE_LLHTTP_H_ +#define INCLUDE_LLHTTP_H_ + +#define LLHTTP_VERSION_MAJOR 9 +#define LLHTTP_VERSION_MINOR 2 +#define LLHTTP_VERSION_PATCH 1 + +#ifndef INCLUDE_LLHTTP_ITSELF_H_ +#define INCLUDE_LLHTTP_ITSELF_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct llhttp__internal_s llhttp__internal_t; +struct llhttp__internal_s { + int32_t _index; + void* _span_pos0; + void* _span_cb0; + int32_t error; + const char* reason; + const char* error_pos; + void* data; + void* _current; + uint64_t content_length; + uint8_t type; + uint8_t method; + uint8_t http_major; + uint8_t http_minor; + uint8_t header_state; + uint16_t lenient_flags; + uint8_t upgrade; + uint8_t finish; + uint16_t flags; + uint16_t status_code; + uint8_t initial_message_completed; + void* settings; +}; + +int llhttp__internal_init(llhttp__internal_t* s); +int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_ITSELF_H_ */ + + +#ifndef LLLLHTTP_C_HEADERS_ +#define LLLLHTTP_C_HEADERS_ +#ifdef __cplusplus +extern "C" { +#endif + +enum llhttp_errno { + HPE_OK = 0, + HPE_INTERNAL = 1, + HPE_STRICT = 2, + HPE_CR_EXPECTED = 25, + HPE_LF_EXPECTED = 3, + HPE_UNEXPECTED_CONTENT_LENGTH = 4, + HPE_UNEXPECTED_SPACE = 30, + HPE_CLOSED_CONNECTION = 5, + HPE_INVALID_METHOD = 6, + HPE_INVALID_URL = 7, + HPE_INVALID_CONSTANT = 8, + HPE_INVALID_VERSION = 9, + HPE_INVALID_HEADER_TOKEN = 10, + HPE_INVALID_CONTENT_LENGTH = 11, + HPE_INVALID_CHUNK_SIZE = 12, + HPE_INVALID_STATUS = 13, + HPE_INVALID_EOF_STATE = 14, + HPE_INVALID_TRANSFER_ENCODING = 15, + HPE_CB_MESSAGE_BEGIN = 16, + HPE_CB_HEADERS_COMPLETE = 17, + HPE_CB_MESSAGE_COMPLETE = 18, + HPE_CB_CHUNK_HEADER = 19, + HPE_CB_CHUNK_COMPLETE = 20, + HPE_PAUSED = 21, + HPE_PAUSED_UPGRADE = 22, + HPE_PAUSED_H2_UPGRADE = 23, + HPE_USER = 24, + HPE_CB_URL_COMPLETE = 26, + HPE_CB_STATUS_COMPLETE = 27, + HPE_CB_METHOD_COMPLETE = 32, + HPE_CB_VERSION_COMPLETE = 33, + HPE_CB_HEADER_FIELD_COMPLETE = 28, + HPE_CB_HEADER_VALUE_COMPLETE = 29, + HPE_CB_CHUNK_EXTENSION_NAME_COMPLETE = 34, + HPE_CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35, + HPE_CB_RESET = 31 +}; +typedef enum llhttp_errno llhttp_errno_t; + +enum llhttp_flags { + F_CONNECTION_KEEP_ALIVE = 0x1, + F_CONNECTION_CLOSE = 0x2, + F_CONNECTION_UPGRADE = 0x4, + F_CHUNKED = 0x8, + F_UPGRADE = 0x10, + F_CONTENT_LENGTH = 0x20, + F_SKIPBODY = 0x40, + F_TRAILING = 0x80, + F_TRANSFER_ENCODING = 0x200 +}; +typedef enum llhttp_flags llhttp_flags_t; + +enum llhttp_lenient_flags { + LENIENT_HEADERS = 0x1, + LENIENT_CHUNKED_LENGTH = 0x2, + LENIENT_KEEP_ALIVE = 0x4, + LENIENT_TRANSFER_ENCODING = 0x8, + LENIENT_VERSION = 0x10, + LENIENT_DATA_AFTER_CLOSE = 0x20, + LENIENT_OPTIONAL_LF_AFTER_CR = 0x40, + LENIENT_OPTIONAL_CRLF_AFTER_CHUNK = 0x80, + LENIENT_OPTIONAL_CR_BEFORE_LF = 0x100, + LENIENT_SPACES_AFTER_CHUNK_SIZE = 0x200 +}; +typedef enum llhttp_lenient_flags llhttp_lenient_flags_t; + +enum llhttp_type { + HTTP_BOTH = 0, + HTTP_REQUEST = 1, + HTTP_RESPONSE = 2 +}; +typedef enum llhttp_type llhttp_type_t; + +enum llhttp_finish { + HTTP_FINISH_SAFE = 0, + HTTP_FINISH_SAFE_WITH_CB = 1, + HTTP_FINISH_UNSAFE = 2 +}; +typedef enum llhttp_finish llhttp_finish_t; + +enum llhttp_method { + HTTP_DELETE = 0, + HTTP_GET = 1, + HTTP_HEAD = 2, + HTTP_POST = 3, + HTTP_PUT = 4, + HTTP_CONNECT = 5, + HTTP_OPTIONS = 6, + HTTP_TRACE = 7, + HTTP_COPY = 8, + HTTP_LOCK = 9, + HTTP_MKCOL = 10, + HTTP_MOVE = 11, + HTTP_PROPFIND = 12, + HTTP_PROPPATCH = 13, + HTTP_SEARCH = 14, + HTTP_UNLOCK = 15, + HTTP_BIND = 16, + HTTP_REBIND = 17, + HTTP_UNBIND = 18, + HTTP_ACL = 19, + HTTP_REPORT = 20, + HTTP_MKACTIVITY = 21, + HTTP_CHECKOUT = 22, + HTTP_MERGE = 23, + HTTP_MSEARCH = 24, + HTTP_NOTIFY = 25, + HTTP_SUBSCRIBE = 26, + HTTP_UNSUBSCRIBE = 27, + HTTP_PATCH = 28, + HTTP_PURGE = 29, + HTTP_MKCALENDAR = 30, + HTTP_LINK = 31, + HTTP_UNLINK = 32, + HTTP_SOURCE = 33, + HTTP_PRI = 34, + HTTP_DESCRIBE = 35, + HTTP_ANNOUNCE = 36, + HTTP_SETUP = 37, + HTTP_PLAY = 38, + HTTP_PAUSE = 39, + HTTP_TEARDOWN = 40, + HTTP_GET_PARAMETER = 41, + HTTP_SET_PARAMETER = 42, + HTTP_REDIRECT = 43, + HTTP_RECORD = 44, + HTTP_FLUSH = 45, + HTTP_QUERY = 46 +}; +typedef enum llhttp_method llhttp_method_t; + +enum llhttp_status { + HTTP_STATUS_CONTINUE = 100, + HTTP_STATUS_SWITCHING_PROTOCOLS = 101, + HTTP_STATUS_PROCESSING = 102, + HTTP_STATUS_EARLY_HINTS = 103, + HTTP_STATUS_RESPONSE_IS_STALE = 110, + HTTP_STATUS_REVALIDATION_FAILED = 111, + HTTP_STATUS_DISCONNECTED_OPERATION = 112, + HTTP_STATUS_HEURISTIC_EXPIRATION = 113, + HTTP_STATUS_MISCELLANEOUS_WARNING = 199, + HTTP_STATUS_OK = 200, + HTTP_STATUS_CREATED = 201, + HTTP_STATUS_ACCEPTED = 202, + HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, + HTTP_STATUS_NO_CONTENT = 204, + HTTP_STATUS_RESET_CONTENT = 205, + HTTP_STATUS_PARTIAL_CONTENT = 206, + HTTP_STATUS_MULTI_STATUS = 207, + HTTP_STATUS_ALREADY_REPORTED = 208, + HTTP_STATUS_TRANSFORMATION_APPLIED = 214, + HTTP_STATUS_IM_USED = 226, + HTTP_STATUS_MISCELLANEOUS_PERSISTENT_WARNING = 299, + HTTP_STATUS_MULTIPLE_CHOICES = 300, + HTTP_STATUS_MOVED_PERMANENTLY = 301, + HTTP_STATUS_FOUND = 302, + HTTP_STATUS_SEE_OTHER = 303, + HTTP_STATUS_NOT_MODIFIED = 304, + HTTP_STATUS_USE_PROXY = 305, + HTTP_STATUS_SWITCH_PROXY = 306, + HTTP_STATUS_TEMPORARY_REDIRECT = 307, + HTTP_STATUS_PERMANENT_REDIRECT = 308, + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED = 401, + HTTP_STATUS_PAYMENT_REQUIRED = 402, + HTTP_STATUS_FORBIDDEN = 403, + HTTP_STATUS_NOT_FOUND = 404, + HTTP_STATUS_METHOD_NOT_ALLOWED = 405, + HTTP_STATUS_NOT_ACCEPTABLE = 406, + HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, + HTTP_STATUS_REQUEST_TIMEOUT = 408, + HTTP_STATUS_CONFLICT = 409, + HTTP_STATUS_GONE = 410, + HTTP_STATUS_LENGTH_REQUIRED = 411, + HTTP_STATUS_PRECONDITION_FAILED = 412, + HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, + HTTP_STATUS_URI_TOO_LONG = 414, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, + HTTP_STATUS_EXPECTATION_FAILED = 417, + HTTP_STATUS_IM_A_TEAPOT = 418, + HTTP_STATUS_PAGE_EXPIRED = 419, + HTTP_STATUS_ENHANCE_YOUR_CALM = 420, + HTTP_STATUS_MISDIRECTED_REQUEST = 421, + HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, + HTTP_STATUS_LOCKED = 423, + HTTP_STATUS_FAILED_DEPENDENCY = 424, + HTTP_STATUS_TOO_EARLY = 425, + HTTP_STATUS_UPGRADE_REQUIRED = 426, + HTTP_STATUS_PRECONDITION_REQUIRED = 428, + HTTP_STATUS_TOO_MANY_REQUESTS = 429, + HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL = 430, + HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + HTTP_STATUS_LOGIN_TIMEOUT = 440, + HTTP_STATUS_NO_RESPONSE = 444, + HTTP_STATUS_RETRY_WITH = 449, + HTTP_STATUS_BLOCKED_BY_PARENTAL_CONTROL = 450, + HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, + HTTP_STATUS_CLIENT_CLOSED_LOAD_BALANCED_REQUEST = 460, + HTTP_STATUS_INVALID_X_FORWARDED_FOR = 463, + HTTP_STATUS_REQUEST_HEADER_TOO_LARGE = 494, + HTTP_STATUS_SSL_CERTIFICATE_ERROR = 495, + HTTP_STATUS_SSL_CERTIFICATE_REQUIRED = 496, + HTTP_STATUS_HTTP_REQUEST_SENT_TO_HTTPS_PORT = 497, + HTTP_STATUS_INVALID_TOKEN = 498, + HTTP_STATUS_CLIENT_CLOSED_REQUEST = 499, + HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + HTTP_STATUS_NOT_IMPLEMENTED = 501, + HTTP_STATUS_BAD_GATEWAY = 502, + HTTP_STATUS_SERVICE_UNAVAILABLE = 503, + HTTP_STATUS_GATEWAY_TIMEOUT = 504, + HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, + HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, + HTTP_STATUS_INSUFFICIENT_STORAGE = 507, + HTTP_STATUS_LOOP_DETECTED = 508, + HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509, + HTTP_STATUS_NOT_EXTENDED = 510, + HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511, + HTTP_STATUS_WEB_SERVER_UNKNOWN_ERROR = 520, + HTTP_STATUS_WEB_SERVER_IS_DOWN = 521, + HTTP_STATUS_CONNECTION_TIMEOUT = 522, + HTTP_STATUS_ORIGIN_IS_UNREACHABLE = 523, + HTTP_STATUS_TIMEOUT_OCCURED = 524, + HTTP_STATUS_SSL_HANDSHAKE_FAILED = 525, + HTTP_STATUS_INVALID_SSL_CERTIFICATE = 526, + HTTP_STATUS_RAILGUN_ERROR = 527, + HTTP_STATUS_SITE_IS_OVERLOADED = 529, + HTTP_STATUS_SITE_IS_FROZEN = 530, + HTTP_STATUS_IDENTITY_PROVIDER_AUTHENTICATION_ERROR = 561, + HTTP_STATUS_NETWORK_READ_TIMEOUT = 598, + HTTP_STATUS_NETWORK_CONNECT_TIMEOUT = 599 +}; +typedef enum llhttp_status llhttp_status_t; + +#define HTTP_ERRNO_MAP(XX) \ + XX(0, OK, OK) \ + XX(1, INTERNAL, INTERNAL) \ + XX(2, STRICT, STRICT) \ + XX(25, CR_EXPECTED, CR_EXPECTED) \ + XX(3, LF_EXPECTED, LF_EXPECTED) \ + XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \ + XX(30, UNEXPECTED_SPACE, UNEXPECTED_SPACE) \ + XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \ + XX(6, INVALID_METHOD, INVALID_METHOD) \ + XX(7, INVALID_URL, INVALID_URL) \ + XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \ + XX(9, INVALID_VERSION, INVALID_VERSION) \ + XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \ + XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \ + XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \ + XX(13, INVALID_STATUS, INVALID_STATUS) \ + XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \ + XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \ + XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \ + XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \ + XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \ + XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \ + XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \ + XX(21, PAUSED, PAUSED) \ + XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \ + XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \ + XX(24, USER, USER) \ + XX(26, CB_URL_COMPLETE, CB_URL_COMPLETE) \ + XX(27, CB_STATUS_COMPLETE, CB_STATUS_COMPLETE) \ + XX(32, CB_METHOD_COMPLETE, CB_METHOD_COMPLETE) \ + XX(33, CB_VERSION_COMPLETE, CB_VERSION_COMPLETE) \ + XX(28, CB_HEADER_FIELD_COMPLETE, CB_HEADER_FIELD_COMPLETE) \ + XX(29, CB_HEADER_VALUE_COMPLETE, CB_HEADER_VALUE_COMPLETE) \ + XX(34, CB_CHUNK_EXTENSION_NAME_COMPLETE, CB_CHUNK_EXTENSION_NAME_COMPLETE) \ + XX(35, CB_CHUNK_EXTENSION_VALUE_COMPLETE, CB_CHUNK_EXTENSION_VALUE_COMPLETE) \ + XX(31, CB_RESET, CB_RESET) \ + + +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + XX(30, MKCALENDAR, MKCALENDAR) \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + XX(33, SOURCE, SOURCE) \ + XX(46, QUERY, QUERY) \ + + +#define RTSP_METHOD_MAP(XX) \ + XX(1, GET, GET) \ + XX(3, POST, POST) \ + XX(6, OPTIONS, OPTIONS) \ + XX(35, DESCRIBE, DESCRIBE) \ + XX(36, ANNOUNCE, ANNOUNCE) \ + XX(37, SETUP, SETUP) \ + XX(38, PLAY, PLAY) \ + XX(39, PAUSE, PAUSE) \ + XX(40, TEARDOWN, TEARDOWN) \ + XX(41, GET_PARAMETER, GET_PARAMETER) \ + XX(42, SET_PARAMETER, SET_PARAMETER) \ + XX(43, REDIRECT, REDIRECT) \ + XX(44, RECORD, RECORD) \ + XX(45, FLUSH, FLUSH) \ + + +#define HTTP_ALL_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + XX(30, MKCALENDAR, MKCALENDAR) \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + XX(33, SOURCE, SOURCE) \ + XX(34, PRI, PRI) \ + XX(35, DESCRIBE, DESCRIBE) \ + XX(36, ANNOUNCE, ANNOUNCE) \ + XX(37, SETUP, SETUP) \ + XX(38, PLAY, PLAY) \ + XX(39, PAUSE, PAUSE) \ + XX(40, TEARDOWN, TEARDOWN) \ + XX(41, GET_PARAMETER, GET_PARAMETER) \ + XX(42, SET_PARAMETER, SET_PARAMETER) \ + XX(43, REDIRECT, REDIRECT) \ + XX(44, RECORD, RECORD) \ + XX(45, FLUSH, FLUSH) \ + XX(46, QUERY, QUERY) \ + + +#define HTTP_STATUS_MAP(XX) \ + XX(100, CONTINUE, CONTINUE) \ + XX(101, SWITCHING_PROTOCOLS, SWITCHING_PROTOCOLS) \ + XX(102, PROCESSING, PROCESSING) \ + XX(103, EARLY_HINTS, EARLY_HINTS) \ + XX(110, RESPONSE_IS_STALE, RESPONSE_IS_STALE) \ + XX(111, REVALIDATION_FAILED, REVALIDATION_FAILED) \ + XX(112, DISCONNECTED_OPERATION, DISCONNECTED_OPERATION) \ + XX(113, HEURISTIC_EXPIRATION, HEURISTIC_EXPIRATION) \ + XX(199, MISCELLANEOUS_WARNING, MISCELLANEOUS_WARNING) \ + XX(200, OK, OK) \ + XX(201, CREATED, CREATED) \ + XX(202, ACCEPTED, ACCEPTED) \ + XX(203, NON_AUTHORITATIVE_INFORMATION, NON_AUTHORITATIVE_INFORMATION) \ + XX(204, NO_CONTENT, NO_CONTENT) \ + XX(205, RESET_CONTENT, RESET_CONTENT) \ + XX(206, PARTIAL_CONTENT, PARTIAL_CONTENT) \ + XX(207, MULTI_STATUS, MULTI_STATUS) \ + XX(208, ALREADY_REPORTED, ALREADY_REPORTED) \ + XX(214, TRANSFORMATION_APPLIED, TRANSFORMATION_APPLIED) \ + XX(226, IM_USED, IM_USED) \ + XX(299, MISCELLANEOUS_PERSISTENT_WARNING, MISCELLANEOUS_PERSISTENT_WARNING) \ + XX(300, MULTIPLE_CHOICES, MULTIPLE_CHOICES) \ + XX(301, MOVED_PERMANENTLY, MOVED_PERMANENTLY) \ + XX(302, FOUND, FOUND) \ + XX(303, SEE_OTHER, SEE_OTHER) \ + XX(304, NOT_MODIFIED, NOT_MODIFIED) \ + XX(305, USE_PROXY, USE_PROXY) \ + XX(306, SWITCH_PROXY, SWITCH_PROXY) \ + XX(307, TEMPORARY_REDIRECT, TEMPORARY_REDIRECT) \ + XX(308, PERMANENT_REDIRECT, PERMANENT_REDIRECT) \ + XX(400, BAD_REQUEST, BAD_REQUEST) \ + XX(401, UNAUTHORIZED, UNAUTHORIZED) \ + XX(402, PAYMENT_REQUIRED, PAYMENT_REQUIRED) \ + XX(403, FORBIDDEN, FORBIDDEN) \ + XX(404, NOT_FOUND, NOT_FOUND) \ + XX(405, METHOD_NOT_ALLOWED, METHOD_NOT_ALLOWED) \ + XX(406, NOT_ACCEPTABLE, NOT_ACCEPTABLE) \ + XX(407, PROXY_AUTHENTICATION_REQUIRED, PROXY_AUTHENTICATION_REQUIRED) \ + XX(408, REQUEST_TIMEOUT, REQUEST_TIMEOUT) \ + XX(409, CONFLICT, CONFLICT) \ + XX(410, GONE, GONE) \ + XX(411, LENGTH_REQUIRED, LENGTH_REQUIRED) \ + XX(412, PRECONDITION_FAILED, PRECONDITION_FAILED) \ + XX(413, PAYLOAD_TOO_LARGE, PAYLOAD_TOO_LARGE) \ + XX(414, URI_TOO_LONG, URI_TOO_LONG) \ + XX(415, UNSUPPORTED_MEDIA_TYPE, UNSUPPORTED_MEDIA_TYPE) \ + XX(416, RANGE_NOT_SATISFIABLE, RANGE_NOT_SATISFIABLE) \ + XX(417, EXPECTATION_FAILED, EXPECTATION_FAILED) \ + XX(418, IM_A_TEAPOT, IM_A_TEAPOT) \ + XX(419, PAGE_EXPIRED, PAGE_EXPIRED) \ + XX(420, ENHANCE_YOUR_CALM, ENHANCE_YOUR_CALM) \ + XX(421, MISDIRECTED_REQUEST, MISDIRECTED_REQUEST) \ + XX(422, UNPROCESSABLE_ENTITY, UNPROCESSABLE_ENTITY) \ + XX(423, LOCKED, LOCKED) \ + XX(424, FAILED_DEPENDENCY, FAILED_DEPENDENCY) \ + XX(425, TOO_EARLY, TOO_EARLY) \ + XX(426, UPGRADE_REQUIRED, UPGRADE_REQUIRED) \ + XX(428, PRECONDITION_REQUIRED, PRECONDITION_REQUIRED) \ + XX(429, TOO_MANY_REQUESTS, TOO_MANY_REQUESTS) \ + XX(430, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL) \ + XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, REQUEST_HEADER_FIELDS_TOO_LARGE) \ + XX(440, LOGIN_TIMEOUT, LOGIN_TIMEOUT) \ + XX(444, NO_RESPONSE, NO_RESPONSE) \ + XX(449, RETRY_WITH, RETRY_WITH) \ + XX(450, BLOCKED_BY_PARENTAL_CONTROL, BLOCKED_BY_PARENTAL_CONTROL) \ + XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, UNAVAILABLE_FOR_LEGAL_REASONS) \ + XX(460, CLIENT_CLOSED_LOAD_BALANCED_REQUEST, CLIENT_CLOSED_LOAD_BALANCED_REQUEST) \ + XX(463, INVALID_X_FORWARDED_FOR, INVALID_X_FORWARDED_FOR) \ + XX(494, REQUEST_HEADER_TOO_LARGE, REQUEST_HEADER_TOO_LARGE) \ + XX(495, SSL_CERTIFICATE_ERROR, SSL_CERTIFICATE_ERROR) \ + XX(496, SSL_CERTIFICATE_REQUIRED, SSL_CERTIFICATE_REQUIRED) \ + XX(497, HTTP_REQUEST_SENT_TO_HTTPS_PORT, HTTP_REQUEST_SENT_TO_HTTPS_PORT) \ + XX(498, INVALID_TOKEN, INVALID_TOKEN) \ + XX(499, CLIENT_CLOSED_REQUEST, CLIENT_CLOSED_REQUEST) \ + XX(500, INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR) \ + XX(501, NOT_IMPLEMENTED, NOT_IMPLEMENTED) \ + XX(502, BAD_GATEWAY, BAD_GATEWAY) \ + XX(503, SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE) \ + XX(504, GATEWAY_TIMEOUT, GATEWAY_TIMEOUT) \ + XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP_VERSION_NOT_SUPPORTED) \ + XX(506, VARIANT_ALSO_NEGOTIATES, VARIANT_ALSO_NEGOTIATES) \ + XX(507, INSUFFICIENT_STORAGE, INSUFFICIENT_STORAGE) \ + XX(508, LOOP_DETECTED, LOOP_DETECTED) \ + XX(509, BANDWIDTH_LIMIT_EXCEEDED, BANDWIDTH_LIMIT_EXCEEDED) \ + XX(510, NOT_EXTENDED, NOT_EXTENDED) \ + XX(511, NETWORK_AUTHENTICATION_REQUIRED, NETWORK_AUTHENTICATION_REQUIRED) \ + XX(520, WEB_SERVER_UNKNOWN_ERROR, WEB_SERVER_UNKNOWN_ERROR) \ + XX(521, WEB_SERVER_IS_DOWN, WEB_SERVER_IS_DOWN) \ + XX(522, CONNECTION_TIMEOUT, CONNECTION_TIMEOUT) \ + XX(523, ORIGIN_IS_UNREACHABLE, ORIGIN_IS_UNREACHABLE) \ + XX(524, TIMEOUT_OCCURED, TIMEOUT_OCCURED) \ + XX(525, SSL_HANDSHAKE_FAILED, SSL_HANDSHAKE_FAILED) \ + XX(526, INVALID_SSL_CERTIFICATE, INVALID_SSL_CERTIFICATE) \ + XX(527, RAILGUN_ERROR, RAILGUN_ERROR) \ + XX(529, SITE_IS_OVERLOADED, SITE_IS_OVERLOADED) \ + XX(530, SITE_IS_FROZEN, SITE_IS_FROZEN) \ + XX(561, IDENTITY_PROVIDER_AUTHENTICATION_ERROR, IDENTITY_PROVIDER_AUTHENTICATION_ERROR) \ + XX(598, NETWORK_READ_TIMEOUT, NETWORK_READ_TIMEOUT) \ + XX(599, NETWORK_CONNECT_TIMEOUT, NETWORK_CONNECT_TIMEOUT) \ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* LLLLHTTP_C_HEADERS_ */ + + +#ifndef INCLUDE_LLHTTP_API_H_ +#define INCLUDE_LLHTTP_API_H_ +#ifdef __cplusplus +extern "C" { +#endif +#include + +#define LLHTTP_EXPORT + +typedef llhttp__internal_t llhttp_t; +typedef struct llhttp_settings_s llhttp_settings_t; + +typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length); +typedef int (*llhttp_cb)(llhttp_t*); + +struct llhttp_settings_s { + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_begin; + + /* Possible return values 0, -1, HPE_USER */ + llhttp_data_cb on_url; + llhttp_data_cb on_status; + llhttp_data_cb on_method; + llhttp_data_cb on_version; + llhttp_data_cb on_header_field; + llhttp_data_cb on_header_value; + llhttp_data_cb on_chunk_extension_name; + llhttp_data_cb on_chunk_extension_value; + + /* Possible return values: + * 0 - Proceed normally + * 1 - Assume that request/response has no body, and proceed to parsing the + * next message + * 2 - Assume absence of body (as above) and make `llhttp_execute()` return + * `HPE_PAUSED_UPGRADE` + * -1 - Error + * `HPE_PAUSED` + */ + llhttp_cb on_headers_complete; + + /* Possible return values 0, -1, HPE_USER */ + llhttp_data_cb on_body; + + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_complete; + llhttp_cb on_url_complete; + llhttp_cb on_status_complete; + llhttp_cb on_method_complete; + llhttp_cb on_version_complete; + llhttp_cb on_header_field_complete; + llhttp_cb on_header_value_complete; + llhttp_cb on_chunk_extension_name_complete; + llhttp_cb on_chunk_extension_value_complete; + + /* When on_chunk_header is called, the current chunk length is stored + * in parser->content_length. + * Possible return values 0, -1, `HPE_PAUSED` + */ + llhttp_cb on_chunk_header; + llhttp_cb on_chunk_complete; + llhttp_cb on_reset; +}; + +/* Initialize the parser with specific type and user settings. + * + * NOTE: lifetime of `settings` has to be at least the same as the lifetime of + * the `parser` here. In practice, `settings` has to be either a static + * variable or be allocated with `malloc`, `new`, etc. + */ +LLHTTP_EXPORT +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings); + +LLHTTP_EXPORT +llhttp_t* llhttp_alloc(llhttp_type_t type); + +LLHTTP_EXPORT +void llhttp_free(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_type(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_http_major(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_http_minor(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_method(llhttp_t* parser); + +LLHTTP_EXPORT +int llhttp_get_status_code(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_upgrade(llhttp_t* parser); + +/* Reset an already initialized parser back to the start state, preserving the + * existing parser type, callback settings, user data, and lenient flags. + */ +LLHTTP_EXPORT +void llhttp_reset(llhttp_t* parser); + +/* Initialize the settings object */ +LLHTTP_EXPORT +void llhttp_settings_init(llhttp_settings_t* settings); + +/* Parse full or partial request/response, invoking user callbacks along the + * way. + * + * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing + * interrupts, and such errno is returned from `llhttp_execute()`. If + * `HPE_PAUSED` was used as a errno, the execution can be resumed with + * `llhttp_resume()` call. + * + * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE` + * is returned after fully parsing the request/response. If the user wishes to + * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`. + * + * NOTE: if this function ever returns a non-pause type error, it will continue + * to return the same error upon each successive call up until `llhttp_init()` + * is called. + */ +LLHTTP_EXPORT +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len); + +/* This method should be called when the other side has no further bytes to + * send (e.g. shutdown of readable side of the TCP connection.) + * + * Requests without `Content-Length` and other messages might require treating + * all incoming bytes as the part of the body, up to the last byte of the + * connection. This method will invoke `on_message_complete()` callback if the + * request was terminated safely. Otherwise a error code would be returned. + */ +LLHTTP_EXPORT +llhttp_errno_t llhttp_finish(llhttp_t* parser); + +/* Returns `1` if the incoming message is parsed until the last byte, and has + * to be completed by calling `llhttp_finish()` on EOF + */ +LLHTTP_EXPORT +int llhttp_message_needs_eof(const llhttp_t* parser); + +/* Returns `1` if there might be any other messages following the last that was + * successfully parsed. + */ +LLHTTP_EXPORT +int llhttp_should_keep_alive(const llhttp_t* parser); + +/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set + * appropriate error reason. + * + * Important: do not call this from user callbacks! User callbacks must return + * `HPE_PAUSED` if pausing is required. + */ +LLHTTP_EXPORT +void llhttp_pause(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED`. + */ +LLHTTP_EXPORT +void llhttp_resume(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE` + */ +LLHTTP_EXPORT +void llhttp_resume_after_upgrade(llhttp_t* parser); + +/* Returns the latest return error */ +LLHTTP_EXPORT +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser); + +/* Returns the verbal explanation of the latest returned error. + * + * Note: User callback should set error reason when returning the error. See + * `llhttp_set_error_reason()` for details. + */ +LLHTTP_EXPORT +const char* llhttp_get_error_reason(const llhttp_t* parser); + +/* Assign verbal description to the returned error. Must be called in user + * callbacks right before returning the errno. + * + * Note: `HPE_USER` error code might be useful in user callbacks. + */ +LLHTTP_EXPORT +void llhttp_set_error_reason(llhttp_t* parser, const char* reason); + +/* Returns the pointer to the last parsed byte before the returned error. The + * pointer is relative to the `data` argument of `llhttp_execute()`. + * + * Note: this method might be useful for counting the number of parsed bytes. + */ +LLHTTP_EXPORT +const char* llhttp_get_error_pos(const llhttp_t* parser); + +/* Returns textual name of error code */ +LLHTTP_EXPORT +const char* llhttp_errno_name(llhttp_errno_t err); + +/* Returns textual name of HTTP method */ +LLHTTP_EXPORT +const char* llhttp_method_name(llhttp_method_t method); + +/* Returns textual name of HTTP status */ +LLHTTP_EXPORT +const char* llhttp_status_name(llhttp_status_t status); + +/* Enables/disables lenient header value parsing (disabled by default). + * + * Lenient parsing disables header value token checks, extending llhttp's + * protocol support to highly non-compliant clients/server. No + * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when + * lenient parsing is "on". + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_headers(llhttp_t* parser, int enabled); + + +/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and + * `Content-Length` headers (disabled by default). + * + * Normally `llhttp` would error when `Transfer-Encoding` is present in + * conjunction with `Content-Length`. This error is important to prevent HTTP + * request smuggling, but may be less desirable for small number of cases + * involving legacy servers. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled); + + +/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0 + * requests responses. + * + * Normally `llhttp` would error on (in strict mode) or discard (in loose mode) + * the HTTP request/response after the request/response with `Connection: close` + * and `Content-Length`. This is important to prevent cache poisoning attacks, + * but might interact badly with outdated and insecure clients. With this flag + * the extra request/response will be parsed normally. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * poisoning attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of `Transfer-Encoding` header. + * + * Normally `llhttp` would error when a `Transfer-Encoding` has `chunked` value + * and another value after it (either in a single header or in multiple + * headers whose value are internally joined using `, `). + * This is mandated by the spec to reliably determine request body size and thus + * avoid request smuggling. + * With this flag the extra value will be parsed normally. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of HTTP version. + * + * Normally `llhttp` would error when the HTTP version in the request or status line + * is not `0.9`, `1.0`, `1.1` or `2.0`. + * With this flag the invalid value will be parsed normally. + * + * **Enabling this flag can pose a security issue since you will allow unsupported + * HTTP versions. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_version(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of additional data received after a message ends + * and keep-alive is disabled. + * + * Normally `llhttp` would error when additional unexpected data is received if the message + * contains the `Connection` header with `close` value. + * With this flag the extra data will discarded without throwing an error. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * poisoning attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of incomplete CRLF sequences. + * + * Normally `llhttp` would error when a CR is not followed by LF when terminating the + * request line, the status line, the headers or a chunk header. + * With this flag only a CR is required to terminate such sections. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled); + +/* + * Enables/disables lenient handling of line separators. + * + * Normally `llhttp` would error when a LF is not preceded by CR when terminating the + * request line, the status line, the headers, a chunk header or a chunk data. + * With this flag only a LF is required to terminate such sections. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of chunks not separated via CRLF. + * + * Normally `llhttp` would error when after a chunk data a CRLF is missing before + * starting a new chunk. + * With this flag the new chunk can start immediately after the previous one. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of spaces after chunk size. + * + * Normally `llhttp` would error when after a chunk size is followed by one or more + * spaces are present instead of a CRLF or `;`. + * With this flag this check is disabled. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_API_H_ */ + + +#endif /* INCLUDE_LLHTTP_H_ */ From d396819101a67c652af0fa0ae65cda19a2c0430a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 Apr 2024 21:07:11 +0100 Subject: [PATCH 501/816] http: abstract http parsing out of httpclient Avoid #ifdef's in httpclient.c, and move http parsing into its own file. --- cmake/SelectHTTPParser.cmake | 53 ++++----- src/libgit2/transports/httpclient.c | 178 +++++++++------------------- src/libgit2/transports/httpparser.c | 126 ++++++++++++++++++++ src/libgit2/transports/httpparser.h | 99 ++++++++++++++++ src/util/git2_features.h.in | 4 + 5 files changed, 305 insertions(+), 155 deletions(-) create mode 100644 src/libgit2/transports/httpparser.c create mode 100644 src/libgit2/transports/httpparser.h diff --git a/cmake/SelectHTTPParser.cmake b/cmake/SelectHTTPParser.cmake index aa6711d9607..111170cb259 100644 --- a/cmake/SelectHTTPParser.cmake +++ b/cmake/SelectHTTPParser.cmake @@ -1,39 +1,32 @@ # Optional external dependency: http-parser -if(USE_HTTP_PARSER STREQUAL "builtin") - message(STATUS "support for bundled (legacy) http-parser explicitly requested") +if(USE_HTTP_PARSER STREQUAL "http-parser") + find_package(HTTPParser) - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") - add_feature_info(http-parser ON "http-parser support (bundled)") -else() - # By default, try to use system LLHTTP. Fall back to - # system http-parser, and even to bundled http-parser - # as a last resort. - find_package(LLHTTP) + if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) + list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES}) + list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") + set(GIT_HTTPPARSER_HTTPPARSER 1) + add_feature_info(http-parser ON "using http-parser (system)") + else() + message(FATAL_ERROR "http-parser support was requested but not found") + endif() +elseif(USE_HTTP_PARSER STREQUAL "llhttp") + find_package(LLHTTP) if(LLHTTP_FOUND AND LLHTTP_VERSION_MAJOR EQUAL 9) - add_compile_definitions(USE_LLHTTP) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${LLHTTP_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${LLHTTP_LIBRARIES}) list(APPEND LIBGIT2_PC_LIBS "-lllhttp") - add_feature_info(llhttp ON "llhttp support (system)") + set(GIT_HTTPPARSER_LLHTTP 1) + add_feature_info(http-parser ON "using llhttp (system)") else() - message(STATUS "llhttp support was requested but not found; checking (legacy) http-parser support") - find_package(HTTPParser) - - if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) - list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS}) - list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES}) - list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") - add_feature_info(http-parser ON "http-parser support (system)") - else() - message(STATUS "neither llhttp nor http-parser support was found; proceeding with bundled (legacy) http-parser") - - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") - add_feature_info(http-parser ON "http-parser support (bundled)") - endif() - endif() + message(FATAL_ERROR "llhttp support was requested but not found") + endif() +else() + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") + set(GIT_HTTPPARSER_BUILTIN 1) + add_feature_info(http-parser ON "using bundled parser") endif() diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index 6e3491ed2b3..9937e9484b1 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -8,31 +8,6 @@ #include "common.h" #include "git2.h" -#ifdef USE_LLHTTP -#include -typedef llhttp_settings_t http_settings_t; -typedef llhttp_t http_parser_t; -GIT_INLINE(http_settings_t *) http_client_parser_settings(void); -#define git_http_parser_init(parser) llhttp_init(parser, HTTP_RESPONSE, http_client_parser_settings()) -#define git_http_parser_pause(parser) llhttp_pause(parser) -#define git_http_parser_resume(parser) llhttp_resume(parser) -#define git_http_parser_errno(parser) parser.error -#define git_http_should_keep_alive(parser) llhttp_should_keep_alive(parser) -#define git_http_errno_description(parser, errno) llhttp_get_error_reason(parser) -#else -#include -/* Legacy http-parser. */ -typedef http_parser_settings http_settings_t; -typedef struct http_parser http_parser_t; -GIT_INLINE(http_settings_t *) http_client_parser_settings(void); -#define git_http_parser_init(parser) http_parser_init(parser, HTTP_RESPONSE) -#define git_http_parser_pause(parser) http_parser_pause(parser, 1) -#define git_http_parser_resume(parser) http_parser_pause(parser, 0) -#define git_http_parser_errno(parser) parser.http_errno -#define git_http_should_keep_alive(parser) http_should_keep_alive(parser) -#define git_http_errno_description(parser, errno) http_errno_description(errno) -#endif /* USE_LLHTTP */ - #include "vector.h" #include "trace.h" #include "httpclient.h" @@ -46,6 +21,7 @@ GIT_INLINE(http_settings_t *) http_client_parser_settings(void); #include "streams/socket.h" #include "streams/tls.h" #include "auth.h" +#include "httpparser.h" static git_http_auth_scheme auth_schemes[] = { { GIT_HTTP_AUTH_NEGOTIATE, "Negotiate", GIT_CREDENTIAL_DEFAULT, git_http_auth_negotiate }, @@ -133,7 +109,7 @@ struct git_http_client { git_http_server_t current_server; http_client_state state; - http_parser_t parser; + git_http_parser parser; git_http_server server; git_http_server proxy; @@ -179,7 +155,7 @@ void git_http_response_dispose(git_http_response *response) memset(response, 0, sizeof(git_http_response)); } -static int on_header_complete(http_parser_t *parser) +static int on_header_complete(git_http_parser *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; git_http_client *client = ctx->client; @@ -244,7 +220,7 @@ static int on_header_complete(http_parser_t *parser) return 0; } -static int on_header_field(http_parser_t *parser, const char *str, size_t len) +static int on_header_field(git_http_parser *parser, const char *str, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -279,7 +255,7 @@ static int on_header_field(http_parser_t *parser, const char *str, size_t len) return 0; } -static int on_header_value(http_parser_t *parser, const char *str, size_t len) +static int on_header_value(git_http_parser *parser, const char *str, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -367,7 +343,7 @@ static int resend_needed(git_http_client *client, git_http_response *response) return 0; } -static int on_headers_complete(http_parser_t *parser) +static int on_headers_complete(git_http_parser *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -389,8 +365,8 @@ static int on_headers_complete(http_parser_t *parser) return ctx->parse_status = PARSE_STATUS_ERROR; } - ctx->response->status = parser->status_code; - ctx->client->keepalive = git_http_should_keep_alive(parser); + ctx->response->status = git_http_parser_status_code(parser); + ctx->client->keepalive = git_http_parser_keep_alive(parser); /* Prepare for authentication */ collect_authinfo(&ctx->response->server_auth_schemetypes, @@ -403,28 +379,15 @@ static int on_headers_complete(http_parser_t *parser) ctx->response->resend_credentials = resend_needed(ctx->client, ctx->response); -#ifndef USE_LLHTTP - /* Stop parsing. llhttp documentation says about llhttp_pause(): - * "Do not call this from user callbacks! User callbacks must - * return HPE_PAUSED if pausing is required", so that's what - * we will do, and call git_http_parser_pause() only for - * http-parser. */ - git_http_parser_pause(parser); -#endif - if (ctx->response->content_type || ctx->response->chunked) ctx->client->state = READING_BODY; else ctx->client->state = DONE; -#ifdef USE_LLHTTP - return HPE_PAUSED; -#else - return 0; -#endif + return git_http_parser_pause(parser); } -static int on_body(http_parser_t *parser, const char *buf, size_t len) +static int on_body(git_http_parser *parser, const char *buf, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; size_t max_len; @@ -446,7 +409,7 @@ static int on_body(http_parser_t *parser, const char *buf, size_t len) return 0; } -static int on_message_complete(http_parser_t *parser) +static int on_message_complete(git_http_parser *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -911,9 +874,29 @@ GIT_INLINE(int) server_setup_from_url( return 0; } +static bool parser_settings_initialized; +static git_http_parser_settings parser_settings; + +GIT_INLINE(git_http_parser_settings *) http_client_parser_settings(void) +{ + if (!parser_settings_initialized) { + parser_settings.on_header_field = on_header_field; + parser_settings.on_header_value = on_header_value; + parser_settings.on_headers_complete = on_headers_complete; + parser_settings.on_body = on_body; + parser_settings.on_message_complete = on_message_complete; + + parser_settings_initialized = true; + } + + return &parser_settings; +} + static void reset_parser(git_http_client *client) { - git_http_parser_init(&client->parser); + git_http_parser_init(&client->parser, + GIT_HTTP_PARSER_RESPONSE, + http_client_parser_settings()); } static int setup_hosts( @@ -1156,64 +1139,9 @@ GIT_INLINE(int) client_read(git_http_client *client) return (int)read_len; } -static bool parser_settings_initialized; -static http_settings_t parser_settings; - -static size_t git_http_parser_execute(http_parser_t *parser, const char* data, size_t len) -{ -#ifdef USE_LLHTTP - llhttp_errno_t error; - size_t parsed_len; - - /* - * Unlike http_parser, which returns the number of parsed - * bytes in the _execute() call, llhttp returns an error - * code. - */ - - if (data == NULL || len == 0) { - error = llhttp_finish(parser); - } else { - error = llhttp_execute(parser, data, len); - } - - parsed_len = len; - /* - * Adjust number of parsed bytes in case of error. - */ - if (error != HPE_OK) { - parsed_len = llhttp_get_error_pos(parser) - data; - - /* This isn't a real pause, just a way to stop parsing early. */ - if (error == HPE_PAUSED_UPGRADE) { - llhttp_resume_after_upgrade(parser); - } - } - - return parsed_len; -#else - return http_parser_execute(parser, http_client_parser_settings(), data, len); -#endif -} - -GIT_INLINE(http_settings_t *) http_client_parser_settings(void) -{ - if (!parser_settings_initialized) { - parser_settings.on_header_field = on_header_field; - parser_settings.on_header_value = on_header_value; - parser_settings.on_headers_complete = on_headers_complete; - parser_settings.on_body = on_body; - parser_settings.on_message_complete = on_message_complete; - - parser_settings_initialized = true; - } - - return &parser_settings; -} - GIT_INLINE(int) client_read_and_parse(git_http_client *client) { - http_parser_t *parser = &client->parser; + git_http_parser *parser = &client->parser; http_parser_context *ctx = (http_parser_context *) parser->data; unsigned char http_errno; int read_len; @@ -1230,7 +1158,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) parsed_len = git_http_parser_execute(parser, client->read_buf.ptr, client->read_buf.size); - http_errno = git_http_parser_errno(client->parser); + http_errno = git_http_parser_errno(parser); if (parsed_len > INT_MAX) { git_error_set(GIT_ERROR_HTTP, "unexpectedly large parse"); @@ -1249,29 +1177,29 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) * (This can happen in response to an expect/continue request, * where the server gives you a 100 and 200 simultaneously.) */ - if (http_errno == HPE_PAUSED) { -#ifndef USE_LLHTTP - /* - * http-parser has a "feature" where it will not deliver the - * final byte when paused in a callback. Consume that byte. - * https://github.com/nodejs/http-parser/issues/97 - */ - GIT_ASSERT(client->read_buf.size > parsed_len); + if (http_errno == GIT_HTTP_PARSER_PAUSED) { + size_t additional_size; -#endif git_http_parser_resume(parser); -#ifndef USE_LLHTTP - parsed_len += git_http_parser_execute(parser, - client->read_buf.ptr + parsed_len, - 1); -#endif + /* + * http-parser has a "feature" where it will not deliver + * the final byte when paused in a callback. Consume + * that byte. + */ + if ((additional_size = git_http_parser_remain_after_pause(parser)) > 0) { + GIT_ASSERT((client->read_buf.size - parsed_len) >= additional_size); + + parsed_len += git_http_parser_execute(parser, + client->read_buf.ptr + parsed_len, + additional_size); + } } /* Most failures will be reported in http_errno */ - else if (git_http_parser_errno(client->parser) != HPE_OK) { + else if (git_http_parser_errno(parser) != GIT_HTTP_PARSER_OK) { git_error_set(GIT_ERROR_HTTP, "http parser error: %s", - git_http_errno_description(parser, http_errno)); + git_http_parser_errmsg(parser, http_errno)); return -1; } @@ -1279,7 +1207,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) else if (parsed_len != client->read_buf.size) { git_error_set(GIT_ERROR_HTTP, "http parser did not consume entire buffer: %s", - git_http_errno_description(parser, http_errno)); + git_http_parser_errmsg(parser, http_errno)); return -1; } @@ -1318,7 +1246,7 @@ static void complete_response_body(git_http_client *client) /* If there was an error, just close the connection. */ if (client_read_and_parse(client) < 0 || - parser_context.error != HPE_OK || + parser_context.error != GIT_HTTP_PARSER_OK || (parser_context.parse_status != PARSE_STATUS_OK && parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) { git_error_clear(); @@ -1596,7 +1524,7 @@ int git_http_client_skip_body(git_http_client *client) do { error = client_read_and_parse(client); - if (parser_context.error != HPE_OK || + if (parser_context.error != GIT_HTTP_PARSER_OK || (parser_context.parse_status != PARSE_STATUS_OK && parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) { git_error_set(GIT_ERROR_HTTP, diff --git a/src/libgit2/transports/httpparser.c b/src/libgit2/transports/httpparser.c new file mode 100644 index 00000000000..abd8f0244c7 --- /dev/null +++ b/src/libgit2/transports/httpparser.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "httpparser.h" + +#include + +#if defined(GIT_HTTPPARSER_HTTPPARSER) || defined(GIT_HTTPPARSER_BUILTIN) + +#include "http_parser.h" + +static int on_message_begin(http_parser *p) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_message_begin(parser); +} + +static int on_url(http_parser *p, const char *str, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_url(parser, str, len); +} + +static int on_header_field(http_parser *p, const char *str, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_header_field(parser, str, len); +} + +static int on_header_value(http_parser *p, const char *str, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_header_value(parser, str, len); +} + +static int on_headers_complete(http_parser *p) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_headers_complete(parser); +} + +static int on_body(http_parser *p, const char *buf, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_body(parser, buf, len); +} + +static int on_message_complete(http_parser *p) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_message_complete(parser); +} + +void git_http_parser_init( + git_http_parser *parser, + git_http_parser_t type, + git_http_parser_settings *settings) +{ + http_parser_init(&parser->parser, (enum http_parser_type)type); + memcpy(&parser->settings, settings, sizeof(git_http_parser_settings)); +} + +size_t git_http_parser_execute( + git_http_parser *parser, + const char *data, + size_t len) +{ + struct http_parser_settings settings_proxy; + + settings_proxy.on_message_begin = parser->settings.on_message_begin ? on_message_begin : NULL; + settings_proxy.on_url = parser->settings.on_url ? on_url : NULL; + settings_proxy.on_header_field = parser->settings.on_header_field ? on_header_field : NULL; + settings_proxy.on_header_value = parser->settings.on_header_value ? on_header_value : NULL; + settings_proxy.on_headers_complete = parser->settings.on_headers_complete ? on_headers_complete : NULL; + settings_proxy.on_body = parser->settings.on_body ? on_body : NULL; + settings_proxy.on_message_complete = parser->settings.on_message_complete ? on_message_complete : NULL; + + return http_parser_execute(&parser->parser, &settings_proxy, data, len); +} + +#elif defined(GIT_HTTPPARSER_LLHTTP) + +# include + +size_t git_http_parser_execute( + git_http_parser *parser, + const char* data, + size_t len) +{ + llhttp_errno_t error; + size_t parsed_len; + + /* + * Unlike http_parser, which returns the number of parsed + * bytes in the _execute() call, llhttp returns an error + * code. + */ + + if (data == NULL || len == 0) + error = llhttp_finish(parser); + else + error = llhttp_execute(parser, data, len); + + parsed_len = len; + + /* + * Adjust number of parsed bytes in case of error. + */ + if (error != HPE_OK) { + parsed_len = llhttp_get_error_pos(parser) - data; + + /* This isn't a real pause, just a way to stop parsing early. */ + if (error == HPE_PAUSED_UPGRADE) + llhttp_resume_after_upgrade(parser); + } + + return parsed_len; +} + +#else +# error unknown http-parser +#endif diff --git a/src/libgit2/transports/httpparser.h b/src/libgit2/transports/httpparser.h new file mode 100644 index 00000000000..616be587edd --- /dev/null +++ b/src/libgit2/transports/httpparser.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_transports_httpparser_h__ +#define INCLUDE_transports_httpparser_h__ + +#include "git2_util.h" + +#if defined(GIT_HTTPPARSER_HTTPPARSER) || defined(GIT_HTTPPARSER_BUILTIN) + +# include + +typedef enum { + GIT_HTTP_PARSER_OK = HPE_OK, + GIT_HTTP_PARSER_PAUSED = HPE_PAUSED, +} git_http_parser_error_t; + +typedef enum { + GIT_HTTP_PARSER_REQUEST = HTTP_REQUEST, + GIT_HTTP_PARSER_RESPONSE = HTTP_RESPONSE, +} git_http_parser_t; + +typedef struct git_http_parser git_http_parser; + +typedef struct { + int (*on_message_begin)(git_http_parser *); + int (*on_url)(git_http_parser *, const char *, size_t); + int (*on_header_field)(git_http_parser *, const char *, size_t); + int (*on_header_value)(git_http_parser *, const char *, size_t); + int (*on_headers_complete)(git_http_parser *); + int (*on_body)(git_http_parser *, const char *, size_t); + int (*on_message_complete)(git_http_parser *); +} git_http_parser_settings; + +struct git_http_parser { + http_parser parser; + git_http_parser_settings settings; + void *data; +}; + +void git_http_parser_init( + git_http_parser *parser, + git_http_parser_t type, + git_http_parser_settings *settings); + +size_t git_http_parser_execute( + git_http_parser *parser, + const char *data, + size_t len); + +# define git_http_parser_status_code(parser) parser->parser.status_code +# define git_http_parser_keep_alive(parser) http_should_keep_alive(&parser->parser) +# define git_http_parser_pause(parser) (http_parser_pause(&parser->parser, 1), 0) +# define git_http_parser_resume(parser) http_parser_pause(&parser->parser, 0) +# define git_http_parser_remain_after_pause(parser) 1 +# define git_http_parser_errno(parser) parser->parser.http_errno +# define git_http_parser_errmsg(parser, errno) http_errno_description(errno) + +#elif defined(GIT_HTTPPARSER_LLHTTP) + +# include + +typedef enum { + GIT_HTTP_PARSER_OK = HPE_OK, + GIT_HTTP_PARSER_PAUSED = HPE_PAUSED, +} git_http_parser_error_t; + +typedef enum { + GIT_HTTP_PARSER_REQUEST = HTTP_REQUEST, + GIT_HTTP_PARSER_RESPONSE = HTTP_RESPONSE, +} git_http_parser_t; + +typedef llhttp_t git_http_parser; +typedef llhttp_settings_t git_http_parser_settings; + +# define git_http_parser_init(parser, direction, settings) llhttp_init(parser, (llhttp_type_t)direction, settings) + +size_t git_http_parser_execute( + git_http_parser *parser, + const char *data, + size_t len); + +# define git_http_parser_status_code(parser) parser->status_code +# define git_http_parser_keep_alive(parser) llhttp_should_keep_alive(parser) +# define git_http_parser_pause(parser) (llhttp_pause(parser), GIT_HTTP_PARSER_PAUSED) +# define git_http_parser_resume(parser) llhttp_resume(parser) +# define git_http_parser_remain_after_pause(parser) 0 +# define git_http_parser_errno(parser) parser->error +# define git_http_parser_errmsg(parser, errno) llhttp_get_error_reason(parser) + +#else +# error unknown http-parser +#endif + +#endif diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index a328f77cb00..52b73284687 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -46,6 +46,10 @@ #cmakedefine GIT_MBEDTLS 1 #cmakedefine GIT_SCHANNEL 1 +#cmakedefine GIT_HTTPPARSER_HTTPPARSER 1 +#cmakedefine GIT_HTTPPARSER_LLHTTP 1 +#cmakedefine GIT_HTTPPARSER_BUILTIN 1 + #cmakedefine GIT_SHA1_COLLISIONDETECT 1 #cmakedefine GIT_SHA1_WIN32 1 #cmakedefine GIT_SHA1_COMMON_CRYPTO 1 From d02b549dab742a1666934e013160fc35985dc4d2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 22 Apr 2024 13:44:55 +0100 Subject: [PATCH 502/816] http: make llhttp the default --- cmake/SelectHTTPParser.cmake | 6 +++--- deps/llhttp/CMakeLists.txt | 6 +++--- src/libgit2/transports/httpparser.c | 4 ++-- src/libgit2/transports/httpparser.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmake/SelectHTTPParser.cmake b/cmake/SelectHTTPParser.cmake index 111170cb259..4fc1f6968e6 100644 --- a/cmake/SelectHTTPParser.cmake +++ b/cmake/SelectHTTPParser.cmake @@ -24,9 +24,9 @@ elseif(USE_HTTP_PARSER STREQUAL "llhttp") message(FATAL_ERROR "llhttp support was requested but not found") endif() else() - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/llhttp" "${PROJECT_BINARY_DIR}/deps/llhttp") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/llhttp") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") set(GIT_HTTPPARSER_BUILTIN 1) add_feature_info(http-parser ON "using bundled parser") endif() diff --git a/deps/llhttp/CMakeLists.txt b/deps/llhttp/CMakeLists.txt index 89daa87c8de..6965335ab27 100644 --- a/deps/llhttp/CMakeLists.txt +++ b/deps/llhttp/CMakeLists.txt @@ -1,7 +1,7 @@ -file(GLOB SRC_HTTP "*.c" "*.h") -list(SORT SRC_HTTP) +file(GLOB SRC_LLHTTP "*.c" "*.h") +list(SORT SRC_LLHTTP) -add_library(llhttp OBJECT ${SRC_HTTP}) +add_library(llhttp OBJECT ${SRC_LLHTTP}) if(NOT MSVC) set_source_files_properties(api.c http.c llhttp.c PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter -Wno-missing-declarations") diff --git a/src/libgit2/transports/httpparser.c b/src/libgit2/transports/httpparser.c index abd8f0244c7..50ba6d2e0cd 100644 --- a/src/libgit2/transports/httpparser.c +++ b/src/libgit2/transports/httpparser.c @@ -9,7 +9,7 @@ #include -#if defined(GIT_HTTPPARSER_HTTPPARSER) || defined(GIT_HTTPPARSER_BUILTIN) +#if defined(GIT_HTTPPARSER_HTTPPARSER) #include "http_parser.h" @@ -82,7 +82,7 @@ size_t git_http_parser_execute( return http_parser_execute(&parser->parser, &settings_proxy, data, len); } -#elif defined(GIT_HTTPPARSER_LLHTTP) +#elif defined(GIT_HTTPPARSER_LLHTTP) || defined(GIT_HTTPPARSER_BUILTIN) # include diff --git a/src/libgit2/transports/httpparser.h b/src/libgit2/transports/httpparser.h index 616be587edd..1fe0dcf6406 100644 --- a/src/libgit2/transports/httpparser.h +++ b/src/libgit2/transports/httpparser.h @@ -10,7 +10,7 @@ #include "git2_util.h" -#if defined(GIT_HTTPPARSER_HTTPPARSER) || defined(GIT_HTTPPARSER_BUILTIN) +#if defined(GIT_HTTPPARSER_HTTPPARSER) # include @@ -60,7 +60,7 @@ size_t git_http_parser_execute( # define git_http_parser_errno(parser) parser->parser.http_errno # define git_http_parser_errmsg(parser, errno) http_errno_description(errno) -#elif defined(GIT_HTTPPARSER_LLHTTP) +#elif defined(GIT_HTTPPARSER_LLHTTP) || defined(GIT_HTTPPARSER_BUILTIN) # include From 98c495539053a2c43e5ac00affa5561870a7745e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 Apr 2024 21:07:25 +0100 Subject: [PATCH 503/816] http: remove legacy bundled http-parser Users can still use the legacy Node.js http-parser library, but now we bundle llhttp and prefer it. --- deps/http-parser/CMakeLists.txt | 6 - deps/http-parser/COPYING | 23 - deps/http-parser/http_parser.c | 2182 ------------------------------- deps/http-parser/http_parser.h | 305 ----- 4 files changed, 2516 deletions(-) delete mode 100644 deps/http-parser/CMakeLists.txt delete mode 100644 deps/http-parser/COPYING delete mode 100644 deps/http-parser/http_parser.c delete mode 100644 deps/http-parser/http_parser.h diff --git a/deps/http-parser/CMakeLists.txt b/deps/http-parser/CMakeLists.txt deleted file mode 100644 index b9da2496f75..00000000000 --- a/deps/http-parser/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -file(GLOB SRC_HTTP "*.c" "*.h") -list(SORT SRC_HTTP) - -add_library(http-parser OBJECT ${SRC_HTTP}) - -enable_warnings(implicit-fallthrough=1) diff --git a/deps/http-parser/COPYING b/deps/http-parser/COPYING deleted file mode 100644 index 58010b38894..00000000000 --- a/deps/http-parser/COPYING +++ /dev/null @@ -1,23 +0,0 @@ -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/deps/http-parser/http_parser.c b/deps/http-parser/http_parser.c deleted file mode 100644 index 1bcd330e5b5..00000000000 --- a/deps/http-parser/http_parser.c +++ /dev/null @@ -1,2182 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "http_parser.h" -#include -#include -#include -#include -#include -#include - -#ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -#ifndef BIT_AT -# define BIT_AT(a, i) \ - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ - (1 << ((unsigned int) (i) & 7)))) -#endif - -#ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -#endif - -#define SET_ERRNO(e) \ -do { \ - parser->http_errno = (e); \ -} while(0) - - -/* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser)) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ -} while (0) - -/* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) - -/* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) - -/* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) { \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ -} while (0) - -/* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) - -/* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) - -/* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ - if (!FOR##_mark) { \ - FOR##_mark = p; \ - } \ -} while (0) - - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" -#define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" - - -static const char *method_strings[] = - { -#define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -static const char tokens[256] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - - -#if HTTP_PARSER_STRICT -# define T(v) 0 -#else -# define T(v) v -#endif - - -static const uint8_t normal_url_char[32] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; - -#undef T - -enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done - }; - - -#define PARSING_HEADER(state) (state <= s_headers_done) - - -enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_keep_alive - , h_matching_connection_close - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - }; - -enum http_host_state - { - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_port_start - , s_http_host_port -}; - -/* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ - (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ - (c) == '$' || (c) == ',') - -#if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -#else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -#endif - - -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - - -#if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ - if (cond) { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state -#endif - - -/* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -static struct { - const char *name; - const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; -#undef HTTP_STRERROR_GEN - -int http_message_needs_eof(const http_parser *parser); - -/* Our URL parser. - * - * This is designed to be shared by http_parser_execute() for URL validation, - * hence it has a state transition + byte-for-byte interface. In addition, it - * is meant to be embedded in http_parser_parse_url(), which does the dirty - * work of turning state transitions URL components for its API. - * - * This function should only be invoked with non-space characters. It is - * assumed that the caller cares about (and can detect) the transition between - * URL and non-URL states by looking for these. - */ -static enum state -parse_url_char(enum state s, const char ch) -{ - if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; - } - -#if HTTP_PARSER_STRICT - if (ch == '\t' || ch == '\f') { - return s_dead; - } -#endif - - switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). - * All methods except CONNECT are followed by '/' or '*'. - */ - - if (ch == '/' || ch == '*') { - return s_req_path; - } - - /* The schema must start with an alpha character. After that, it may - * consist of digits, '+', '-' or '.', followed by a ':'. - */ - if (IS_ALPHA(ch)) { - return s_req_schema; - } - - break; - - case s_req_schema: - if (IS_ALPHANUM(ch) || ch == '+' || ch == '-' || ch == '.') { - return s; - } - - if (ch == ':') { - return s_req_schema_slash; - } - - break; - - case s_req_schema_slash: - if (ch == '/') { - return s_req_schema_slash_slash; - } - - break; - - case s_req_schema_slash_slash: - if (ch == '/') { - return s_req_server_start; - } - - break; - - case s_req_server_with_at: - if (ch == '@') { - return s_dead; - } - - /* FALLTHROUGH */ - case s_req_server_start: - case s_req_server: - if (ch == '/') { - return s_req_path; - } - - if (ch == '?') { - return s_req_query_string_start; - } - - if (ch == '@') { - return s_req_server_with_at; - } - - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_server; - } - - break; - - case s_req_path: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - return s_req_query_string_start; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) { - return s_req_query_string; - } - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) { - return s_req_fragment; - } - - switch (ch) { - case '?': - return s_req_fragment; - - case '#': - return s; - } - - break; - - case s_req_fragment: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - case '#': - return s; - } - - break; - - default: - break; - } - - /* We should never fall out of the switch above unless there's an error */ - return s_dead; -} - -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - - /* We're in an error state. Don't bother doing anything. */ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; - } - - if (len == 0) { - switch (parser->state) { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if - * we got paused. - */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } - } - - - if (parser->state == s_header_field) - header_field_mark = data; - if (parser->state == s_header_value) - header_value_mark = data; - switch (parser->state) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - } - - for (p=data; p != data + len; p++) { - ch = *p; - - if (PARSING_HEADER(parser->state)) { - ++parser->nread; - /* Buffer overflow attack */ - if (parser->nread > HTTP_MAX_HEADER_SIZE) { - SET_ERRNO(HPE_HEADER_OVERFLOW); - goto error; - } - } - - reexecute_byte: - switch (parser->state) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - if (ch == CR || ch == LF) - break; - - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') { - parser->state = s_res_or_resp_H; - - CALLBACK_NOTIFY(message_begin); - } else { - parser->type = HTTP_REQUEST; - parser->state = s_start_req; - goto reexecute_byte; - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - parser->state = s_res_HT; - } else { - if (ch != 'E') { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - parser->state = s_req_method; - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - switch (ch) { - case 'H': - parser->state = s_res_H; - break; - - case CR: - case LF: - break; - - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HT; - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HTT; - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_res_HTTP; - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_res_first_http_major; - break; - - case s_res_first_http_major: - if (ch < '0' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_res_http_major; - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - parser->state = s_res_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_res_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - parser->state = s_res_first_status_code; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) { - if (ch == ' ') { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - parser->state = s_res_status_code; - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) { - switch (ch) { - case ' ': - parser->state = s_res_status; - break; - case CR: - parser->state = s_res_line_almost_done; - break; - case LF: - parser->state = s_header_field_start; - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (parser->status_code > 999) { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status: - /* the human readable status. e.g. "NOT FOUND" - * we are not humans so just ignore this */ - if (ch == CR) { - parser->state = s_res_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - parser->state = s_header_field_start; - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (!IS_ALPHA(ch)) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method) 0; - parser->index = 1; - switch (ch) { - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': parser->method = HTTP_REPORT; break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - parser->state = s_req_method; - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (ch == '\0') { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') { - parser->state = s_req_spaces_before_url; - } else if (ch == matcher[parser->index]) { - ; /* nada */ - } else if (parser->method == HTTP_CONNECT) { - if (parser->index == 1 && ch == 'H') { - parser->method = HTTP_CHECKOUT; - } else if (parser->index == 2 && ch == 'P') { - parser->method = HTTP_COPY; - } else { - goto error; - } - } else if (parser->method == HTTP_MKCOL) { - if (parser->index == 1 && ch == 'O') { - parser->method = HTTP_MOVE; - } else if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_MERGE; - } else if (parser->index == 1 && ch == '-') { - parser->method = HTTP_MSEARCH; - } else if (parser->index == 2 && ch == 'A') { - parser->method = HTTP_MKACTIVITY; - } else { - goto error; - } - } else if (parser->method == HTTP_SUBSCRIBE) { - if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_SEARCH; - } else { - goto error; - } - } else if (parser->index == 1 && parser->method == HTTP_POST) { - if (ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (ch == 'U') { - parser->method = HTTP_PUT; /* or HTTP_PURGE */ - } else if (ch == 'A') { - parser->method = HTTP_PATCH; - } else { - goto error; - } - } else if (parser->index == 2) { - if (parser->method == HTTP_PUT) { - if (ch == 'R') parser->method = HTTP_PURGE; - } else if (parser->method == HTTP_UNLOCK) { - if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE; - } - } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { - parser->method = HTTP_PROPPATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - MARK(url); - if (parser->method == HTTP_CONNECT) { - parser->state = s_req_server_start; - } - - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) { - case ' ': - parser->state = s_req_http_start; - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - parser->state = (ch == CR) ? - s_req_line_almost_done : - s_header_field_start; - CALLBACK_DATA(url); - break; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - parser->state = s_req_http_H; - break; - case ' ': - break; - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HT; - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HTT; - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_req_http_HTTP; - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_req_first_http_major; - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (ch < '1' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_req_http_major; - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - parser->state = s_req_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_req_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - parser->state = s_req_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - - /* XXX allow spaces after digit? */ - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (ch != LF) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - parser->state = s_header_field_start; - break; - } - - case s_header_field_start: - { - if (ch == CR) { - parser->state = s_headers_almost_done; - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - parser->state = s_headers_almost_done; - goto reexecute_byte; - } - - c = TOKEN(ch); - - if (!c) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - parser->state = s_header_field; - - switch (c) { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - c = TOKEN(ch); - - if (c) { - switch (parser->header_state) { - case h_general: - break; - - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - parser->index++; - switch (c) { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - break; - } - - if (ch == ':') { - parser->state = s_header_value_start; - CALLBACK_DATA(header_field); - break; - } - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_field); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_start: - { - if (ch == ' ' || ch == '\t') break; - - MARK(header_value); - - parser->state = s_header_value; - parser->index = 0; - - if (ch == CR) { - parser->header_state = h_general; - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_value); - break; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - parser->header_state = h_matching_transfer_encoding_chunked; - } else { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - parser->header_state = h_matching_connection_close; - } else { - parser->header_state = h_general; - } - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_almost_done; - CALLBACK_DATA_NOADVANCE(header_value); - goto reexecute_byte; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_general: - break; - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - { - uint64_t t; - - if (ch == ' ') break; - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { - parser->header_state = h_transfer_encoding_chunked; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { - parser->header_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CLOSE)-2) { - parser->header_state = h_connection_close; - } - break; - - case h_transfer_encoding_chunked: - case h_connection_keep_alive: - case h_connection_close: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - parser->state = s_header_value; - parser->header_state = h_general; - break; - } - break; - } - - case s_header_almost_done: - { - STRICT_CHECK(ch != LF); - - parser->state = s_header_value_lws; - - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') - parser->state = s_header_value_start; - else - { - parser->state = s_header_field_start; - goto reexecute_byte; - } - break; - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - } - - parser->state = s_headers_done; - - /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT); - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - * - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so - * we have to simulate it by handling a change in errno below. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - SET_ERRNO(HPE_CB_headers_complete); - return p - data; /* Error */ - } - } - - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return p - data; - } - - goto reexecute_byte; - } - - case s_headers_done: - { - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - /* Exit, the rest of the connect is in a different protocol. */ - if (parser->upgrade) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - return (p - data) + 1; - } - - if (parser->flags & F_SKIPBODY) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - parser->state = s_chunk_size_start; - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->content_length != ULLONG_MAX) { - /* Content-Length header given and non-zero */ - parser->state = s_body_identity; - } else { - if (parser->type == HTTP_REQUEST || - !http_message_needs_eof(parser)) { - /* Assume content-length 0 - read the next */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else { - /* Read body until EOF */ - parser->state = s_body_identity_eof; - } - } - } - - break; - } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because - * the latter will automaticaly advance on the next loop iteration. - * Further, if content_length ends up at 0, we want to see the last - * byte again for our message complete callback. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_message_done; - - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. - * - * The alternative to doing this is to wait for the next byte to - * trigger the data callback, just as in every other case. The - * problem with this is that this makes it difficult for the test - * harness to distinguish between complete-on-EOF and - * complete-on-length. It's not clear that this distinction is - * important for applications, but let's keep it for now. - */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - goto reexecute_byte; - } - - break; - } - - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; - - break; - - case s_message_done: - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - - case s_chunk_size_start: - { - assert(parser->nread == 1); - assert(parser->flags & F_CHUNKED); - - unhex_val = unhex[(unsigned char)ch]; - if (unhex_val == -1) { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - parser->content_length = unhex_val; - parser->state = s_chunk_size; - break; - } - - case s_chunk_size: - { - uint64_t t; - - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - - unhex_val = unhex[(unsigned char)ch]; - - if (unhex_val == -1) { - if (ch == ';' || ch == ' ') { - parser->state = s_chunk_parameters; - break; - } - - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - t = parser->content_length; - t *= 16; - t += unhex_val; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this. TODO check for overflow */ - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - parser->state = s_header_field_start; - } else { - parser->state = s_chunk_data; - } - break; - } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* See the explanation in s_body_identity for why the content - * length and data pointers are managed this way. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_chunk_data_almost_done; - } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - parser->state = s_chunk_data_done; - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - parser->state = s_chunk_size_start; - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } - } - - /* Run callbacks for any marks that we have leftover after we ran our of - * bytes. There should be at most one of these set, so it's OK to invoke - * them in series (unset marks will not result in callbacks). - * - * We use the NOADVANCE() variety of callbacks here because 'p' has already - * overflowed 'data' and this allows us to correct for the off-by-one that - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' - * value that's in-bounds). - */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0)) <= 1); - - CALLBACK_DATA_NOADVANCE(header_field); - CALLBACK_DATA_NOADVANCE(header_value); - CALLBACK_DATA_NOADVANCE(url); - CALLBACK_DATA_NOADVANCE(body); - - return len; - -error: - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); - } - - return (p - data); -} - - -/* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ - if (parser->type == HTTP_REQUEST) { - return 0; - } - - /* See RFC 2616 section 4.4 */ - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ - parser->status_code == 204 || /* No Content */ - parser->status_code == 304 || /* Not Modified */ - parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; - } - - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; - } - - return 1; -} - - -int -http_should_keep_alive (const http_parser *parser) -{ - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } - } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { - return 0; - } - } - - return !http_message_needs_eof(parser); -} - - -const char * -http_method_str (enum http_method m) -{ - return ELEM_AT(method_strings, m, ""); -} - - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ - void *data = parser->data; /* preserve application data */ - memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->http_errno = HPE_OK; -} - -const char * -http_errno_name(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].name; -} - -const char * -http_errno_description(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].description; -} - -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') { - return s_http_host_start; - } - - if (IS_USERINFO_CHAR(ch)) { - return s_http_userinfo; - } - break; - - case s_http_host_start: - if (ch == '[') { - return s_http_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - break; - - case s_http_host: - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - /* FALLTHROUGH */ - case s_http_host_v6_end: - if (ch == ':') { - return s_http_host_port_start; - } - - break; - - case s_http_host_v6: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':') { - return s_http_host_v6; - } - - break; - - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) { - return s_http_host_port; - } - - break; - - default: - break; - } - return s_http_host_dead; -} - -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { - enum http_host_state s; - - const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - - if (buflen > UINT16_MAX) - return 1; - - u->field_data[UF_HOST].len = 0; - - s = found_at ? s_http_userinfo_start : s_http_host_start; - - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); - - if (new_s == s_http_host_dead) { - return 1; - } - - switch(new_s) { - case s_http_host: - if (s != s_http_host) { - u->field_data[UF_HOST].off = (uint16_t)(p - buf); - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6: - if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = (uint16_t)(p - buf); - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) { - u->field_data[UF_PORT].off = (uint16_t)(p - buf); - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = (uint16_t)(p - buf); - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; - } - - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; - } - - return 0; -} - -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; - enum http_parser_url_fields uf, old_uf; - int found_at = 0; - - if (buflen > UINT16_MAX) - return 1; - - u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - uf = old_uf = UF_MAX; - - for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); - - /* Figure out the next field that we're operating on */ - switch (s) { - case s_dead: - return 1; - - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; - - case s_req_schema: - uf = UF_SCHEMA; - break; - - case s_req_server_with_at: - found_at = 1; - - /* FALLTROUGH */ - case s_req_server: - uf = UF_HOST; - break; - - case s_req_path: - uf = UF_PATH; - break; - - case s_req_query_string: - uf = UF_QUERY; - break; - - case s_req_fragment: - uf = UF_FRAGMENT; - break; - - default: - assert(!"Unexpected state"); - return 1; - } - - /* Nothing's changed; soldier on */ - if (uf == old_uf) { - u->field_data[uf].len++; - continue; - } - - u->field_data[uf].off = (uint16_t)(p - buf); - u->field_data[uf].len = 1; - - u->field_set |= (1 << uf); - old_uf = uf; - } - - /* host must be present if there is a schema */ - /* parsing http:///toto will fail */ - if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { - if (http_parse_host(buf, u, found_at) != 0) { - return 1; - } - } - - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; - } - - if (u->field_set & (1 << UF_PORT)) { - /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) { - return 1; - } - - u->port = (uint16_t) v; - } - - return 0; -} - -void -http_parser_pause(http_parser *parser, int paused) { - /* Users should only be pausing/unpausing a parser that is not in an error - * state. In non-debug builds, there's not much that we can do about this - * other than ignore it. - */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); - } else { - assert(0 && "Attempting to pause parser in error state"); - } -} - -int -http_body_is_final(const struct http_parser *parser) { - return parser->state == s_message_done; -} diff --git a/deps/http-parser/http_parser.h b/deps/http-parser/http_parser.h deleted file mode 100644 index 67e1d95dd6e..00000000000 --- a/deps/http-parser/http_parser.h +++ /dev/null @@ -1,305 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef http_parser_h -#define http_parser_h -#ifdef __cplusplus -extern "C" { -#endif - -#define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 0 - -#include -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef SIZE_T size_t; -typedef SSIZE_T ssize_t; -#elif defined(__sun) || defined(__sun__) -#include -#else -#include -#endif - -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 -#endif - -/* Maximium header size allowed */ -#define HTTP_MAX_HEADER_SIZE (80*1024) - - -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; - - -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * http_data_cb does not return data chunks. It will be call arbitrarally - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); - - -/* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* webdav */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - /* subversion */ \ - XX(16, REPORT, REPORT) \ - XX(17, MKACTIVITY, MKACTIVITY) \ - XX(18, CHECKOUT, CHECKOUT) \ - XX(19, MERGE, MERGE) \ - /* upnp */ \ - XX(20, MSEARCH, M-SEARCH) \ - XX(21, NOTIFY, NOTIFY) \ - XX(22, SUBSCRIBE, SUBSCRIBE) \ - XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(24, PATCH, PATCH) \ - XX(25, PURGE, PURGE) \ - -enum http_method - { -#define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_TRAILING = 1 << 3 - , F_UPGRADE = 1 << 4 - , F_SKIPBODY = 1 << 5 - }; - - -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") - - -/* Define HPE_* values for each errno value above */ -#define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -}; -#undef HTTP_ERRNO_GEN - - -/* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - -struct http_parser { - /** PRIVATE **/ - unsigned char type : 2; /* enum http_parser_type */ - unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ - unsigned char state; /* enum state from http_parser.c */ - unsigned char header_state; /* enum header_state from http_parser.c */ - unsigned char index; /* index into current matcher */ - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned short status_code; /* responses only */ - unsigned char method; /* requests only */ - unsigned char http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned char upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; - - -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; -}; - - -enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - -/* Result structure for http_parser_parse_url(). - * - * Callers should index into field_data[] with UF_* values iff field_set - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and - * because we probably have padding left over), we convert any port to - * a uint16_t. - */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; -}; - - -void http_parser_init(http_parser *parser, enum http_parser_type type); - - -size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - -/* If http_should_keep_alive() in the on_headers_complete or - * on_message_complete callback returns 0, then this should be - * the last message on the connection. - * If you are the server, respond with the "Connection: close" header. - * If you are the client, close the connection. - */ -int http_should_keep_alive(const http_parser *parser); - -/* Returns a string version of the HTTP method. */ -const char *http_method_str(enum http_method m); - -/* Return a string name of the given error */ -const char *http_errno_name(enum http_errno err); - -/* Return a string description of the given error */ -const char *http_errno_description(enum http_errno err); - -/* Parse a URL; return nonzero on failure */ -int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - -/* Pause or un-pause the parser; a nonzero value pauses */ -void http_parser_pause(http_parser *parser, int paused); - -/* Checks if this is the final chunk of the body. */ -int http_body_is_final(const http_parser *parser); - -#ifdef __cplusplus -} -#endif -#endif From 64808a9a8e9ba6796fd3bdd78db9a148b8586348 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 22 Apr 2024 22:23:32 +0100 Subject: [PATCH 504/816] ci: fixes for fedora Use fedora's valgrind instead of trying to build our own; omit false positive leaks in getaddrinfo; --- ci/docker/fedora | 19 +++++-------------- script/valgrind.supp | 7 +++++++ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ci/docker/fedora b/ci/docker/fedora index d6339bc8512..1db3ceb78a0 100644 --- a/ci/docker/fedora +++ b/ci/docker/fedora @@ -18,10 +18,12 @@ RUN yum install -y \ java-1.8.0-openjdk-headless \ sudo \ python3 \ + valgrind \ krb5-workstation \ krb5-libs \ - krb5-devel \ - pcre2-devel \ + krb5-devel \ + pcre2-devel \ + zlib-devel \ ninja-build \ llhttp-devel @@ -35,18 +37,7 @@ RUN cd /tmp && \ cd .. && \ rm -rf libssh2-1.11.0 -FROM libssh2 AS valgrind -RUN cd /tmp && \ - curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \ - tar -xj && \ - cd valgrind-3.15.0 && \ - ./configure && \ - make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \ - make install && \ - cd .. && \ - rm -rf valgrind-3.15.0 - -FROM valgrind AS adduser +FROM libssh2 AS adduser ARG UID="" ARG GID="" RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ diff --git a/script/valgrind.supp b/script/valgrind.supp index 8c4549f62be..b641386636f 100644 --- a/script/valgrind.supp +++ b/script/valgrind.supp @@ -80,6 +80,13 @@ fun:__check_pf } +{ + ignore-glibc-getaddrinfo-fn + Memcheck:Leak + ... + fun:getaddrinfo +} + { ignore-curl-global-init Memcheck:Leak From 15a8d8763e3088e2fa5c7bd7ba75c02454a16af8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 22 Apr 2024 23:44:32 +0100 Subject: [PATCH 505/816] ci: make fedora a nightly build --- .github/workflows/main.yml | 9 --------- .github/workflows/nightly.yml | 10 +++++++++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aca6b0ee359..accb042e463 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -62,15 +62,6 @@ jobs: CC: clang CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - - name: "Linux (Fedora, GCC, llhttp, SHA-256, OpenSSL, libssh2" - id: fedora-gcc-openssl-llhttp - os: ubuntu-latest - container: - name: fedora - env: - CC: gcc - CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=pcre2 -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_NTLMCLIENT=OFF -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON -DEXPERIMENTAL_SHA256=ON - name: "macOS" id: macos os: macos-12 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 43796859762..57bdd1f778e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -208,7 +208,15 @@ jobs: SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true ARCH: x86 - + - name: "Linux (Fedora, llhttp)" + id: fedora + os: ubuntu-latest + container: + name: fedora + env: + CC: gcc + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=pcre2 -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DUSE_HTTP_PARSER=llhttp - name: "Linux (Bionic, GCC, dynamically-loaded OpenSSL)" container: name: bionic From ffd881eb4a6f378e9bbefb40e72ff0098579be12 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 29 Apr 2024 09:44:30 +0100 Subject: [PATCH 506/816] transport: provide a useful error message during cancellation Since 3618a2a, `git_error_last` does not return NULL when there was no error. Adapt to this when testing for a user cancelling a callback but not setting an error message, testing for `klass` of `GIT_ERROR_NONE`. --- src/libgit2/transports/local.c | 2 +- src/libgit2/transports/ssh_libssh2.c | 4 ++-- src/libgit2/transports/winhttp.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libgit2/transports/local.c b/src/libgit2/transports/local.c index fe59bcab0c1..68ff1c1c12c 100644 --- a/src/libgit2/transports/local.c +++ b/src/libgit2/transports/local.c @@ -458,7 +458,7 @@ static int local_push( default: last = git_error_last(); - if (last && last->message) + if (last->klass != GIT_ERROR_NONE) status->msg = git__strdup(last->message); else status->msg = git__strdup("Unspecified error encountered"); diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index d1b5d40d51f..1993ffe5c3a 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -375,8 +375,8 @@ static int _git_ssh_authenticate_session( return GIT_EAUTH; if (rc != LIBSSH2_ERROR_NONE) { - if (!git_error_last()) - ssh_error(session, "Failed to authenticate SSH session"); + if (git_error_last()->klass == GIT_ERROR_NONE) + ssh_error(session, "failed to authenticate SSH session"); return -1; } diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index 7eca4b7443b..b83ef990de6 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -293,7 +293,7 @@ static int certificate_check(winhttp_stream *s, int valid) /* If there is no override, we should fail if WinHTTP doesn't think it's fine */ if (t->owner->connect_opts.callbacks.certificate_check == NULL && !valid) { - if (!git_error_last()) + if (git_error_last()->klass == GIT_ERROR_NONE) git_error_set(GIT_ERROR_HTTP, "unknown certificate check failure"); return GIT_ECERTIFICATE; @@ -317,7 +317,7 @@ static int certificate_check(winhttp_stream *s, int valid) if (error == GIT_PASSTHROUGH) error = valid ? 0 : GIT_ECERTIFICATE; - if (error < 0 && !git_error_last()) + if (error < 0 && git_error_last()->klass == GIT_ERROR_NONE) git_error_set(GIT_ERROR_HTTP, "user cancelled certificate check"); return error; @@ -961,7 +961,7 @@ static int send_request(winhttp_stream *s, size_t len, bool chunked) (!request_failed && s->status_sending_request_reached)) { git_error_clear(); if ((error = certificate_check(s, cert_valid)) < 0) { - if (!git_error_last()) + if (git_error_last()->klass == GIT_ERROR_NONE) git_error_set(GIT_ERROR_OS, "user cancelled certificate check"); return error; From 2fd37e1bfedf8363d37f12eda726cdc34961e49a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 18 Mar 2024 21:01:29 +0000 Subject: [PATCH 507/816] transport: support sha256 oids --- src/libgit2/transports/smart_protocol.c | 29 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 13f97b7274f..df1c190c30e 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -786,29 +786,43 @@ static int gen_pktline(git_str *buf, git_push *push) push_spec *spec; char *option; size_t i, len; - char old_id[GIT_OID_SHA1_HEXSIZE+1], new_id[GIT_OID_SHA1_HEXSIZE+1]; - - old_id[GIT_OID_SHA1_HEXSIZE] = '\0'; new_id[GIT_OID_SHA1_HEXSIZE] = '\0'; + char old_id[GIT_OID_MAX_HEXSIZE + 1], new_id[GIT_OID_MAX_HEXSIZE + 1]; + size_t old_id_len, new_id_len; git_vector_foreach(&push->specs, i, spec) { - len = 2*GIT_OID_SHA1_HEXSIZE + 7 + strlen(spec->refspec.dst); + len = strlen(spec->refspec.dst) + 7; if (i == 0) { - ++len; /* '\0' */ + /* Need a leading \0 */ + ++len; + if (push->report_status) len += strlen(GIT_CAP_REPORT_STATUS) + 1; + if (git_vector_length(&push->remote_push_options) > 0) len += strlen(GIT_CAP_PUSH_OPTIONS) + 1; + len += strlen(GIT_CAP_SIDE_BAND_64K) + 1; } + old_id_len = git_oid_hexsize(git_oid_type(&spec->roid)); + new_id_len = git_oid_hexsize(git_oid_type(&spec->loid)); + + len += (old_id_len + new_id_len); + git_oid_fmt(old_id, &spec->roid); + old_id[old_id_len] = '\0'; + git_oid_fmt(new_id, &spec->loid); + new_id[new_id_len] = '\0'; - git_str_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->refspec.dst); + git_str_printf(buf, "%04"PRIxZ"%.*s %.*s %s", len, + (int)old_id_len, old_id, (int)new_id_len, new_id, + spec->refspec.dst); if (i == 0) { git_str_putc(buf, '\0'); + /* Core git always starts their capabilities string with a space */ if (push->report_status) { git_str_putc(buf, ' '); @@ -831,6 +845,7 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_printf(buf, "%04"PRIxZ"%s", strlen(option) + 4 , option); } } + git_str_puts(buf, "0000"); return git_str_oom(buf) ? -1 : 0; } @@ -1176,7 +1191,7 @@ int git_smart__push(git_transport *transport, git_push *push) #ifdef PUSH_DEBUG { git_remote_head *head; - char hex[GIT_OID_SHA1_HEXSIZE+1]; hex[GIT_OID_SHA1_HEXSIZE] = '\0'; + char hex[GIT_OID_MAX_HEXSIZE+1], hex[GIT_OID_MAX_HEXSIZE] = '\0'; git_vector_foreach(&push->remote->refs, i, head) { git_oid_fmt(hex, &head->oid); From aa093c4b0754047278dae5e1af752994ecfa87e3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 29 Apr 2024 22:12:25 +0100 Subject: [PATCH 508/816] config: remove `free` ptr from `git_config_entry` This is a leftover leaky abstraction. If consumers aren't meant to _call_ the `free` function then they shouldn't _see_ the free function. Move it out into a `git_config_backend_entry` that is, well, produced by the config backends. This makes our code messier but is an improvement for consumers. --- include/git2/config.h | 6 ---- include/git2/sys/config.h | 14 ++++++-- src/libgit2/config.c | 62 +++++++++++++++++++++++++---------- src/libgit2/config_backend.h | 9 ++++- src/libgit2/config_file.c | 41 ++++++++++++----------- src/libgit2/config_list.c | 44 ++++++++++++------------- src/libgit2/config_list.h | 4 +-- src/libgit2/config_mem.c | 30 ++++++++--------- src/libgit2/config_snapshot.c | 5 ++- 9 files changed, 129 insertions(+), 86 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index 32361431326..9a425aa0b13 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -97,12 +97,6 @@ typedef struct git_config_entry { /** Configuration level for the file this was found in */ git_config_level_t level; - - /** - * Free function for this entry; for internal purposes. Callers - * should call `git_config_entry_free` to free data. - */ - void GIT_CALLBACK(free)(struct git_config_entry *entry); } git_config_entry; /** diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index 75d20758b84..a45d5f80709 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -20,6 +20,16 @@ */ GIT_BEGIN_DECL +typedef struct git_config_backend_entry { + struct git_config_entry entry; + + /** + * Free function for this entry; for internal purposes. Callers + * should call `git_config_entry_free` to free data. + */ + void GIT_CALLBACK(free)(struct git_config_backend_entry *entry); +} git_config_backend_entry; + /** * Every iterator must have this struct as its first element, so the * API can talk to it. You'd define your iterator as @@ -39,7 +49,7 @@ struct git_config_iterator { * Return the current entry and advance the iterator. The * memory belongs to the library. */ - int GIT_CALLBACK(next)(git_config_entry **entry, git_config_iterator *iter); + int GIT_CALLBACK(next)(git_config_backend_entry **entry, git_config_iterator *iter); /** * Free the iterator @@ -59,7 +69,7 @@ struct git_config_backend { /* Open means open the file/database and parse if necessary */ int GIT_CALLBACK(open)(struct git_config_backend *, git_config_level_t level, const git_repository *repo); - int GIT_CALLBACK(get)(struct git_config_backend *, const char *key, git_config_entry **entry); + int GIT_CALLBACK(get)(struct git_config_backend *, const char *key, git_config_backend_entry **entry); int GIT_CALLBACK(set)(struct git_config_backend *, const char *key, const char *value); int GIT_CALLBACK(set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); int GIT_CALLBACK(del)(struct git_config_backend *, const char *key); diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 1e4e17597d6..597928caec9 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -50,10 +50,13 @@ typedef struct { void git_config_entry_free(git_config_entry *entry) { + git_config_backend_entry *be; + if (!entry) return; - entry->free(entry); + be = (git_config_backend_entry *)entry; + be->free(be); } static void backend_instance_free(backend_instance *instance) @@ -430,15 +433,19 @@ typedef struct { size_t i; } all_iter; -static int all_iter_next(git_config_entry **out, git_config_iterator *_iter) +static int all_iter_next( + git_config_backend_entry **out, + git_config_iterator *_iter) { all_iter *iter = (all_iter *) _iter; backend_entry *entry; git_config_backend *backend; + git_config_backend_entry *be; int error = 0; if (iter->current != NULL && - (error = iter->current->next(out, iter->current)) == 0) { + (error = iter->current->next(&be, iter->current)) == 0) { + *out = be; return 0; } @@ -460,13 +467,18 @@ static int all_iter_next(git_config_entry **out, git_config_iterator *_iter) iter->current = NULL; error = backend->iterator(&iter->current, backend); + if (error == GIT_ENOTFOUND) continue; if (error < 0) return error; - error = iter->current->next(out, iter->current); + if ((error = iter->current->next(&be, iter->current)) == 0) { + *out = be; + return 0; + } + /* If this backend is empty, then keep going */ if (error == GIT_ITEROVER) continue; @@ -478,7 +490,9 @@ static int all_iter_next(git_config_entry **out, git_config_iterator *_iter) return GIT_ITEROVER; } -static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_iter) +static int all_iter_glob_next( + git_config_backend_entry **entry, + git_config_iterator *_iter) { int error; all_iter *iter = (all_iter *) _iter; @@ -489,7 +503,7 @@ static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_it */ while ((error = all_iter_next(entry, _iter)) == 0) { /* skip non-matching keys if regexp was provided */ - if (git_regexp_match(&iter->regex, (*entry)->name) != 0) + if (git_regexp_match(&iter->regex, (*entry)->entry.name) != 0) continue; /* and simply return if we like the entry's name */ @@ -573,7 +587,7 @@ int git_config_backend_foreach_match( git_config_foreach_cb cb, void *payload) { - git_config_entry *entry; + git_config_backend_entry *entry; git_config_iterator *iter; git_regexp regex; int error = 0; @@ -591,11 +605,11 @@ int git_config_backend_foreach_match( while (!(iter->next(&entry, iter) < 0)) { /* skip non-matching keys if regexp was provided */ - if (regexp && git_regexp_match(®ex, entry->name) != 0) + if (regexp && git_regexp_match(®ex, entry->entry.name) != 0) continue; /* abort iterator on non-zero return value */ - if ((error = cb(entry, payload)) != 0) { + if ((error = cb(&entry->entry, payload)) != 0) { git_error_set_after_callback(error); break; } @@ -772,6 +786,7 @@ static int get_entry( { backend_entry *entry; git_config_backend *backend; + git_config_backend_entry *be; int res = GIT_ENOTFOUND; const char *key = name; char *normalized = NULL; @@ -790,10 +805,12 @@ static int get_entry( GIT_ASSERT(entry->instance && entry->instance->backend); backend = entry->instance->backend; - res = backend->get(backend, key, out); + res = backend->get(backend, key, &be); - if (res != GIT_ENOTFOUND) + if (res != GIT_ENOTFOUND) { + *out = &be->entry; break; + } } git__free(normalized); @@ -1043,16 +1060,16 @@ int git_config_get_multivar_foreach( { int err, found; git_config_iterator *iter; - git_config_entry *entry; + git_config_backend_entry *be; if ((err = git_config_multivar_iterator_new(&iter, config, name, regexp)) < 0) return err; found = 0; - while ((err = iter->next(&entry, iter)) == 0) { + while ((err = iter->next(&be, iter)) == 0) { found = 1; - if ((err = cb(entry, payload)) != 0) { + if ((err = cb(&be->entry, payload)) != 0) { git_error_set_after_callback(err); break; } @@ -1076,19 +1093,21 @@ typedef struct { int have_regex; } multivar_iter; -static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter) +static int multivar_iter_next( + git_config_backend_entry **entry, + git_config_iterator *_iter) { multivar_iter *iter = (multivar_iter *) _iter; int error = 0; while ((error = iter->iter->next(entry, iter->iter)) == 0) { - if (git__strcmp(iter->name, (*entry)->name)) + if (git__strcmp(iter->name, (*entry)->entry.name)) continue; if (!iter->have_regex) return 0; - if (git_regexp_match(&iter->regex, (*entry)->value) == 0) + if (git_regexp_match(&iter->regex, (*entry)->entry.value) == 0) return 0; } @@ -1168,7 +1187,14 @@ int git_config_delete_multivar(git_config *config, const char *name, const char int git_config_next(git_config_entry **entry, git_config_iterator *iter) { - return iter->next(entry, iter); + git_config_backend_entry *be; + int error; + + if ((error = iter->next(&be, iter)) != 0) + return error; + + *entry = &be->entry; + return 0; } void git_config_iterator_free(git_config_iterator *iter) diff --git a/src/libgit2/config_backend.h b/src/libgit2/config_backend.h index 37d25abe146..786c5de1a75 100644 --- a/src/libgit2/config_backend.h +++ b/src/libgit2/config_backend.h @@ -51,7 +51,14 @@ GIT_INLINE(void) git_config_backend_free(git_config_backend *cfg) GIT_INLINE(int) git_config_backend_get_string( git_config_entry **out, git_config_backend *cfg, const char *name) { - return cfg->get(cfg, name, out); + git_config_backend_entry *be; + int error; + + if ((error = cfg->get(cfg, name, &be)) < 0) + return error; + + *out = &be->entry; + return 0; } GIT_INLINE(int) git_config_backend_set_string( diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 340e85691ed..510f6fd0b77 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -310,8 +310,8 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char if (error != GIT_ENOTFOUND) goto out; error = 0; - } else if ((!existing->base.value && !value) || - (existing->base.value && value && !strcmp(existing->base.value, value))) { + } else if ((!existing->base.entry.value && !value) || + (existing->base.entry.value && value && !strcmp(existing->base.entry.value, value))) { /* don't update if old and new values already match */ error = 0; goto out; @@ -336,7 +336,10 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char /* * Internal function that actually gets the value in string form */ -static int config_file_get(git_config_backend *cfg, const char *key, git_config_entry **out) +static int config_file_get( + git_config_backend *cfg, + const char *key, + git_config_backend_entry **out) { config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent); git_config_list *config_list = NULL; @@ -407,7 +410,7 @@ static int config_file_delete(git_config_backend *cfg, const char *name) goto out; } - if ((error = config_file_write(b, name, entry->base.name, NULL, NULL)) < 0) + if ((error = config_file_write(b, name, entry->base.entry.name, NULL, NULL)) < 0) goto out; out: @@ -795,22 +798,22 @@ static int read_on_variable( entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->base.name = git_str_detach(&buf); - GIT_ERROR_CHECK_ALLOC(entry->base.name); + entry->base.entry.name = git_str_detach(&buf); + GIT_ERROR_CHECK_ALLOC(entry->base.entry.name); if (var_value) { - entry->base.value = git__strdup(var_value); - GIT_ERROR_CHECK_ALLOC(entry->base.value); + entry->base.entry.value = git__strdup(var_value); + GIT_ERROR_CHECK_ALLOC(entry->base.entry.value); } - entry->base.backend_type = git_config_list_add_string(parse_data->config_list, CONFIG_FILE_TYPE); - GIT_ERROR_CHECK_ALLOC(entry->base.backend_type); + entry->base.entry.backend_type = git_config_list_add_string(parse_data->config_list, CONFIG_FILE_TYPE); + GIT_ERROR_CHECK_ALLOC(entry->base.entry.backend_type); - entry->base.origin_path = git_config_list_add_string(parse_data->config_list, parse_data->file->path); - GIT_ERROR_CHECK_ALLOC(entry->base.origin_path); + entry->base.entry.origin_path = git_config_list_add_string(parse_data->config_list, parse_data->file->path); + GIT_ERROR_CHECK_ALLOC(entry->base.entry.origin_path); - entry->base.level = parse_data->level; - entry->base.include_depth = parse_data->depth; + entry->base.entry.level = parse_data->level; + entry->base.entry.include_depth = parse_data->depth; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; @@ -820,11 +823,11 @@ static int read_on_variable( result = 0; /* Add or append the new config option */ - if (!git__strcmp(entry->base.name, "include.path")) - result = parse_include(parse_data, entry->base.value); - else if (!git__prefixcmp(entry->base.name, "includeif.") && - !git__suffixcmp(entry->base.name, ".path")) - result = parse_conditional_include(parse_data, entry->base.name, entry->base.value); + if (!git__strcmp(entry->base.entry.name, "include.path")) + result = parse_include(parse_data, entry->base.entry.value); + else if (!git__prefixcmp(entry->base.entry.name, "includeif.") && + !git__suffixcmp(entry->base.entry.name, ".path")) + result = parse_conditional_include(parse_data, entry->base.entry.name, entry->base.entry.value); return result; } diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index 0b7a4f3600a..c6042149c78 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -64,24 +64,24 @@ int git_config_list_dup_entry(git_config_list *config_list, const git_config_ent duplicated = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(duplicated); - duplicated->base.name = git__strdup(entry->name); - GIT_ERROR_CHECK_ALLOC(duplicated->base.name); + duplicated->base.entry.name = git__strdup(entry->name); + GIT_ERROR_CHECK_ALLOC(duplicated->base.entry.name); if (entry->value) { - duplicated->base.value = git__strdup(entry->value); - GIT_ERROR_CHECK_ALLOC(duplicated->base.value); + duplicated->base.entry.value = git__strdup(entry->value); + GIT_ERROR_CHECK_ALLOC(duplicated->base.entry.value); } - duplicated->base.backend_type = git_config_list_add_string(config_list, entry->backend_type); - GIT_ERROR_CHECK_ALLOC(duplicated->base.backend_type); + duplicated->base.entry.backend_type = git_config_list_add_string(config_list, entry->backend_type); + GIT_ERROR_CHECK_ALLOC(duplicated->base.entry.backend_type); if (entry->origin_path) { - duplicated->base.origin_path = git_config_list_add_string(config_list, entry->origin_path); - GIT_ERROR_CHECK_ALLOC(duplicated->base.origin_path); + duplicated->base.entry.origin_path = git_config_list_add_string(config_list, entry->origin_path); + GIT_ERROR_CHECK_ALLOC(duplicated->base.entry.origin_path); } - duplicated->base.level = entry->level; - duplicated->base.include_depth = entry->include_depth; + duplicated->base.entry.level = entry->level; + duplicated->base.entry.include_depth = entry->include_depth; duplicated->base.free = git_config_list_entry_free; duplicated->config_list = config_list; @@ -90,8 +90,8 @@ int git_config_list_dup_entry(git_config_list *config_list, const git_config_ent out: if (error && duplicated) { - git__free((char *) duplicated->base.name); - git__free((char *) duplicated->base.value); + git__free((char *) duplicated->base.entry.name); + git__free((char *) duplicated->base.entry.value); git__free(duplicated); } return error; @@ -107,7 +107,7 @@ int git_config_list_dup(git_config_list **out, git_config_list *config_list) goto out; for (head = config_list->entries; head; head = head->next) - if ((git_config_list_dup_entry(result, &head->entry->base)) < 0) + if ((git_config_list_dup_entry(result, &head->entry->base.entry)) < 0) goto out; *out = result; @@ -135,7 +135,7 @@ static void config_list_free(git_config_list *config_list) git_strmap_free(config_list->strings); git_strmap_foreach_value(config_list->map, head, { - git__free((char *) head->entry->base.name); + git__free((char *) head->entry->base.entry.name); git__free(head); }); git_strmap_free(config_list->map); @@ -143,7 +143,7 @@ static void config_list_free(git_config_list *config_list) entry_list = config_list->entries; while (entry_list != NULL) { next = entry_list->next; - git__free((char *) entry_list->entry->base.value); + git__free((char *) entry_list->entry->base.entry.value); git__free(entry_list->entry); git__free(entry_list); entry_list = next; @@ -163,7 +163,7 @@ int git_config_list_append(git_config_list *config_list, git_config_list_entry * config_entry_list *list_head; config_entry_map_head *map_head; - if ((map_head = git_strmap_get(config_list->map, entry->base.name)) != NULL) { + if ((map_head = git_strmap_get(config_list->map, entry->base.entry.name)) != NULL) { map_head->multivar = true; /* * This is a micro-optimization for configuration files @@ -171,11 +171,11 @@ int git_config_list_append(git_config_list *config_list, git_config_list_entry * * key will be the same for all list, we can just free * all except the first entry's name and just re-use it. */ - git__free((char *) entry->base.name); - entry->base.name = map_head->entry->base.name; + git__free((char *) entry->base.entry.name); + entry->base.entry.name = map_head->entry->base.entry.name; } else { map_head = git__calloc(1, sizeof(*map_head)); - if ((git_strmap_set(config_list->map, entry->base.name, map_head)) < 0) + if ((git_strmap_set(config_list->map, entry->base.entry.name, map_head)) < 0) return -1; } map_head->entry = entry; @@ -216,7 +216,7 @@ int git_config_list_get_unique(git_config_list_entry **out, git_config_list *con return -1; } - if (entry->entry->base.include_depth) { + if (entry->entry->base.entry.include_depth) { git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included"); return -1; } @@ -233,7 +233,7 @@ static void config_iterator_free(git_config_iterator *iter) } static int config_iterator_next( - git_config_entry **entry, + git_config_backend_entry **entry, git_config_iterator *iter) { config_list_iterator *it = (config_list_iterator *) iter; @@ -265,7 +265,7 @@ int git_config_list_iterator_new(git_config_iterator **out, git_config_list *con } /* release the map containing the entry as an equivalent to freeing it */ -void git_config_list_entry_free(git_config_entry *e) +void git_config_list_entry_free(git_config_backend_entry *e) { git_config_list_entry *entry = (git_config_list_entry *)e; git_config_list_free(entry->config_list); diff --git a/src/libgit2/config_list.h b/src/libgit2/config_list.h index 023bca1e5ca..091a59b9079 100644 --- a/src/libgit2/config_list.h +++ b/src/libgit2/config_list.h @@ -13,7 +13,7 @@ typedef struct git_config_list git_config_list; typedef struct { - git_config_entry base; + git_config_backend_entry base; git_config_list *config_list; } git_config_list_entry; @@ -29,4 +29,4 @@ int git_config_list_get_unique(git_config_list_entry **out, git_config_list *lis int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); const char *git_config_list_add_string(git_config_list *list, const char *str); -void git_config_list_entry_free(git_config_entry *entry); +void git_config_list_entry_free(git_config_backend_entry *entry); diff --git a/src/libgit2/config_mem.c b/src/libgit2/config_mem.c index 406aa83e6e1..3c159073f2d 100644 --- a/src/libgit2/config_mem.c +++ b/src/libgit2/config_mem.c @@ -77,12 +77,12 @@ static int read_variable_cb( entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->base.name = git_str_detach(&buf); - entry->base.value = var_value ? git__strdup(var_value) : NULL; - entry->base.level = parse_data->level; - entry->base.include_depth = 0; - entry->base.backend_type = parse_data->backend_type; - entry->base.origin_path = parse_data->origin_path; + entry->base.entry.name = git_str_detach(&buf); + entry->base.entry.value = var_value ? git__strdup(var_value) : NULL; + entry->base.entry.level = parse_data->level; + entry->base.entry.include_depth = 0; + entry->base.entry.backend_type = parse_data->backend_type; + entry->base.entry.origin_path = parse_data->origin_path; entry->base.free = git_config_list_entry_free; entry->config_list = parse_data->config_list; @@ -151,18 +151,18 @@ static int parse_values( entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->base.name = git__strndup(memory_backend->values[i], name_len); - GIT_ERROR_CHECK_ALLOC(entry->base.name); + entry->base.entry.name = git__strndup(memory_backend->values[i], name_len); + GIT_ERROR_CHECK_ALLOC(entry->base.entry.name); if (eql) { - entry->base.value = git__strdup(eql + 1); - GIT_ERROR_CHECK_ALLOC(entry->base.value); + entry->base.entry.value = git__strdup(eql + 1); + GIT_ERROR_CHECK_ALLOC(entry->base.entry.value); } - entry->base.level = level; - entry->base.include_depth = 0; - entry->base.backend_type = backend_type; - entry->base.origin_path = origin_path; + entry->base.entry.level = level; + entry->base.entry.include_depth = 0; + entry->base.entry.backend_type = backend_type; + entry->base.entry.origin_path = origin_path; entry->base.free = git_config_list_entry_free; entry->config_list = memory_backend->config_list; @@ -190,7 +190,7 @@ static int config_memory_open(git_config_backend *backend, git_config_level_t le return 0; } -static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) +static int config_memory_get(git_config_backend *backend, const char *key, git_config_backend_entry **out) { config_memory_backend *memory_backend = (config_memory_backend *) backend; git_config_list_entry *entry; diff --git a/src/libgit2/config_snapshot.c b/src/libgit2/config_snapshot.c index d8b8733a9fb..d20984f512d 100644 --- a/src/libgit2/config_snapshot.c +++ b/src/libgit2/config_snapshot.c @@ -41,7 +41,10 @@ static int config_snapshot_iterator( return error; } -static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out) +static int config_snapshot_get( + git_config_backend *cfg, + const char *key, + git_config_backend_entry **out) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); git_config_list *config_list = NULL; From 2d649ccd234914a7173142caed3434d6a73ddfe8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 6 May 2024 15:46:21 +0100 Subject: [PATCH 509/816] remote: drop bitfields in git_remote_fetch_options In attempting to make a clever change that added fetch options as flags, while keeping ABI and API compatibility, we screwed up. Bitfields in structs are implementation-specific and are not necessarily ABI compatible across compilers. Make `update_fetchhead` a flags value which is weirdly named, but that's a future problem. This removes the `report_unchanged` option from API. --- include/git2/remote.h | 6 ++---- src/libgit2/remote.c | 7 +------ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 7067c88b0b1..5505f6c358d 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -746,8 +746,7 @@ typedef struct { /** * How to handle reference updates; see `git_remote_update_flags`. */ - unsigned int update_fetchhead : 1, - report_unchanged : 1; + unsigned int update_fetchhead; /** * Determines how to behave regarding tags on the remote, such @@ -790,8 +789,7 @@ typedef struct { GIT_FETCH_OPTIONS_VERSION, \ GIT_REMOTE_CALLBACKS_INIT, \ GIT_FETCH_PRUNE_UNSPECIFIED, \ - 1, \ - 0, \ + GIT_REMOTE_UPDATE_FETCHHEAD, \ GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, \ GIT_PROXY_OPTIONS_INIT } diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 8b07c83184a..8b486ea3550 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1376,12 +1376,7 @@ int git_remote_fetch( return error; if (opts) { - if (opts->update_fetchhead) - update_flags |= GIT_REMOTE_UPDATE_FETCHHEAD; - - if (opts->report_unchanged) - update_flags |= GIT_REMOTE_UPDATE_REPORT_UNCHANGED; - + update_flags = opts->update_fetchhead; tagopt = opts->download_tags; } From 322ea80231832fcb441ecfdcbbbf706e4acc3fc5 Mon Sep 17 00:00:00 2001 From: qaqland Date: Wed, 8 May 2024 11:08:26 +0800 Subject: [PATCH 510/816] examples: fix memory leak in for-each-ref.c --- examples/for-each-ref.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/for-each-ref.c b/examples/for-each-ref.c index a0706741a3f..f745bc38cb9 100644 --- a/examples/for-each-ref.c +++ b/examples/for-each-ref.c @@ -25,6 +25,8 @@ static int show_ref(git_reference *ref, void *data) git_object_type2string(git_object_type(obj)), git_reference_name(ref)); + git_object_free(obj); + git_reference_free(ref); if (resolved) git_reference_free(resolved); return 0; From 60f219e80be22a733fb4321e5aed189fde984dbe Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Wed, 8 May 2024 17:05:19 +0200 Subject: [PATCH 511/816] Revparse: Correctly accept ref with '@' at the end Signed-off-by: Sven Strickroth --- src/libgit2/revparse.c | 8 +------- tests/libgit2/refs/revparse.c | 31 +++++++++++++++++++------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/libgit2/revparse.c b/src/libgit2/revparse.c index 08237628793..9083e7a3cdc 100644 --- a/src/libgit2/revparse.c +++ b/src/libgit2/revparse.c @@ -816,13 +816,7 @@ static int revparse( if (temp_object != NULL) base_rev = temp_object; break; - } else if (spec[pos+1] == '\0') { - if (pos) { - git_error_set(GIT_ERROR_REFERENCE, "invalid revspec"); - error = GIT_EINVALIDSPEC; - goto cleanup; - } - + } else if (spec[pos + 1] == '\0' && !pos) { spec = "HEAD"; identifier_len = 4; parsed = true; diff --git a/tests/libgit2/refs/revparse.c b/tests/libgit2/refs/revparse.c index 3fe07811796..9bc3bd10e4c 100644 --- a/tests/libgit2/refs/revparse.c +++ b/tests/libgit2/refs/revparse.c @@ -747,6 +747,25 @@ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void) cl_git_sandbox_cleanup(); } +void test_refs_revparse__at_at_end_of_refname(void) +{ + git_repository *repo; + git_reference *branch; + git_object *target; + + repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_revparse_single(&target, repo, "HEAD")); + cl_git_pass(git_branch_create(&branch, repo, "master@", (git_commit *)target, 0)); + git_object_free(target); + + test_id_inrepo("master@", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVSPEC_SINGLE, repo); + + cl_git_fail_with(GIT_ENOTFOUND, git_revparse_single(&target, repo, "foo@")); + + git_reference_free(branch); + cl_git_sandbox_cleanup(); +} void test_refs_revparse__range(void) { @@ -889,15 +908,3 @@ void test_refs_revparse__parses_at_head(void) test_id("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVSPEC_SINGLE); test_id("@", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVSPEC_SINGLE); } - -void test_refs_revparse__rejects_bogus_at(void) -{ - git_repository *repo; - git_object *target; - - repo = cl_git_sandbox_init("testrepo.git"); - - cl_git_fail_with(GIT_EINVALIDSPEC, git_revparse_single(&target, repo, "foo@")); - - cl_git_sandbox_cleanup(); -} From b1d6fd0858aad5db7bb33d56fb8f76fd3fb6722a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 13 May 2024 10:21:24 +0100 Subject: [PATCH 512/816] cli: include alloca on illumos / solaris / sunos --- src/cli/opt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cli/opt.c b/src/cli/opt.c index 2b08dc219a3..9242e2203b4 100644 --- a/src/cli/opt.c +++ b/src/cli/opt.c @@ -19,6 +19,10 @@ #include #include +#if defined(__sun) || defined(__illumos__) +# include +#endif + #include "common.h" #include "opt.h" From 99ba44608f216d6c59eb9131907114883c7059a9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 13 May 2024 10:21:58 +0100 Subject: [PATCH 513/816] tree: avoid mixed signedness comparison Promote mode to `uint32_t` before comparing it to an `uint16_t` to avoid mixed signed comparison warnings. --- src/libgit2/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/tree.c b/src/libgit2/tree.c index 236a87f7e3e..18278d34e77 100644 --- a/src/libgit2/tree.c +++ b/src/libgit2/tree.c @@ -381,7 +381,7 @@ static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, if ((error = git__strntol32(&mode, buffer, buffer_len, buffer_out, 8)) < 0) return error; - if (mode < 0 || mode > UINT16_MAX) + if (mode < 0 || (uint32_t)mode > UINT16_MAX) return -1; *mode_out = mode; From 2fb07fd0e18d8e589e8b9ca9c7f8140b173b5d27 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 13 May 2024 10:24:21 +0100 Subject: [PATCH 514/816] rand: avoid uninitialized loadavg warnings --- src/util/rand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/util/rand.c b/src/util/rand.c index a02853519b2..2b137a57b56 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -76,10 +76,10 @@ GIT_INLINE(int) getseed(uint64_t *seed) GIT_INLINE(int) getseed(uint64_t *seed) { struct timeval tv; - double loadavg[3]; int fd; # if defined(GIT_RAND_GETLOADAVG) + double loadavg[3]; bits convert; # endif @@ -125,8 +125,6 @@ GIT_INLINE(int) getseed(uint64_t *seed) convert.f = loadavg[0]; *seed ^= (convert.d >> 36); convert.f = loadavg[1]; *seed ^= (convert.d); convert.f = loadavg[2]; *seed ^= (convert.d >> 16); -# else - GIT_UNUSED(loadavg[0]); # endif *seed ^= git_time_monotonic(); From bb3c31f3274f1ec046c6a798c3c10d1043dfe517 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 Apr 2024 20:47:11 +0100 Subject: [PATCH 515/816] xdiff: use proper free function --- deps/xdiff/xmerge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/xdiff/xmerge.c b/deps/xdiff/xmerge.c index af40c88a5b3..6ebf73a933a 100644 --- a/deps/xdiff/xmerge.c +++ b/deps/xdiff/xmerge.c @@ -88,7 +88,7 @@ static int xdl_cleanup_merge(xdmerge_t *c) if (c->mode == 0) count++; next_c = c->next; - free(c); + xdl_free(c); } return count; } @@ -456,7 +456,7 @@ static void xdl_merge_two_conflicts(xdmerge_t *m) m->chg1 = next_m->i1 + next_m->chg1 - m->i1; m->chg2 = next_m->i2 + next_m->chg2 - m->i2; m->next = next_m->next; - free(next_m); + xdl_free(next_m); } /* From 54218b5506a45217403f6cdfb85fce861b62606d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 29 Apr 2024 19:16:29 +0100 Subject: [PATCH 516/816] array: treat `git_array` ptrs as `void *` Avoid sloppy aliasing in our (re-)allocation, which is undefined behavior. This has been problematic before and was helped by `volatile` (see b62a6a13b2f9a40e6ea4bf7bc2a9255429fb0bd6) but that is not technically correct, and some compilers / architectures do not understand that `ptr` is changing due to its aliasing. Just make `git_array_alloc` behave like `realloc`, taking a `void *` and returning a `void *`. --- src/util/array.h | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/util/array.h b/src/util/array.h index 633d598ee26..515e6e3ab46 100644 --- a/src/util/array.h +++ b/src/util/array.h @@ -41,39 +41,40 @@ #define GIT_ERROR_CHECK_ARRAY(a) GIT_ERROR_CHECK_ALLOC((a).ptr) - -typedef git_array_t(char) git_array_generic_t; - -/* use a generic array for growth, return 0 on success */ -GIT_INLINE(int) git_array_grow(void *_a, size_t item_size) +GIT_INLINE(void *) git_array__alloc(void *arr, size_t *size, size_t *asize, size_t item_size) { - volatile git_array_generic_t *a = _a; size_t new_size; - char *new_array; + void *new_array; + + if (*size < *asize) + return arr; - if (a->size < 8) { + if (*size < 8) { new_size = 8; } else { - if (GIT_MULTIPLY_SIZET_OVERFLOW(&new_size, a->size, 3)) + if (GIT_MULTIPLY_SIZET_OVERFLOW(&new_size, *asize, 3)) goto on_oom; + new_size /= 2; } - if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL) + if ((new_array = git__reallocarray(arr, new_size, item_size)) == NULL) goto on_oom; - a->ptr = new_array; - a->asize = new_size; - return 0; + *asize = new_size; + + return new_array; on_oom: - git_array_clear(*a); - return -1; + git__free(arr); + *size = 0; + *asize = 0; + return NULL; } #define git_array_alloc(a) \ - (((a).size < (a).asize || git_array_grow(&(a), sizeof(*(a).ptr)) == 0) ? \ - &(a).ptr[(a).size++] : (void *)NULL) + (((a).size < (a).asize || \ + ((a).ptr = git_array__alloc((a).ptr, &(a).size, &(a).asize, sizeof(*(a).ptr))) != NULL) ? &(a).ptr[(a).size++] : (void *)NULL) #define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : (void *)NULL) From aaed67f78673d6fb213de5a58dd1ed08d2ab9db2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 Apr 2024 20:47:45 +0100 Subject: [PATCH 517/816] alloc: introduce debug allocators Instead of tweaking the `stdalloc` allocator when `GIT_DEBUG_STRICT_ALLOC` is defined, actually create a debugging allocator. This allows us to ensure that we are strict about things like not expecting `malloc(0)` to do something useful, but we can also introduce an excessively pedantic `realloc` implementation that _always_ creates a new buffer, throws away its original `ptr`, and overwrites the data that's there with garbage. This may be helpful to identify places that make assumptions about realloc. --- src/util/alloc.c | 5 ++- src/util/allocators/debugalloc.c | 71 ++++++++++++++++++++++++++++++++ src/util/allocators/debugalloc.h | 17 ++++++++ src/util/allocators/stdalloc.c | 10 ----- 4 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/util/allocators/debugalloc.c create mode 100644 src/util/allocators/debugalloc.h diff --git a/src/util/alloc.c b/src/util/alloc.c index 6ec173d04a4..998b0aea1d9 100644 --- a/src/util/alloc.c +++ b/src/util/alloc.c @@ -8,8 +8,9 @@ #include "alloc.h" #include "runtime.h" -#include "allocators/failalloc.h" #include "allocators/stdalloc.h" +#include "allocators/debugalloc.h" +#include "allocators/failalloc.h" #include "allocators/win32_leakcheck.h" /* Fail any allocation until git_libgit2_init is called. */ @@ -88,6 +89,8 @@ static int setup_default_allocator(void) { #if defined(GIT_WIN32_LEAKCHECK) return git_win32_leakcheck_init_allocator(&git__allocator); +#elif defined(GIT_DEBUG_STRICT_ALLOC) + return git_debugalloc_init_allocator(&git__allocator); #else return git_stdalloc_init_allocator(&git__allocator); #endif diff --git a/src/util/allocators/debugalloc.c b/src/util/allocators/debugalloc.c new file mode 100644 index 00000000000..acb002dbb32 --- /dev/null +++ b/src/util/allocators/debugalloc.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "debugalloc.h" + +static void *debugalloc__malloc(size_t len, const char *file, int line) +{ + void *ptr; + size_t total = len + sizeof(size_t); + + GIT_UNUSED(file); + GIT_UNUSED(line); + + if (!len || (ptr = malloc(total)) == NULL) + return NULL; + + memcpy(ptr, &len, sizeof(size_t)); + return ptr + sizeof(size_t); +} + +static void *debugalloc__realloc(void *ptr, size_t len, const char *file, int line) +{ + void *newptr; + size_t original_len; + size_t total = len + sizeof(size_t); + + GIT_UNUSED(file); + GIT_UNUSED(line); + + if (!len && !ptr) + return NULL; + + if (!len) { + free(ptr - sizeof(size_t)); + return NULL; + } + + if ((newptr = malloc(total)) == NULL) + return NULL; + + if (ptr) { + memcpy(&original_len, ptr - sizeof(size_t), sizeof(size_t)); + memcpy(newptr + sizeof(size_t), ptr, min(len, original_len)); + + memset(ptr - sizeof(size_t), 0xfd, original_len + sizeof(size_t)); + free(ptr - sizeof(size_t)); + } + + memcpy(newptr, &len, sizeof(size_t)); + return newptr + sizeof(size_t); +} + +static void debugalloc__free(void *ptr) +{ + if (!ptr) + return; + + free(ptr - sizeof(size_t)); +} + +int git_debugalloc_init_allocator(git_allocator *allocator) +{ + allocator->gmalloc = debugalloc__malloc; + allocator->grealloc = debugalloc__realloc; + allocator->gfree = debugalloc__free; + return 0; +} diff --git a/src/util/allocators/debugalloc.h b/src/util/allocators/debugalloc.h new file mode 100644 index 00000000000..dea0ca31cc1 --- /dev/null +++ b/src/util/allocators/debugalloc.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_allocators_debugalloc_h__ +#define INCLUDE_allocators_debugalloc_h__ + +#include "git2_util.h" + +#include "alloc.h" + +int git_debugalloc_init_allocator(git_allocator *allocator); + +#endif diff --git a/src/util/allocators/stdalloc.c b/src/util/allocators/stdalloc.c index f2d72a7e6c9..65ec40fbe9d 100644 --- a/src/util/allocators/stdalloc.c +++ b/src/util/allocators/stdalloc.c @@ -12,11 +12,6 @@ static void *stdalloc__malloc(size_t len, const char *file, int line) GIT_UNUSED(file); GIT_UNUSED(line); -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!len) - return NULL; -#endif - return malloc(len); } @@ -25,11 +20,6 @@ static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int lin GIT_UNUSED(file); GIT_UNUSED(line); -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!size) - return NULL; -#endif - return realloc(ptr, size); } From cfd6e0148b93e4823630c2839610f825b11d0294 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 Apr 2024 20:49:57 +0100 Subject: [PATCH 518/816] tests: use git__ allocator functions consistently --- tests/libgit2/checkout/conflict.c | 2 +- tests/libgit2/checkout/icase.c | 2 +- tests/libgit2/remote/fetch.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/libgit2/checkout/conflict.c b/tests/libgit2/checkout/conflict.c index b2eb939dcd7..3539c8b2dee 100644 --- a/tests/libgit2/checkout/conflict.c +++ b/tests/libgit2/checkout/conflict.c @@ -1095,7 +1095,7 @@ static void collect_progress( if (path == NULL) return; - git_vector_insert(paths, strdup(path)); + git_vector_insert(paths, git__strdup(path)); } void test_checkout_conflict__report_progress(void) diff --git a/tests/libgit2/checkout/icase.c b/tests/libgit2/checkout/icase.c index d77c7abd514..3769a9f9b7e 100644 --- a/tests/libgit2/checkout/icase.c +++ b/tests/libgit2/checkout/icase.c @@ -89,7 +89,7 @@ static void assert_name_is(const char *expected) if (start) cl_assert_equal_strn("/", actual + (start - 1), 1); - free(actual); + git__free(actual); } static int symlink_or_fake(git_repository *repo, const char *a, const char *b) diff --git a/tests/libgit2/remote/fetch.c b/tests/libgit2/remote/fetch.c index a5d3272c56b..7d2d11e2702 100644 --- a/tests/libgit2/remote/fetch.c +++ b/tests/libgit2/remote/fetch.c @@ -40,10 +40,10 @@ void test_remote_fetch__cleanup(void) { git_repository_free(repo2); cl_git_pass(git_futils_rmdir_r(repo1_path, NULL, GIT_RMDIR_REMOVE_FILES)); - free(repo1_path); + git__free(repo1_path); cl_git_pass(git_futils_rmdir_r(repo2_path, NULL, GIT_RMDIR_REMOVE_FILES)); - free(repo2_path); + git__free(repo2_path); } From afb2ef21bc46e116ec939164fdb5efb77cd88536 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 Apr 2024 14:54:29 +0100 Subject: [PATCH 519/816] util: don't return system allocated strings in realpath realpath(3) _may_ allocate strings (if the second param is NULL) using the system allocator. However, callers need an assurance that they can free memory using git__free. If we made realpath do an allocation, then make sure that we strdup it into our allocator's memory. More importantly, avoid this behavior by always providing a buffer to p_realpath invocations. --- src/util/unix/realpath.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/util/unix/realpath.c b/src/util/unix/realpath.c index 9e31a63b9f4..e1d2adb8dba 100644 --- a/src/util/unix/realpath.c +++ b/src/util/unix/realpath.c @@ -16,17 +16,35 @@ char *p_realpath(const char *pathname, char *resolved) { - char *ret; - if ((ret = realpath(pathname, resolved)) == NULL) + char *result; + + if ((result = realpath(pathname, resolved)) == NULL) return NULL; #ifdef __OpenBSD__ /* The OpenBSD realpath function behaves differently, * figure out if the file exists */ - if (access(ret, F_OK) < 0) - ret = NULL; + if (access(ret, F_OK) < 0) { + if (!resolved) + free(result); + + return NULL; + } #endif - return ret; + + /* + * If resolved == NULL, the system has allocated the result + * string. We need to strdup this into _our_ allocator pool + * so that callers can free it with git__free. + */ + if (!resolved) { + char *dup = git__strdup(result); + free(result); + + result = dup; + } + + return result; } #endif From abedcfe71ce8b8cf58b4ac4c276dbc45a31d90ea Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 Apr 2024 17:31:27 +0100 Subject: [PATCH 520/816] tests: reset the allocator to the default Instead of setting the allocator to stdalloc, just pass `NULL`, in case we're running with the debug allocator. --- tests/clar/clar_libgit2_alloc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/clar/clar_libgit2_alloc.c b/tests/clar/clar_libgit2_alloc.c index e9303792382..54eacd543e2 100644 --- a/tests/clar/clar_libgit2_alloc.c +++ b/tests/clar/clar_libgit2_alloc.c @@ -104,7 +104,5 @@ void cl_alloc_limit(size_t bytes) void cl_alloc_reset(void) { - git_allocator stdalloc; - git_stdalloc_init_allocator(&stdalloc); - git_allocator_setup(&stdalloc); + git_allocator_setup(NULL); } From eb00b48d915d0dd01e41364d31c6ab8470834aae Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 15 May 2024 22:38:33 +0100 Subject: [PATCH 521/816] fixup! alloc: introduce debug allocators --- src/util/allocators/debugalloc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/util/allocators/debugalloc.c b/src/util/allocators/debugalloc.c index acb002dbb32..44022cd785a 100644 --- a/src/util/allocators/debugalloc.c +++ b/src/util/allocators/debugalloc.c @@ -9,7 +9,7 @@ static void *debugalloc__malloc(size_t len, const char *file, int line) { - void *ptr; + unsigned char *ptr; size_t total = len + sizeof(size_t); GIT_UNUSED(file); @@ -22,9 +22,9 @@ static void *debugalloc__malloc(size_t len, const char *file, int line) return ptr + sizeof(size_t); } -static void *debugalloc__realloc(void *ptr, size_t len, const char *file, int line) +static void *debugalloc__realloc(void *_ptr, size_t len, const char *file, int line) { - void *newptr; + unsigned char *ptr = _ptr, *newptr; size_t original_len; size_t total = len + sizeof(size_t); @@ -54,8 +54,10 @@ static void *debugalloc__realloc(void *ptr, size_t len, const char *file, int li return newptr + sizeof(size_t); } -static void debugalloc__free(void *ptr) +static void debugalloc__free(void *_ptr) { + unsigned char *ptr = _ptr; + if (!ptr) return; From 0dab9d4a5774418cc5fc587ba4ee19fa62606f8c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 15 May 2024 23:11:07 +0100 Subject: [PATCH 522/816] README: add experimental builds to ci table --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 77efdd4a688..ac2c9d1bff7 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | -| **main** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) | -| **v1.8 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.8) | -| **v1.7 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.7) | +| **main** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) | [![Experimental Features](https://github.com/libgit2/libgit2/workflows/Experimental%20Features/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Experimental+Features%22+event%3Apush) | +| **v1.8 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.8) | [![Experimental Features](https://github.com/libgit2/libgit2/workflows/Experimental%20Features/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Experimental+Features%22+event%3Apush+branch%3Amaint%2Fv1.8) | +| **v1.7 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.7) | [![Experimental Features](https://github.com/libgit2/libgit2/workflows/Experimental%20Features/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Experimental+Features%22+event%3Apush+branch%3Amaint%2Fv1.7) | | **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/workflows/Nightly%20Build/badge.svg)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Nightly+Build%22) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | `libgit2` is a portable, pure C implementation of the Git core methods From 834ec0f52fcafd3af011dfd3f1b36ae2ee984ea5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 16 May 2024 00:49:10 +0100 Subject: [PATCH 523/816] v1.8.1: update version numbers --- CMakeLists.txt | 2 +- include/git2/version.h | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17ca7576834..9ca8882a00e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.8.0" LANGUAGES C) +project(libgit2 VERSION "1.8.1" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") diff --git a/include/git2/version.h b/include/git2/version.h index 010d4a224d9..33c96254cee 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,7 +11,7 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.8.0" +#define LIBGIT2_VERSION "1.8.1" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 @@ -20,7 +20,7 @@ #define LIBGIT2_VER_MINOR 8 /** The revision ("teeny") version number for this version of libgit2. */ -#define LIBGIT2_VER_REVISION 0 +#define LIBGIT2_VER_REVISION 1 /** The Windows DLL patch number for this version of libgit2. */ #define LIBGIT2_VER_PATCH 0 diff --git a/package.json b/package.json index 2306e721853..6c1cb286ebd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.8.0", + "version": "1.8.1", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From ae65dac85ec4bfe795b35a8f1f4815489668713f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 16 May 2024 00:46:42 +0100 Subject: [PATCH 524/816] v1.8.1: update changelog --- docs/changelog.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 7b118c798be..a35a389a4c6 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,92 @@ +v1.8.1 +------ + +This release primarily includes straightforward bugfixes, as well as +new functionality to have more control over the HTTP User-Agent header. +However, there is an API change from v1.8 that was required for +improved compatibility. + +In v1.8, libgit2 introduced the `report_unchanged ` member in the +`git_fetch_options` structure. We mistakenly introduced this as a +bitfield, which is not suitable for our public API. To correct this +mistake, we have _removed_ the `report_unchanged ` member. To support +the report unchanged tips option, users can set the `update_fetchhead` +member to include the `GIT_REMOTE_UPDATE_REPORT_UNCHANGED` value. + +The libgit2 projects regrets the API change, but this was required to +support cross-platform compatibility. + +## What's Changed + +### New features + +* Allow more control over the user-agent by @ethomson in + https://github.com/libgit2/libgit2/pull/6788 + +### Bug fixes + +* commit: Fix git_commit_create_from_stage without author and + committer by @florianpircher in + https://github.com/libgit2/libgit2/pull/6781 +* process.c: fix environ for macOS by @barracuda156 in + https://github.com/libgit2/libgit2/pull/6792 +* Bounds check for pack index read by @ConradIrwin in + https://github.com/libgit2/libgit2/pull/6796 +* transport: provide a useful error message during cancellation + by @ethomson in https://github.com/libgit2/libgit2/pull/6802 +* transport: support sha256 oids by @ethomson in + https://github.com/libgit2/libgit2/pull/6803 +* Revparse: Correctly accept ref with '@' at the end by @csware in + https://github.com/libgit2/libgit2/pull/6809 +* remote: drop bitfields in git_remote_fetch_options by @ethomson in + https://github.com/libgit2/libgit2/pull/6806 +* examples: fix memory leak in for-each-ref.c by @qaqland in + https://github.com/libgit2/libgit2/pull/6808 +* xdiff: use proper free function by @ethomson in + https://github.com/libgit2/libgit2/pull/6810 +* rand: avoid uninitialized loadavg warnings by @ethomson in + https://github.com/libgit2/libgit2/pull/6812 +* cli: include alloca on illumos / solaris / sunos by @ethomson in + https://github.com/libgit2/libgit2/pull/6813 +* Update git_array allocator to obey strict aliasing rules + by @ethomson in https://github.com/libgit2/libgit2/pull/6814 +* tree: avoid mixed signedness comparison by @ethomson in + https://github.com/libgit2/libgit2/pull/6815 + +### Build and CI improvements + +* ci: update nightly workflows by @ethomson in + https://github.com/libgit2/libgit2/pull/6773 +* ci: give all nightly builds a unique id by @ethomson in + https://github.com/libgit2/libgit2/pull/6782 +* cmake: remove workaround that isn't compatible with Windows on + ARM by @hackhaslam in https://github.com/libgit2/libgit2/pull/6794 + +### Documentation improvements + +* Docs meta-updates by @ethomson in + https://github.com/libgit2/libgit2/pull/6787 + +### Dependency updates + +* Enable llhttp for HTTP parsing by @sgallagher in + https://github.com/libgit2/libgit2/pull/6713 + +## New Contributors + +* @florianpircher made their first contribution in + https://github.com/libgit2/libgit2/pull/6781 +* @barracuda156 made their first contribution in + https://github.com/libgit2/libgit2/pull/6792 +* @sgallagher made their first contribution in + https://github.com/libgit2/libgit2/pull/6713 +* @ConradIrwin made their first contribution in + https://github.com/libgit2/libgit2/pull/6796 +* @qaqland made their first contribution in + https://github.com/libgit2/libgit2/pull/6808 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.8.0...v1.8.1 + v1.8 ---- From ee552697d52dcd4394df90fd69c439bcdd7901d7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 16 May 2024 11:18:41 +0100 Subject: [PATCH 525/816] README: update build badges and links Use new-style links to the build information and badges, which link to the workflow filename, not the display name. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ac2c9d1bff7..0f492d14461 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | -| **main** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) | [![Experimental Features](https://github.com/libgit2/libgit2/workflows/Experimental%20Features/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Experimental+Features%22+event%3Apush) | -| **v1.8 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.8) | [![Experimental Features](https://github.com/libgit2/libgit2/workflows/Experimental%20Features/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Experimental+Features%22+event%3Apush+branch%3Amaint%2Fv1.8) | -| **v1.7 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.7) | [![Experimental Features](https://github.com/libgit2/libgit2/workflows/Experimental%20Features/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Experimental+Features%22+event%3Apush+branch%3Amaint%2Fv1.7) | -| **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/workflows/Nightly%20Build/badge.svg)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Nightly+Build%22) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | +| **main** branch builds | [![CI Build](https://github.com/libgit2/libgit2/actions/workflows/main.yml/badge.svg?branch=main&event=push)](https://github.com/libgit2/libgit2/actions/workflows/main.yml?query=event%3Apush+branch%3Amain) [![Experimental Features](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml/badge.svg?branch=main)](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml?query=event%3Apush+branch%3Amain) | +| **v1.8 branch** builds | [![CI Build](https://github.com/libgit2/libgit2/actions/workflows/main.yml/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions/workflows/main.yml?query=event%3Apush+branch%3Amaint%2Fv1.8) [![Experimental Features](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml/badge.svg?branch=maint%2Fv1.8)](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml?query=event%3Apush+branch%3Amaint%2Fv1.8) | +| **v1.7 branch** builds | [![CI Build](https://github.com/libgit2/libgit2/actions/workflows/main.yml/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions/workflows/main.yml?query=event%3Apush+branch%3Amaint%2Fv1.7) | +| **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/actions/workflows/nightly.yml/badge.svg?branch=main&event=schedule)](https://github.com/libgit2/libgit2/actions/workflows/nightly.yml) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | `libgit2` is a portable, pure C implementation of the Git core methods provided as a linkable library with a solid API, allowing to build Git From 49d3fadfca4ce8e7a643525eb301a2d45956641e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 13 Jun 2024 15:20:40 +0200 Subject: [PATCH 526/816] Revert "commit: fix const declaration" This reverts commit cf19ddc52227f4ec2efd4c0a84aa5d2362f0ffc7, which was breaking for several projects. --- examples/merge.c | 2 +- include/git2/commit.h | 6 +++--- src/libgit2/commit.c | 11 ++++++----- src/libgit2/commit.h | 2 +- src/libgit2/notes.c | 4 ++-- src/libgit2/rebase.c | 9 +++++---- src/libgit2/stash.c | 4 ++-- tests/libgit2/checkout/tree.c | 2 +- tests/libgit2/cherrypick/workdir.c | 2 +- tests/libgit2/commit/commit.c | 4 ++-- tests/libgit2/commit/write.c | 2 +- tests/libgit2/diff/rename.c | 2 +- tests/libgit2/odb/freshen.c | 2 +- tests/libgit2/rebase/sign.c | 6 +++--- tests/libgit2/refs/reflog/messages.c | 2 +- tests/libgit2/revert/workdir.c | 6 +++--- tests/libgit2/revwalk/basic.c | 3 ++- 17 files changed, 36 insertions(+), 33 deletions(-) diff --git a/examples/merge.c b/examples/merge.c index 718c767d038..7a76912cd24 100644 --- a/examples/merge.c +++ b/examples/merge.c @@ -263,7 +263,7 @@ static int create_merge_commit(git_repository *repo, git_index *index, struct me sign, sign, NULL, msg, tree, - opts->annotated_count + 1, parents); + opts->annotated_count + 1, (const git_commit **)parents); check_lg2(err, "failed to create commit", NULL); /* We're done merging, cleanup the repository state */ diff --git a/include/git2/commit.h b/include/git2/commit.h index ef38c66e6cc..88c21e0c973 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -366,7 +366,7 @@ GIT_EXTERN(int) git_commit_create( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[]); + const git_commit *parents[]); /** * Create new commit in the repository using a variable argument list. @@ -512,7 +512,7 @@ GIT_EXTERN(int) git_commit_create_buffer( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[]); + const git_commit *parents[]); /** * Create a commit object from the given buffer and signature @@ -581,7 +581,7 @@ typedef int (*git_commit_create_cb)( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[], + const git_commit *parents[], void *payload); /** An array of commits returned from the library */ diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 47f6fed892f..10df43623d2 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -281,7 +281,7 @@ int git_commit_create_from_ids( typedef struct { size_t total; - git_commit * const *parents; + const git_commit **parents; git_repository *repo; } commit_parent_data; @@ -307,7 +307,7 @@ int git_commit_create( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[]) + const git_commit *parents[]) { commit_parent_data data = { parent_count, parents, repo }; @@ -945,7 +945,7 @@ int git_commit_create_buffer( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[]) + const git_commit *parents[]) { GIT_BUF_WRAP_PRIVATE(out, git_commit__create_buffer, repo, author, committer, message_encoding, message, @@ -961,7 +961,7 @@ int git_commit__create_buffer( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[]) + const git_commit *parents[]) { int error; commit_parent_data data = { parent_count, parents, repo }; @@ -1150,7 +1150,8 @@ int git_commit_create_from_stage( error = git_commit_create(out, repo, "HEAD", author, committer, opts.message_encoding, message, - tree, parents.count, parents.commits); + tree, parents.count, + (const git_commit **)parents.commits); done: git_commitarray_dispose(&parents); diff --git a/src/libgit2/commit.h b/src/libgit2/commit.h index 53128ba5d83..c25fee327b8 100644 --- a/src/libgit2/commit.h +++ b/src/libgit2/commit.h @@ -64,7 +64,7 @@ int git_commit__create_buffer( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[]); + const git_commit *parents[]); int git_commit__parse( void *commit, diff --git a/src/libgit2/notes.c b/src/libgit2/notes.c index 2dd194581fd..13ca3824bf1 100644 --- a/src/libgit2/notes.c +++ b/src/libgit2/notes.c @@ -303,7 +303,7 @@ static int note_write( error = git_commit_create(&oid, repo, notes_ref, author, committer, NULL, GIT_NOTES_DEFAULT_MSG_ADD, - tree, *parents == NULL ? 0 : 1, parents); + tree, *parents == NULL ? 0 : 1, (const git_commit **) parents); if (notes_commit_out) git_oid_cpy(notes_commit_out, &oid); @@ -394,7 +394,7 @@ static int note_remove( NULL, GIT_NOTES_DEFAULT_MSG_RM, tree_after_removal, *parents == NULL ? 0 : 1, - parents); + (const git_commit **) parents); if (error < 0) goto cleanup; diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c index 2fce3e7bc06..77e442e981d 100644 --- a/src/libgit2/rebase.c +++ b/src/libgit2/rebase.c @@ -952,7 +952,7 @@ static int create_signed( const char *message, git_tree *tree, size_t parent_count, - git_commit * const *parents) + const git_commit **parents) { git_str commit_content = GIT_STR_INIT; git_buf commit_signature = { NULL, 0, 0 }, @@ -1040,7 +1040,8 @@ static int rebase_commit__create( if (rebase->options.commit_create_cb) { error = rebase->options.commit_create_cb(&commit_id, author, committer, message_encoding, message, - tree, 1, &parent_commit, rebase->options.payload); + tree, 1, (const git_commit **)&parent_commit, + rebase->options.payload); git_error_set_after_callback_function(error, "commit_create_cb"); @@ -1049,14 +1050,14 @@ static int rebase_commit__create( else if (rebase->options.signing_cb) { error = create_signed(&commit_id, rebase, author, committer, message_encoding, message, tree, - 1, &parent_commit); + 1, (const git_commit **)&parent_commit); } #endif if (error == GIT_PASSTHROUGH) error = git_commit_create(&commit_id, rebase->repo, NULL, author, committer, message_encoding, message, - tree, 1, &parent_commit); + tree, 1, (const git_commit **)&parent_commit); if (error) goto done; diff --git a/src/libgit2/stash.c b/src/libgit2/stash.c index a0a72deacc6..b49e95cdb21 100644 --- a/src/libgit2/stash.c +++ b/src/libgit2/stash.c @@ -124,7 +124,7 @@ static int commit_index( git_index *index, const git_signature *stasher, const char *message, - git_commit *parent) + const git_commit *parent) { git_tree *i_tree = NULL; git_oid i_commit_oid; @@ -423,7 +423,7 @@ static int build_stash_commit_from_tree( git_commit *u_commit, const git_tree *tree) { - git_commit *parents[] = { NULL, NULL, NULL }; + const git_commit *parents[] = { NULL, NULL, NULL }; parents[0] = b_commit; parents[1] = i_commit; diff --git a/tests/libgit2/checkout/tree.c b/tests/libgit2/checkout/tree.c index 97935aaeaa1..65df00cd87b 100644 --- a/tests/libgit2/checkout/tree.c +++ b/tests/libgit2/checkout/tree.c @@ -1235,7 +1235,7 @@ void test_checkout_tree__case_changing_rename(void) cl_git_pass(git_signature_new(&signature, "Renamer", "rename@contoso.com", time(NULL), 0)); - cl_git_pass(git_commit_create(&commit_id, g_repo, "refs/heads/dir", signature, signature, NULL, "case-changing rename", tree, 1, &dir_commit)); + cl_git_pass(git_commit_create(&commit_id, g_repo, "refs/heads/dir", signature, signature, NULL, "case-changing rename", tree, 1, (const git_commit **)&dir_commit)); cl_assert(git_fs_path_isfile("testrepo/readme")); if (case_sensitive) diff --git a/tests/libgit2/cherrypick/workdir.c b/tests/libgit2/cherrypick/workdir.c index 9d9a3f49795..c16b7814ac0 100644 --- a/tests/libgit2/cherrypick/workdir.c +++ b/tests/libgit2/cherrypick/workdir.c @@ -77,7 +77,7 @@ void test_cherrypick_workdir__automerge(void) cl_git_pass(git_index_write_tree(&cherrypicked_tree_oid, repo_index)); cl_git_pass(git_tree_lookup(&cherrypicked_tree, repo, &cherrypicked_tree_oid)); cl_git_pass(git_commit_create(&cherrypicked_oid, repo, "HEAD", signature, signature, NULL, - "Cherry picked!", cherrypicked_tree, 1, &head)); + "Cherry picked!", cherrypicked_tree, 1, (const git_commit **)&head)); cl_assert(merge_test_index(repo_index, merge_index_entries + i * 3, 3)); diff --git a/tests/libgit2/commit/commit.c b/tests/libgit2/commit/commit.c index 923740f23af..140f87d0c72 100644 --- a/tests/libgit2/commit/commit.c +++ b/tests/libgit2/commit/commit.c @@ -36,11 +36,11 @@ void test_commit_commit__create_unexisting_update_ref(void) cl_git_fail(git_reference_lookup(&ref, _repo, "refs/heads/foo/bar")); cl_git_pass(git_commit_create(&oid, _repo, "refs/heads/foo/bar", s, s, - NULL, "some msg", tree, 1, &commit)); + NULL, "some msg", tree, 1, (const git_commit **) &commit)); /* fail because the parent isn't the tip of the branch anymore */ cl_git_fail(git_commit_create(&oid, _repo, "refs/heads/foo/bar", s, s, - NULL, "some msg", tree, 1, &commit)); + NULL, "some msg", tree, 1, (const git_commit **) &commit)); cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/foo/bar")); cl_assert_equal_oid(&oid, git_reference_target(ref)); diff --git a/tests/libgit2/commit/write.c b/tests/libgit2/commit/write.c index d38b54d2077..890f7384b1a 100644 --- a/tests/libgit2/commit/write.c +++ b/tests/libgit2/commit/write.c @@ -118,7 +118,7 @@ void test_commit_write__into_buf(void) cl_git_pass(git_commit_lookup(&parent, g_repo, &parent_id)); cl_git_pass(git_commit_create_buffer(&commit, g_repo, author, committer, - NULL, root_commit_message, tree, 1, &parent)); + NULL, root_commit_message, tree, 1, (const git_commit **) &parent)); cl_assert_equal_s(commit.ptr, "tree 1810dff58d8a660512d4832e740f692884338ccd\n\ diff --git a/tests/libgit2/diff/rename.c b/tests/libgit2/diff/rename.c index 15dee5c97d5..61a2f839cb3 100644 --- a/tests/libgit2/diff/rename.c +++ b/tests/libgit2/diff/rename.c @@ -424,7 +424,7 @@ void test_diff_rename__test_small_files(void) cl_git_pass(git_index_write_tree(&oid, index)); cl_git_pass(git_tree_lookup(&commit_tree, g_repo, &oid)); cl_git_pass(git_signature_new(&signature, "Rename", "rename@example.com", 1404157834, 0)); - cl_git_pass(git_commit_create(&oid, g_repo, "HEAD", signature, signature, NULL, "Test commit", commit_tree, 1, &head_commit)); + cl_git_pass(git_commit_create(&oid, g_repo, "HEAD", signature, signature, NULL, "Test commit", commit_tree, 1, (const git_commit**)&head_commit)); cl_git_mkfile("renames/copy.txt", "Hello World!\n"); cl_git_rmfile("renames/small.txt"); diff --git a/tests/libgit2/odb/freshen.c b/tests/libgit2/odb/freshen.c index d0e0e3c3c04..e337c82b773 100644 --- a/tests/libgit2/odb/freshen.c +++ b/tests/libgit2/odb/freshen.c @@ -125,7 +125,7 @@ void test_odb_freshen__tree_during_commit(void) cl_git_pass(git_commit_create(&commit_id, repo, NULL, signature, signature, NULL, "New commit pointing to old tree", - tree, 1, &parent)); + tree, 1, (const git_commit **)&parent)); /* make sure we freshen the tree the commit points to */ cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after)); diff --git a/tests/libgit2/rebase/sign.c b/tests/libgit2/rebase/sign.c index 45bac29d095..69bb1c6f998 100644 --- a/tests/libgit2/rebase/sign.c +++ b/tests/libgit2/rebase/sign.c @@ -26,7 +26,7 @@ static int create_cb_passthrough( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[], + const git_commit *parents[], void *payload) { GIT_UNUSED(out); @@ -94,7 +94,7 @@ static int create_cb_signed_gpg( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[], + const git_commit *parents[], void *payload) { git_buf commit_content = GIT_BUF_INIT; @@ -202,7 +202,7 @@ static int create_cb_error( const char *message, const git_tree *tree, size_t parent_count, - git_commit * const parents[], + const git_commit *parents[], void *payload) { GIT_UNUSED(out); diff --git a/tests/libgit2/refs/reflog/messages.c b/tests/libgit2/refs/reflog/messages.c index 4a2ecb02aed..647c00d0dfd 100644 --- a/tests/libgit2/refs/reflog/messages.c +++ b/tests/libgit2/refs/reflog/messages.c @@ -233,7 +233,7 @@ void test_refs_reflog_messages__show_merge_for_merge_commits(void) cl_git_pass(git_commit_create(&merge_commit_oid, g_repo, "HEAD", s, s, NULL, "Merge commit", tree, - 2, parent_commits)); + 2, (const struct git_commit **) parent_commits)); cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, NULL, diff --git a/tests/libgit2/revert/workdir.c b/tests/libgit2/revert/workdir.c index 6d74254e533..3e790b77f78 100644 --- a/tests/libgit2/revert/workdir.c +++ b/tests/libgit2/revert/workdir.c @@ -188,7 +188,7 @@ void test_revert_workdir__again(void) cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); - cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, &orig_head)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head)); cl_git_pass(git_revert(repo, orig_head, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); @@ -238,7 +238,7 @@ void test_revert_workdir__again_after_automerge(void) cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); - cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, &head)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&head)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, second_revert_entries, 6)); @@ -287,7 +287,7 @@ void test_revert_workdir__again_after_edit(void) cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid)); cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0)); - cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, &orig_head)); + cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); diff --git a/tests/libgit2/revwalk/basic.c b/tests/libgit2/revwalk/basic.c index 5c53405051b..41090a1dac8 100644 --- a/tests/libgit2/revwalk/basic.c +++ b/tests/libgit2/revwalk/basic.c @@ -550,7 +550,8 @@ void test_revwalk_basic__big_timestamp(void) cl_git_pass(git_signature_new(&sig, "Joe", "joe@example.com", INT64_C(2399662595), 0)); cl_git_pass(git_commit_tree(&tree, tip)); - cl_git_pass(git_commit_create(&id, _repo, "HEAD", sig, sig, NULL, "some message", tree, 1, &tip)); + cl_git_pass(git_commit_create(&id, _repo, "HEAD", sig, sig, NULL, "some message", tree, 1, + (const git_commit **)&tip)); cl_git_pass(git_revwalk_push_head(_walk)); From 48b63274eaae07512dde115e965a31afa48b75da Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 13 Jun 2024 19:42:55 +0200 Subject: [PATCH 527/816] v1.8.2: update changelog --- docs/changelog.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index a35a389a4c6..fe12271f3ed 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,29 @@ +v1.8.2 +------ + +This release reverts a const-correctness change introduced in +v1.8.0 for the `git_commit_create` functions. We now retain the +const-behavior for the `commits` arguments from prior to v1.8.0. + +This change was meant to resolve compatibility issues with bindings +and downstream users. + +## What's Changed + +### New features + +* Introduce a stricter debugging allocator for testing by @ethomson in https://github.com/libgit2/libgit2/pull/6811 + +### Bug fixes + +* Fix constness issue introduced in #6716 by @ethomson in https://github.com/libgit2/libgit2/pull/6829 + +### Build and CI improvements + +* README: add experimental builds to ci table by @ethomson in https://github.com/libgit2/libgit2/pull/6816 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.8.1...v1.8.2 + v1.8.1 ------ From e9d56b0b14df53e739348e097ebc4dc44a7f3ea5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 13 Jun 2024 19:43:46 +0200 Subject: [PATCH 528/816] v1.8.2: update version numbers --- CMakeLists.txt | 2 +- include/git2/version.h | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ca8882a00e..578ec177729 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.8.1" LANGUAGES C) +project(libgit2 VERSION "1.8.2" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") diff --git a/include/git2/version.h b/include/git2/version.h index 33c96254cee..60675c88be5 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,7 +11,7 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.8.1" +#define LIBGIT2_VERSION "1.8.2" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 @@ -20,7 +20,7 @@ #define LIBGIT2_VER_MINOR 8 /** The revision ("teeny") version number for this version of libgit2. */ -#define LIBGIT2_VER_REVISION 1 +#define LIBGIT2_VER_REVISION 2 /** The Windows DLL patch number for this version of libgit2. */ #define LIBGIT2_VER_PATCH 0 diff --git a/package.json b/package.json index 6c1cb286ebd..df10dee2733 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.8.1", + "version": "1.8.2", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From 24d9fe13390ba84a326ae3895ce9979f89cd147a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 14 Jun 2024 12:49:09 +0200 Subject: [PATCH 529/816] signature: keep using signature_default internally Making the various pieces that create commits automatically (eg, rebase) start paying attention to the environment variables is a Big Change. For now, this is a big change in defaults; we should treat it as breaking. We don't move to this by default; we may add `from_env` or `honor_env` type of API surface in the future. --- src/libgit2/rebase.c | 2 +- src/libgit2/refs.c | 2 +- tests/libgit2/remote/fetch.c | 2 +- tests/libgit2/repo/init.c | 12 +++++------- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c index e9de626521a..77e442e981d 100644 --- a/src/libgit2/rebase.c +++ b/src/libgit2/rebase.c @@ -1268,7 +1268,7 @@ static int rebase_copy_note( } if (!committer) { - if((error = git_signature_default_committer(&who, rebase->repo)) < 0) { + if((error = git_signature_default(&who, rebase->repo)) < 0) { if (error != GIT_ENOTFOUND || (error = git_signature_now(&who, "unknown", "unknown")) < 0) goto done; diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index 8b553d40ae8..c1ed04d233a 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -451,7 +451,7 @@ int git_reference__log_signature(git_signature **out, git_repository *repo) git_signature *who; if(((error = refs_configured_ident(&who, repo)) < 0) && - ((error = git_signature_default_author(&who, repo)) < 0) && + ((error = git_signature_default(&who, repo)) < 0) && ((error = git_signature_now(&who, "unknown", "unknown")) < 0)) return error; diff --git a/tests/libgit2/remote/fetch.c b/tests/libgit2/remote/fetch.c index c24ec5a01f6..a5d3272c56b 100644 --- a/tests/libgit2/remote/fetch.c +++ b/tests/libgit2/remote/fetch.c @@ -82,7 +82,7 @@ static void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, cl_git_pass(git_treebuilder_new(&tb, repo1, NULL)); cl_git_pass(git_treebuilder_write(&empty_tree_id, tb)); cl_git_pass(git_tree_lookup(&empty_tree, repo1, &empty_tree_id)); - cl_git_pass(git_signature_default_author(&sig, repo1)); + cl_git_pass(git_signature_default(&sig, repo1)); cl_git_pass(git_commit_create(commit1id, repo1, REPO1_REFNAME, sig, sig, NULL, "one", empty_tree, 0, NULL)); cl_git_pass(git_commit_lookup(&commit1, repo1, commit1id)); diff --git a/tests/libgit2/repo/init.c b/tests/libgit2/repo/init.c index bb26e5443ae..d78ec063cd2 100644 --- a/tests/libgit2/repo/init.c +++ b/tests/libgit2/repo/init.c @@ -581,7 +581,7 @@ void test_repo_init__init_with_initial_commit(void) * made to a repository... */ - /* Make sure we're ready to use git_signature_default_author :-) */ + /* Make sure we're ready to use git_signature_default :-) */ { git_config *cfg, *local; cl_git_pass(git_repository_config(&cfg, g_repo)); @@ -594,22 +594,20 @@ void test_repo_init__init_with_initial_commit(void) /* Create a commit with the new contents of the index */ { - git_signature *author_sig, *committer_sig; + git_signature *sig; git_oid tree_id, commit_id; git_tree *tree; - cl_git_pass(git_signature_default_author(&author_sig, g_repo)); - cl_git_pass(git_signature_default_committer(&committer_sig, g_repo)); + cl_git_pass(git_signature_default(&sig, g_repo)); cl_git_pass(git_index_write_tree(&tree_id, index)); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); cl_git_pass(git_commit_create_v( - &commit_id, g_repo, "HEAD", author_sig, committer_sig, + &commit_id, g_repo, "HEAD", sig, sig, NULL, "First", tree, 0)); git_tree_free(tree); - git_signature_free(author_sig); - git_signature_free(committer_sig); + git_signature_free(sig); } git_index_free(index); From 649ef1cca624f1e6e4cfa7e286f7a7aca06abab1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 14 Jun 2024 12:50:40 +0200 Subject: [PATCH 530/816] signature: add `git_signature_default_from_env` People who are doing a commit expect a unified timestamp between author and committer information when we're using the current timestamp. Provide a single function that returns both author and committer information so that they can have an identical timestamp when none is specified in the environment. --- examples/commit.c | 6 +- examples/init.c | 3 +- examples/stash.c | 2 +- examples/tag.c | 2 +- include/git2/signature.h | 82 ++++++++----------- src/libgit2/signature.c | 133 ++++++++++++++++++++----------- tests/libgit2/commit/signature.c | 17 ++-- 7 files changed, 134 insertions(+), 111 deletions(-) diff --git a/examples/commit.c b/examples/commit.c index 1ba4739f051..c6e0a8dc447 100644 --- a/examples/commit.c +++ b/examples/commit.c @@ -63,10 +63,8 @@ int lg2_commit(git_repository *repo, int argc, char **argv) check_lg2(git_tree_lookup(&tree, repo, &tree_oid), "Error looking up tree", NULL); - check_lg2(git_signature_default_author(&author_signature, repo), - "Error creating author signature", NULL); - check_lg2(git_signature_default_committer(&committer_signature, repo), - "Error creating committer signature", NULL); + check_lg2(git_signature_default_from_env(&author_signature, &committer_signature, repo), + "Error creating signature", NULL); check_lg2(git_commit_create_v( &commit_oid, diff --git a/examples/init.c b/examples/init.c index f0f0105be6e..036c156ab08 100644 --- a/examples/init.c +++ b/examples/init.c @@ -130,8 +130,7 @@ static void create_initial_commit(git_repository *repo) /** First use the config to initialize a commit signature for the user. */ - if ((git_signature_default_author(&author_sig, repo) < 0) || - (git_signature_default_committer(&committer_sig, repo) < 0)) + if ((git_signature_default_from_env(&author_sig, &committer_sig, repo) < 0)) fatal("Unable to create a commit signature.", "Perhaps 'user.name' and 'user.email' are not set"); diff --git a/examples/stash.c b/examples/stash.c index c330cbce102..197724364f6 100644 --- a/examples/stash.c +++ b/examples/stash.c @@ -108,7 +108,7 @@ static int cmd_push(git_repository *repo, struct opts *opts) if (opts->argc) usage("push does not accept any parameters"); - check_lg2(git_signature_default_author(&signature, repo), + check_lg2(git_signature_default_from_env(&signature, NULL, repo), "Unable to get signature", NULL); check_lg2(git_stash_save(&stashid, repo, signature, NULL, GIT_STASH_DEFAULT), "Unable to save stash", NULL); diff --git a/examples/tag.c b/examples/tag.c index 9bebcd1e68e..ebe1a9d7bf0 100644 --- a/examples/tag.c +++ b/examples/tag.c @@ -226,7 +226,7 @@ static void action_create_tag(tag_state *state) check_lg2(git_revparse_single(&target, repo, opts->target), "Unable to resolve spec", opts->target); - check_lg2(git_signature_default_author(&tagger, repo), + check_lg2(git_signature_default_from_env(&tagger, NULL, repo), "Unable to create signature", NULL); check_lg2(git_tag_create(&oid, repo, opts->tag_name, diff --git a/include/git2/signature.h b/include/git2/signature.h index 84c36a33d98..a027d25dcdc 100644 --- a/include/git2/signature.h +++ b/include/git2/signature.h @@ -49,65 +49,53 @@ GIT_EXTERN(int) git_signature_new(git_signature **out, const char *name, const c GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const char *email); /** - * Create a new author action signature with default information based on the - * configuration and environment variables. - * - * If GIT_AUTHOR_NAME environment variable is set it uses that over the - * user.name value from the configuration. - * - * If GIT_AUTHOR_EMAIL environment variable is set it uses that over the - * user.email value from the configuration. The EMAIL environment variable is - * the fallback email address in case the user.email configuration value isn't - * set. - * - * If GIT_AUTHOR_DATE is set it uses that, otherwise it uses the current time - * as the timestamp. - * - * It will return GIT_ENOTFOUND if either the user.name or user.email are not - * set and there is no fallback from an environment variable. - * - * @param out new signature + * Create a new author and/or committer signatures with default + * information based on the configuration and environment variables. + * + * If `author_out` is set, it will be populated with the author + * information. The `GIT_AUTHOR_NAME` and `GIT_AUTHOR_EMAIL` + * environment variables will be honored, and `user.name` and + * `user.email` configuration options will be honored if the + * environment variables are unset. For timestamps, `GIT_AUTHOR_DATE` + * will be used, otherwise the current time will be used. + * + * If `committer_out` is set, it will be populated with the + * committer information. The `GIT_COMMITTER_NAME` and + * `GIT_COMMITTER_EMAIL` environment variables will be honored, + * and `user.name` and `user.email` configuration options will + * be honored if the environment variables are unset. For timestamps, + * `GIT_COMMITTER_DATE` will be used, otherwise the current time will + * be used. + * + * If neither `GIT_AUTHOR_DATE` nor `GIT_COMMITTER_DATE` are set, + * both timestamps will be set to the same time. + * + * It will return `GIT_ENOTFOUND` if either the `user.name` or + * `user.email` are not set and there is no fallback from an environment + * variable. One of `author_out` or `committer_out` must be set. + * + * @param author_out pointer to set the author signature, or NULL + * @param committer_out pointer to set the committer signature, or NULL * @param repo repository pointer * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code */ -GIT_EXTERN(int) git_signature_default_author(git_signature **out, git_repository *repo); - -/** - * Create a new committer action signature with default information based on - * the configuration and environment variables. - * - * If GIT_COMMITTER_NAME environment variable is set it uses that over the - * user.name value from the configuration. - * - * If GIT_COMMITTER_EMAIL environment variable is set it uses that over the - * user.email value from the configuration. The EMAIL environment variable is - * the fallback email address in case the user.email configuration value isn't - * set. - * - * If GIT_COMMITTER_DATE is set it uses that, otherwise it uses the current - * time as the timestamp. - * - * It will return GIT_ENOTFOUND if either the user.name or user.email are not - * set and there is no fallback from an environment variable. - * - * @param out new signature - * @param repo repository pointer - * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code - */ -GIT_EXTERN(int) git_signature_default_committer(git_signature **out, git_repository *repo); +GIT_EXTERN(int) git_signature_default_from_env( + git_signature **author_out, + git_signature **committer_out, + git_repository *repo); /** * Create a new action signature with default user and now timestamp. * - * Warning: This function may be deprecated in the future. Use one of - * git_signature_default_author or git_signature_default_committer instead. - * These are more compliant with how git constructs default signatures. - * * This looks up the user.name and user.email from the configuration and * uses the current time as the timestamp, and creates a new signature * based on that information. It will return GIT_ENOTFOUND if either the * user.name or user.email are not set. * + * Note that these do not examine environment variables, only the + * configuration files. Use `git_signature_default_from_env` to + * consider the environment variables. + * * @param out new signature * @param repo repository pointer * @return 0 on success, GIT_ENOTFOUND if config is missing, or error code diff --git a/src/libgit2/signature.c b/src/libgit2/signature.c index e6b1ac6622d..71da4162371 100644 --- a/src/libgit2/signature.c +++ b/src/libgit2/signature.c @@ -153,15 +153,10 @@ int git_signature__pdup(git_signature **dest, const git_signature *source, git_p return 0; } -int git_signature_now(git_signature **sig_out, const char *name, const char *email) +static void current_time(time_t *now_out, int *offset_out) { - time_t now; time_t offset; - struct tm *utc_tm; - git_signature *sig; - struct tm _utc; - - *sig_out = NULL; + struct tm _utc, *utc_tm; /* * Get the current time as seconds since the epoch and @@ -171,21 +166,28 @@ int git_signature_now(git_signature **sig_out, const char *name, const char *ema * us that time as seconds since the epoch. The difference * between its return value and 'now' is our offset to UTC. */ - time(&now); - utc_tm = p_gmtime_r(&now, &_utc); + time(now_out); + utc_tm = p_gmtime_r(now_out, &_utc); utc_tm->tm_isdst = -1; - offset = (time_t)difftime(now, mktime(utc_tm)); + offset = (time_t)difftime(*now_out, mktime(utc_tm)); offset /= 60; - if (git_signature_new(&sig, name, email, now, (int)offset) < 0) - return -1; + *offset_out = (int)offset; +} - *sig_out = sig; +int git_signature_now( + git_signature **sig_out, + const char *name, + const char *email) +{ + time_t now; + int offset; - return 0; + current_time(&now, &offset); + + return git_signature_new(sig_out, name, email, now, offset); } -#ifndef GIT_DEPRECATE_HARD int git_signature_default(git_signature **out, git_repository *repo) { int error; @@ -202,10 +204,15 @@ int git_signature_default(git_signature **out, git_repository *repo) git_config_free(cfg); return error; } -#endif -static int git_signature__default_from_env(const char *name_env_var, const char *email_env_var, - const char *date_env_var, git_signature **out, git_repository *repo) +static int user_from_env( + git_signature **out, + git_repository *repo, + const char *name_env_var, + const char *email_env_var, + const char *date_env_var, + time_t default_time, + int default_offset) { int error; git_config *cfg; @@ -215,46 +222,53 @@ static int git_signature__default_from_env(const char *name_env_var, const char git_str name_env = GIT_STR_INIT; git_str email_env = GIT_STR_INIT; git_str date_env = GIT_STR_INIT; - int have_email_env = -1; if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) return error; /* Check if the environment variable for the name is set */ - if (!(git__getenv(&name_env, name_env_var))) + if (!(git__getenv(&name_env, name_env_var))) { name = git_str_cstr(&name_env); - else + } else { /* or else read the configuration value. */ if ((error = git_config_get_string(&name, cfg, "user.name")) < 0) goto done; + } /* Check if the environment variable for the email is set. */ - if (!(git__getenv(&email_env, email_env_var))) + if (!(git__getenv(&email_env, email_env_var))) { email = git_str_cstr(&email_env); - else { - /* Check if the fallback EMAIL environment variable is set - * before we check the configuration so that we preserve the - * error message if the configuration value is missing. */ - git_str_dispose(&email_env); - have_email_env = !git__getenv(&email_env, "EMAIL"); - if ((error = git_config_get_string(&email, cfg, "user.email")) < 0) { - if (have_email_env) { - email = git_str_cstr(&email_env); - error = 0; - } else + } else { + if ((error = git_config_get_string(&email, cfg, "user.email")) == GIT_ENOTFOUND) { + git_error *last_error; + + git_error_save(&last_error); + + if ((error = git__getenv(&email_env, "EMAIL")) < 0) { + git_error_restore(last_error); + error = GIT_ENOTFOUND; goto done; + } + + email = git_str_cstr(&email_env); + git_error_free(last_error); + } else if (error < 0) { + goto done; } } /* Check if the environment variable for the timestamp is set */ if (!(git__getenv(&date_env, date_env_var))) { date = git_str_cstr(&date_env); + if ((error = git_date_offset_parse(×tamp, &offset, date)) < 0) goto done; - error = git_signature_new(out, name, email, timestamp, offset); - } else - /* or else default to the current timestamp. */ - error = git_signature_now(out, name, email); + } else { + timestamp = default_time; + offset = default_offset; + } + + error = git_signature_new(out, name, email, timestamp, offset); done: git_config_free(cfg); @@ -264,16 +278,45 @@ static int git_signature__default_from_env(const char *name_env_var, const char return error; } -int git_signature_default_author(git_signature **out, git_repository *repo) +int git_signature_default_from_env( + git_signature **author_out, + git_signature **committer_out, + git_repository *repo) { - return git_signature__default_from_env("GIT_AUTHOR_NAME", "GIT_AUTHOR_EMAIL", - "GIT_AUTHOR_DATE", out, repo); -} + git_signature *author = NULL, *committer = NULL; + time_t now; + int offset; + int error; -int git_signature_default_committer(git_signature **out, git_repository *repo) -{ - return git_signature__default_from_env("GIT_COMMITTER_NAME", "GIT_COMMITTER_EMAIL", - "GIT_COMMITTER_DATE", out, repo); + GIT_ASSERT_ARG(author_out || committer_out); + GIT_ASSERT_ARG(repo); + + current_time(&now, &offset); + + if (author_out && + (error = user_from_env(&author, repo, "GIT_AUTHOR_NAME", + "GIT_AUTHOR_EMAIL", "GIT_AUTHOR_DATE", + now, offset)) < 0) + goto on_error; + + if (committer_out && + (error = user_from_env(&committer, repo, "GIT_COMMITTER_NAME", + "GIT_COMMITTER_EMAIL", "GIT_COMMITTER_DATE", + now, offset)) < 0) + goto on_error; + + if (author_out) + *author_out = author; + + if (committer_out) + *committer_out = committer; + + return 0; + +on_error: + git__free(author); + git__free(committer); + return error; } int git_signature__parse(git_signature *sig, const char **buffer_out, diff --git a/tests/libgit2/commit/signature.c b/tests/libgit2/commit/signature.c index 2ad91f3f3d0..3fa6646cf33 100644 --- a/tests/libgit2/commit/signature.c +++ b/tests/libgit2/commit/signature.c @@ -167,7 +167,7 @@ void test_commit_signature__cleanup(void) g_repo = NULL; } -void test_commit_signature__signature_default(void) +void test_commit_signature__from_env(void) { git_signature *author_sign, *committer_sign; git_config *cfg, *local; @@ -179,14 +179,12 @@ void test_commit_signature__signature_default(void) cl_setenv("GIT_AUTHOR_EMAIL", NULL); cl_setenv("GIT_COMMITTER_NAME", NULL); cl_setenv("GIT_COMMITTER_EMAIL", NULL); - cl_git_fail(git_signature_default_author(&author_sign, g_repo)); - cl_git_fail(git_signature_default_committer(&committer_sign, g_repo)); + cl_git_fail(git_signature_default_from_env(&author_sign, &committer_sign, g_repo)); /* Name is read from configuration and email is read from fallback EMAIL * environment variable */ cl_git_pass(git_config_set_string(local, "user.name", "Name (config)")); cl_setenv("EMAIL", "email-envvar@example.com"); - cl_git_pass(git_signature_default_author(&author_sign, g_repo)); - cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_git_pass(git_signature_default_from_env(&author_sign, &committer_sign, g_repo)); cl_assert_equal_s("Name (config)", author_sign->name); cl_assert_equal_s("email-envvar@example.com", author_sign->email); cl_assert_equal_s("Name (config)", committer_sign->name); @@ -200,8 +198,7 @@ void test_commit_signature__signature_default(void) cl_setenv("GIT_AUTHOR_EMAIL", "author-envvar@example.com"); cl_setenv("GIT_COMMITTER_NAME", "Committer (envvar)"); cl_setenv("GIT_COMMITTER_EMAIL", "committer-envvar@example.com"); - cl_git_pass(git_signature_default_author(&author_sign, g_repo)); - cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_git_pass(git_signature_default_from_env(&author_sign, &committer_sign, g_repo)); cl_assert_equal_s("Author (envvar)", author_sign->name); cl_assert_equal_s("author-envvar@example.com", author_sign->email); cl_assert_equal_s("Committer (envvar)", committer_sign->name); @@ -214,8 +211,7 @@ void test_commit_signature__signature_default(void) cl_setenv("GIT_AUTHOR_EMAIL", NULL); cl_setenv("GIT_COMMITTER_NAME", NULL); cl_setenv("GIT_COMMITTER_EMAIL", NULL); - cl_git_pass(git_signature_default_author(&author_sign, g_repo)); - cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_git_pass(git_signature_default_from_env(&author_sign, &committer_sign, g_repo)); cl_assert_equal_s("Name (config)", author_sign->name); cl_assert_equal_s("config@example.com", author_sign->email); cl_assert_equal_s("Name (config)", committer_sign->name); @@ -225,8 +221,7 @@ void test_commit_signature__signature_default(void) /* We can also override the timestamp with an environment variable */ cl_setenv("GIT_AUTHOR_DATE", "1971-02-03 04:05:06+01"); cl_setenv("GIT_COMMITTER_DATE", "1988-09-10 11:12:13-01"); - cl_git_pass(git_signature_default_author(&author_sign, g_repo)); - cl_git_pass(git_signature_default_committer(&committer_sign, g_repo)); + cl_git_pass(git_signature_default_from_env(&author_sign, &committer_sign, g_repo)); cl_assert_equal_i(34398306, author_sign->when.time); /* 1971-02-03 03:05:06 UTC */ cl_assert_equal_i(60, author_sign->when.offset); cl_assert_equal_i(589896733, committer_sign->when.time); /* 1988-09-10 12:12:13 UTC */ From b85848e81e2ef0e2763248813c00c11a3a894eff Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Mon, 17 Jun 2024 19:24:15 +0200 Subject: [PATCH 531/816] Limit .gitattributes and .gitignore files to 100 MiB Git introduced this 100 MiB limit in commits 3c50032ff528 (attr: ignore overly large gitattributes files, 2022-12-01) and e7c3d1ddba0b (dir.c: reduce max pattern file size to 100MB, 2024-06-05). Signed-off-by: Sven Strickroth --- src/libgit2/attr_file.c | 5 +++++ src/libgit2/attr_file.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/libgit2/attr_file.c b/src/libgit2/attr_file.c index afa8ec7b379..108ed744630 100644 --- a/src/libgit2/attr_file.c +++ b/src/libgit2/attr_file.c @@ -143,6 +143,8 @@ int git_attr_file__load( blobsize = git_blob_rawsize(blob); GIT_ERROR_CHECK_BLOBSIZE(blobsize); + if (blobsize > GIT_ATTR_MAX_FILE_SIZE) /* TODO: issue warning when warning API is available */ + goto cleanup; git_str_put(&content, git_blob_rawcontent(blob), (size_t)blobsize); break; } @@ -155,6 +157,7 @@ int git_attr_file__load( if (p_stat(entry->fullpath, &st) < 0 || S_ISDIR(st.st_mode) || (fd = git_futils_open_ro(entry->fullpath)) < 0 || + (st.st_size > GIT_ATTR_MAX_FILE_SIZE) || (error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size)) < 0) nonexistent = true; @@ -198,6 +201,8 @@ int git_attr_file__load( blobsize = git_blob_rawsize(blob); GIT_ERROR_CHECK_BLOBSIZE(blobsize); + if (blobsize > GIT_ATTR_MAX_FILE_SIZE) /* TODO: issue warning when warning API is available */ + goto cleanup; if ((error = git_str_put(&content, git_blob_rawcontent(blob), (size_t)blobsize)) < 0) goto cleanup; diff --git a/src/libgit2/attr_file.h b/src/libgit2/attr_file.h index 08630d1a6eb..8025359ba9b 100644 --- a/src/libgit2/attr_file.h +++ b/src/libgit2/attr_file.h @@ -21,6 +21,8 @@ #define GIT_ATTR_FILE_SYSTEM "gitattributes" #define GIT_ATTR_FILE_XDG "attributes" +#define GIT_ATTR_MAX_FILE_SIZE 100 * 1024 * 1024 + #define GIT_ATTR_FNMATCH_NEGATIVE (1U << 0) #define GIT_ATTR_FNMATCH_DIRECTORY (1U << 1) #define GIT_ATTR_FNMATCH_FULLPATH (1U << 2) From c3e76dd2f6aad41dc4a0aafbab6c83e0eb635fa3 Mon Sep 17 00:00:00 2001 From: gensmusic Date: Sat, 22 Jun 2024 09:34:04 +0800 Subject: [PATCH 532/816] odb: conditional git_hash_ctx_cleanup in git_odb_stream When `git_odb_stream` is a read stream, `hash_ctx` is not used. Therefore, check if `hash_ctx` can be freed during the release. This allows implementers of custom ODB backends to not worry about the creation of `hash_ctx` for now. --- src/libgit2/odb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index fec1e45b9d4..7e56774996d 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -1796,7 +1796,8 @@ void git_odb_stream_free(git_odb_stream *stream) if (stream == NULL) return; - git_hash_ctx_cleanup(stream->hash_ctx); + if (stream->hash_ctx) + git_hash_ctx_cleanup(stream->hash_ctx); git__free(stream->hash_ctx); stream->free(stream); } From ca1e3dbb06bcd99a030638f5896519873a2fd912 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 22 Jun 2024 12:59:37 -0700 Subject: [PATCH 533/816] Fix docs for git_odb_stream_read return value. --- include/git2/odb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/git2/odb.h b/include/git2/odb.h index c7d6a894cd2..60e293a13bd 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -382,7 +382,7 @@ GIT_EXTERN(int) git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stre * @param stream the stream * @param buffer a user-allocated buffer to store the data in. * @param len the buffer's length - * @return 0 if the read succeeded, error code otherwise + * @return the number of bytes read if succeeded, error code otherwise */ GIT_EXTERN(int) git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len); From febc6558fea53f44000250c80e2e145a2b260449 Mon Sep 17 00:00:00 2001 From: thymusvulgaris <87661013+thymusvulgaris@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:32:49 +0100 Subject: [PATCH 534/816] docs: Add instructions to build examples To build the examples, they must be included in the main build using the following command: cmake -DBUILD_EXAMPLES=True .. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0f492d14461..c0c997ada28 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,10 @@ On most systems you can build the library using the following commands $ cmake .. $ cmake --build . +To include the examples in the build, use `cmake -DBUILD_EXAMPLES=True ..` instead of `cmake ..`. + +The built executable for the examples can then be found in `build/examples`, relative to the toplevel directory. + Alternatively you can point the CMake GUI tool to the CMakeLists.txt file and generate platform specific build project or IDE workspace. If you're not familiar with CMake, [a more detailed explanation](https://preshing.com/20170511/how-to-build-a-cmake-based-project/) may be helpful. From dfc4d4b7967c5db47ade661d2a257b6f21f5ae9f Mon Sep 17 00:00:00 2001 From: Bruno S Marques Date: Tue, 2 Jul 2024 21:27:36 -0300 Subject: [PATCH 535/816] Add cmake package targets --- src/CMakeLists.txt | 24 ++++++++++++++++++++++++ src/cli/CMakeLists.txt | 2 +- src/cmake_utils/config.cmake.in | 3 +++ src/libgit2/CMakeLists.txt | 2 ++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/cmake_utils/config.cmake.in diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed3f4a51427..35c86c58429 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -198,6 +198,30 @@ add_feature_info(iconv GIT_USE_ICONV "iconv encoding conversion support") # Include child projects # +set(LIBGIT2_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") +set(LIBGIT2_VERSION_CONFIG "${LIBGIT2_GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake") +set(LIBGIT2_PROJECT_CONFIG "${LIBGIT2_GENERATED_DIR}/${PROJECT_NAME}Config.cmake") +set(LIBGIT2_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") +set(LIBGIT2_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") +set(LIBGIT2_NAMESPACE "${PROJECT_NAME}::") +set(LIBGIT2_VERSION ${PROJECT_VERSION}) + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${LIBGIT2_VERSION_CONFIG}" VERSION ${LIBGIT2_VERSION} COMPATIBILITY SameMajorVersion +) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_utils/config.cmake.in" "${LIBGIT2_PROJECT_CONFIG}" @ONLY) + +# Install cmake config files +install( + FILES "${LIBGIT2_PROJECT_CONFIG}" "${LIBGIT2_VERSION_CONFIG}" + DESTINATION "${LIBGIT2_CONFIG_INSTALL_DIR}") + +install( + EXPORT "${LIBGIT2_TARGETS_EXPORT_NAME}" + NAMESPACE "${LIBGIT2_NAMESPACE}" + DESTINATION "${LIBGIT2_CONFIG_INSTALL_DIR}") + add_subdirectory(libgit2) add_subdirectory(util) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 97797e33bd9..447652d8d4f 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -54,4 +54,4 @@ if(MSVC_IDE) set_source_files_properties(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h") endif() -install(TARGETS git2_cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(TARGETS git2_cli EXPORT ${LIBGIT2_TARGETS_EXPORT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/cmake_utils/config.cmake.in b/src/cmake_utils/config.cmake.in new file mode 100644 index 00000000000..6d15e05882f --- /dev/null +++ b/src/cmake_utils/config.cmake.in @@ -0,0 +1,3 @@ +include(CMakeFindDependencyMacro) + +include("${CMAKE_CURRENT_LIST_DIR}/@LIBGIT2_TARGETS_EXPORT_NAME@.cmake") \ No newline at end of file diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index bc7cb5b3597..e2ddc8e213b 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -59,6 +59,7 @@ set(LIBGIT2_SYSTEM_LIBS ${LIBGIT2_SYSTEM_LIBS} PARENT_SCOPE) add_library(libgit2package ${SRC_RC} ${LIBGIT2_OBJECTS}) target_link_libraries(libgit2package ${LIBGIT2_SYSTEM_LIBS}) target_include_directories(libgit2package SYSTEM PRIVATE ${LIBGIT2_INCLUDES}) +target_include_directories(libgit2package INTERFACE $) set_target_properties(libgit2package PROPERTIES C_STANDARD 90) set_target_properties(libgit2package PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) @@ -105,6 +106,7 @@ FILE(WRITE "${PROJECT_BINARY_DIR}/include/${LIBGIT2_FILENAME}.h" ${LIBGIT2_INCLU # Install install(TARGETS libgit2package + EXPORT ${LIBGIT2_TARGETS_EXPORT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) From 9e40c1390c2a66b85b5778c515562faeac3d0c6a Mon Sep 17 00:00:00 2001 From: Kevin Saul Date: Sun, 7 Jul 2024 11:07:45 +1200 Subject: [PATCH 536/816] smart: fix shallow roots setup --- src/libgit2/transports/smart_protocol.c | 1 + tests/libgit2/online/shallow.c | 148 +++++++++++++++++++++++- 2 files changed, 146 insertions(+), 3 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index df1c190c30e..fb2dd7cf2d6 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -394,6 +394,7 @@ static int setup_shallow_roots( memcpy(out->ptr, wants->shallow_roots, sizeof(git_oid) * wants->shallow_roots_len); + out->size = wants->shallow_roots_len; } return 0; diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c index ee4aaf37ed4..d7038cdd2dc 100644 --- a/tests/libgit2/online/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -242,10 +242,15 @@ void test_online_shallow__shorten_four(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); - cl_assert_equal_i(3, roots_len); - cl_assert_equal_s("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864", git_oid_tostr_s(&roots[0])); - cl_assert_equal_s("59706a11bde2b9899a278838ef20a97e8f8795d2", git_oid_tostr_s(&roots[1])); + cl_assert_equal_i(6, roots_len); + /* roots added during initial clone, not removed as not encountered during fetch */ + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&roots[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots[3])); + /* roots added during fetch */ cl_assert_equal_s("bab66b48f836ed950c99134ef666436fb07a09a0", git_oid_tostr_s(&roots[2])); + cl_assert_equal_s("59706a11bde2b9899a278838ef20a97e8f8795d2", git_oid_tostr_s(&roots[4])); + cl_assert_equal_s("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864", git_oid_tostr_s(&roots[5])); git_revwalk_new(&walk, repo); git_revwalk_push_head(walk); @@ -263,3 +268,140 @@ void test_online_shallow__shorten_four(void) git_revwalk_free(walk); git_repository_free(repo); } + +void test_online_shallow__preserve_unrelated_roots(void) +{ + git_str path = GIT_STR_INIT; + git_repository *repo; + git_revwalk *walk; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + git_remote *origin = NULL; + git_strarray refspecs; + git_oid oid; + git_oid *roots; + size_t roots_len; + size_t num_commits = 0; + int error = 0; + git_oid first_oid; + git_oid second_oid; + git_oid third_oid; + char *first_commit = "c070ad8c08840c8116da865b2d65593a6bb9cd2a"; + char *second_commit = "6e1475206e57110fcef4b92320436c1e9872a322"; + char *third_commit = "7f822839a2fe9760f386cbbbcb3f92c5fe81def7"; + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_oid_fromstr(&first_oid, first_commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_fromstr(&second_oid, second_commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_fromstr(&third_oid, third_commit, GIT_OID_SHA1)); +#else + cl_git_pass(git_oid_fromstr(&first_oid, first_commit)); + cl_git_pass(git_oid_fromstr(&second_oid, second_commit)); + cl_git_pass(git_oid_fromstr(&third_oid, third_commit)); +#endif + + /* setup empty repository without cloning */ + git_str_joinpath(&path, clar_sandbox_path(), "preserve_unrelated_roots"); + cl_git_pass(git_repository_init(&repo, git_str_cstr(&path), true)); + cl_git_pass(git_remote_create(&origin, repo, "origin", "https://github.com/libgit2/TestGitRepository")); + cl_assert_equal_b(false, git_repository_is_shallow(repo)); + + /* shallow fetch for first commit */ + fetch_opts.depth = 1; + refspecs.strings = &first_commit; + refspecs.count = 1; + cl_git_pass(git_remote_fetch(origin, &refspecs, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(1, roots_len); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots[0])); + + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &first_oid)); + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(num_commits, 1); + cl_assert_equal_i(error, GIT_ITEROVER); + + /* shallow fetch for second commit */ + fetch_opts.depth = 1; + refspecs.strings = &second_commit; + refspecs.count = 1; + cl_git_pass(git_remote_fetch(origin, &refspecs, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + git__free(roots); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(2, roots_len); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots[0])); + cl_assert_equal_s("6e1475206e57110fcef4b92320436c1e9872a322", git_oid_tostr_s(&roots[1])); + + git_revwalk_free(walk); + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &second_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 1); + + /* fetch full history for third commit, includes first commit which should be removed from shallow roots */ + fetch_opts.depth = 100; + refspecs.strings = &third_commit; + refspecs.count = 1; + cl_git_pass(git_remote_fetch(origin, &refspecs, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + git__free(roots); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(1, roots_len); + cl_assert_equal_s("6e1475206e57110fcef4b92320436c1e9872a322", git_oid_tostr_s(&roots[0])); + + git_revwalk_free(walk); + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &third_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 12); + + cl_git_pass(git_revwalk_reset(walk)); + cl_git_pass(git_revwalk_push(walk, &second_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 1); + + /* unshallow repository without specifying any refspec */ + fetch_opts.depth = GIT_FETCH_DEPTH_UNSHALLOW; + cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL)); + cl_assert_equal_b(false, git_repository_is_shallow(repo)); + + git__free(roots); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(0, roots_len); + + git_revwalk_free(walk); + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &first_oid)); + cl_git_pass(git_revwalk_push(walk, &second_oid)); + cl_git_pass(git_revwalk_push(walk, &third_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 18); + + git__free(roots); + git_remote_free(origin); + git_str_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +} From 9213ed3b753fdd3bddf51d0fe5bbb246c2e061df Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Wed, 10 Jul 2024 14:42:23 -0400 Subject: [PATCH 537/816] Add myself to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 784bab3ee7d..f4e852357e5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -75,4 +75,5 @@ Tim Clem Tim Harder Torsten Bögershausen Trent Mick +Venus Xeon-Blonde Vicent Marti From 848f8d6803a593fb3b86ff3e825f8919b66f34e3 Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Wed, 10 Jul 2024 15:24:08 -0400 Subject: [PATCH 538/816] Add more robust error handling to `SecureTransport` errors that occur on macos. --- src/libgit2/streams/stransport.c | 45 +++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 7a3585e246b..97fe0dace44 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -20,6 +20,9 @@ static int stransport_error(OSStatus ret) { CFStringRef message; + char * message_c_str; + /* Use a boolean to track if we allocate a buffer for message_c_str that we need to free later. */ + bool must_free = false; if (ret == noErr || ret == errSSLClosedGraceful) { git_error_clear(); @@ -30,11 +33,51 @@ static int stransport_error(OSStatus ret) message = SecCopyErrorMessageString(ret, NULL); GIT_ERROR_CHECK_ALLOC(message); - git_error_set(GIT_ERROR_NET, "SecureTransport error: %s", CFStringGetCStringPtr(message, kCFStringEncodingUTF8)); + /* Attempt to cheaply convert the CoreFoundations string ref to a C-style null terminated string. */ + message_c_str = (char *) CFStringGetCStringPtr(message, kCFStringEncodingUTF8); + + /* + CFStringGetCStringPtr can return null in some instances, where the message conversion is not cheap. + In these cases, it's more valuable to print the actual error message than to be cheap/efficient. + Call the (more expensive) + */ + if (message_c_str == NULL) { + /* + Before we allocate a buffer, get the size of the buffer we need to allocate (in bytes). + CFStringGetLength gives us the number of UTF-16 code-pairs (16 bit characters) in the string. + Multiply by 2 (since 2 8-bit bytes make a 16 bit char). Add one for the null terminator. + */ + long buffer_size = CFStringGetLength(message) * 2 + 1; + + /* Allocate the buffer. */ + message_c_str = malloc((size_t) buffer_size); + + /* + Convert the string into a C string using the buffer. + This returns a bool, which we check using this block. + If getting the CString failed (unlikely) we return early. + */ + if (!CFStringGetCString(message, message_c_str, buffer_size, kCFStringEncodingUTF8)) { + git_error_set(GIT_ERROR_NET, "CFStringGetCString error while handling a SecureTransport error"); + free(message_c_str); + CFRelease(message); + return -1; + } + } + + git_error_set(GIT_ERROR_NET, "SecureTransport error: %s", message_c_str); + + /* If we decided earlier that we would have to free the buffer allocation, do that. */ + if (must_free) { + free(message_c_str); + } + CFRelease(message); #else git_error_set(GIT_ERROR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret); GIT_UNUSED(message); + GIT_UNUSED(message_c_str); + GIT_UNUSED(must_free); #endif return -1; From 0c39ee1b1f5b0e4c50e85db17b9bc033b242c495 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Mon, 1 Jul 2024 14:30:12 -0700 Subject: [PATCH 539/816] Use typedef type for git_odb This makes the function signature consistent with other cases --- include/git2/odb.h | 2 +- src/libgit2/odb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/odb.h b/include/git2/odb.h index 60e293a13bd..4a7af07b81f 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -286,7 +286,7 @@ GIT_EXTERN(int) git_odb_expand_ids( * @param db database to refresh * @return 0 on success, error code otherwise */ -GIT_EXTERN(int) git_odb_refresh(struct git_odb *db); +GIT_EXTERN(int) git_odb_refresh(git_odb *db); /** * List all objects available in the database diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 7e56774996d..00e8bb5065b 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -1923,7 +1923,7 @@ void git_odb_backend_data_free(git_odb_backend *backend, void *data) git__free(data); } -int git_odb_refresh(struct git_odb *db) +int git_odb_refresh(git_odb *db) { size_t i; int error; From 1f83c4652ca20ce4f0cf838c60c15a5c942d7278 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Tue, 2 Jul 2024 08:08:51 -0700 Subject: [PATCH 540/816] Remove duplicating declaration of git_email_create_from_diff() Exactly the same function already declared in include/git2/email.h --- include/git2/email.h | 24 ------------------------ src/libgit2/diff.c | 2 +- src/libgit2/email.c | 1 + tests/libgit2/email/create.c | 1 + 4 files changed, 3 insertions(+), 25 deletions(-) diff --git a/include/git2/email.h b/include/git2/email.h index 3389353e796..08b573e8c68 100644 --- a/include/git2/email.h +++ b/include/git2/email.h @@ -84,30 +84,6 @@ typedef struct { GIT_DIFF_FIND_OPTIONS_INIT \ } -/** - * Create a diff for a commit in mbox format for sending via email. - * - * @param out buffer to store the e-mail patch in - * @param diff the changes to include in the email - * @param patch_idx the patch index - * @param patch_count the total number of patches that will be included - * @param commit_id the commit id for this change - * @param summary the commit message for this change - * @param body optional text to include above the diffstat - * @param author the person who authored this commit - * @param opts email creation options - */ -GIT_EXTERN(int) git_email_create_from_diff( - git_buf *out, - git_diff *diff, - size_t patch_idx, - size_t patch_count, - const git_oid *commit_id, - const char *summary, - const char *body, - const git_signature *author, - const git_email_create_options *opts); - /** * Create a diff for a commit in mbox format for sending via email. * The commit must not be a merge commit. diff --git a/src/libgit2/diff.c b/src/libgit2/diff.c index db12ccd6809..80027ba30a0 100644 --- a/src/libgit2/diff.c +++ b/src/libgit2/diff.c @@ -16,7 +16,7 @@ #include "diff_generate.h" #include "git2/version.h" -#include "git2/email.h" +#include "git2/sys/email.h" struct patch_id_args { git_diff *diff; diff --git a/src/libgit2/email.c b/src/libgit2/email.c index 8a10a12b75f..c1470c16323 100644 --- a/src/libgit2/email.c +++ b/src/libgit2/email.c @@ -16,6 +16,7 @@ #include "git2/email.h" #include "git2/patch.h" +#include "git2/sys/email.h" #include "git2/version.h" /* diff --git a/tests/libgit2/email/create.c b/tests/libgit2/email/create.c index cf40ff552e0..cd3ccf7002b 100644 --- a/tests/libgit2/email/create.c +++ b/tests/libgit2/email/create.c @@ -1,5 +1,6 @@ #include "clar.h" #include "clar_libgit2.h" +#include "git2/sys/email.h" #include "diff_generate.h" From c9f0178aac372079f74f09a6e78aafb732a3a762 Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Wed, 10 Jul 2024 21:10:04 -0400 Subject: [PATCH 541/816] Fix missing boolean assignment --- src/libgit2/streams/stransport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 97fe0dace44..b30cb8f3c1f 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -41,7 +41,7 @@ static int stransport_error(OSStatus ret) In these cases, it's more valuable to print the actual error message than to be cheap/efficient. Call the (more expensive) */ - if (message_c_str == NULL) { + if (( must_free = (message_c_str == NULL) )) { /* Before we allocate a buffer, get the size of the buffer we need to allocate (in bytes). CFStringGetLength gives us the number of UTF-16 code-pairs (16 bit characters) in the string. From eebaa36f73bcb6c9eb9f521688d0facb9bf521ac Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 11 Jul 2024 11:13:20 +0100 Subject: [PATCH 542/816] url: track whether url explicitly specified a port When parsing URLs, track whether the port number was explicitly specified or not. We track this separately from whether the port is the _default_ port. This is so that we can discern between URLs that have the default port explicitly specified or not. For example: scp://host:22/foo and scp://host/foo are equivalent in terms of functionality, but are not semantically equivalent. A user might wish to specify scp://host:22/foo in order to explicitly ensure that we connect on port 22, which might override (for example) a different configuration option. --- src/util/net.c | 15 +++++++--- src/util/net.h | 2 ++ tests/util/url/parse.c | 67 ++++++++++++++++++++++++++++++++++++++++++ tests/util/url/scp.c | 33 +++++++++++++++++++++ 4 files changed, 113 insertions(+), 4 deletions(-) diff --git a/src/util/net.c b/src/util/net.c index dede784cc31..d7ca48a590c 100644 --- a/src/util/net.c +++ b/src/util/net.c @@ -387,6 +387,7 @@ static int url_parse_finalize(git_net_url *url, git_net_url_parser *parser) port = GIT_STR_INIT, path = GIT_STR_INIT, query = GIT_STR_INIT, fragment = GIT_STR_INIT; const char *default_port; + int port_specified = 0; int error = 0; if (parser->scheme_len) { @@ -408,10 +409,13 @@ static int url_parse_finalize(git_net_url *url, git_net_url_parser *parser) (error = git_str_decode_percent(&host, parser->host, parser->host_len)) < 0) goto done; - if (parser->port_len) + if (parser->port_len) { + port_specified = 1; error = git_str_put(&port, parser->port, parser->port_len); - else if (parser->scheme_len && (default_port = default_port_for_scheme(scheme.ptr)) != NULL) + } else if (parser->scheme_len && + (default_port = default_port_for_scheme(scheme.ptr)) != NULL) { error = git_str_puts(&port, default_port); + } if (error < 0) goto done; @@ -440,6 +444,7 @@ static int url_parse_finalize(git_net_url *url, git_net_url_parser *parser) url->fragment = git_str_detach(&fragment); url->username = git_str_detach(&user); url->password = git_str_detach(&password); + url->port_specified = port_specified; error = 0; @@ -785,10 +790,12 @@ int git_net_url_parse_scp(git_net_url *url, const char *given) GIT_ASSERT(host_len); GIT_ERROR_CHECK_ALLOC(url->host = git__strndup(host, host_len)); - if (port_len) + if (port_len) { + url->port_specified = 1; GIT_ERROR_CHECK_ALLOC(url->port = git__strndup(port, port_len)); - else + } else { GIT_ERROR_CHECK_ALLOC(url->port = git__strdup(default_port)); + } GIT_ASSERT(path); GIT_ERROR_CHECK_ALLOC(url->path = git__strdup(path)); diff --git a/src/util/net.h b/src/util/net.h index 8024956ad0c..360a55db493 100644 --- a/src/util/net.h +++ b/src/util/net.h @@ -35,6 +35,8 @@ typedef struct git_net_url { char *fragment; char *username; char *password; + + unsigned int port_specified; } git_net_url; #define GIT_NET_URL_INIT { NULL } diff --git a/tests/util/url/parse.c b/tests/util/url/parse.c index 35486f7b7a7..ece379780ac 100644 --- a/tests/util/url/parse.c +++ b/tests/util/url/parse.c @@ -27,6 +27,7 @@ void test_url_parse__hostname_trivial(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_root(void) @@ -41,6 +42,7 @@ void test_url_parse__hostname_root(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_implied_root(void) @@ -55,6 +57,7 @@ void test_url_parse__hostname_implied_root(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_numeric(void) @@ -69,6 +72,7 @@ void test_url_parse__hostname_numeric(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_implied_root_custom_port(void) @@ -83,6 +87,22 @@ void test_url_parse__hostname_implied_root_custom_port(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); +} + +void test_url_parse__specified_default_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://example.com:80/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_p(conndata.query, NULL); + cl_assert_equal_p(conndata.fragment, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__hostname_implied_root_empty_port(void) @@ -97,6 +117,7 @@ void test_url_parse__hostname_implied_root_empty_port(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_encoded_password(void) @@ -112,6 +133,7 @@ void test_url_parse__hostname_encoded_password(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__hostname_user(void) @@ -127,6 +149,7 @@ void test_url_parse__hostname_user(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_user_pass(void) @@ -143,6 +166,7 @@ void test_url_parse__hostname_user_pass(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_port(void) @@ -159,6 +183,7 @@ void test_url_parse__hostname_port(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__hostname_empty_port(void) @@ -173,6 +198,7 @@ void test_url_parse__hostname_empty_port(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__hostname_user_port(void) @@ -189,6 +215,7 @@ void test_url_parse__hostname_user_port(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__hostname_user_pass_port(void) @@ -205,6 +232,7 @@ void test_url_parse__hostname_user_pass_port(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__hostname_user_pass_port_query(void) @@ -221,6 +249,7 @@ void test_url_parse__hostname_user_pass_port_query(void) cl_assert_equal_s(conndata.query, "query=q&foo=bar&z=asdf"); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__hostname_user_pass_port_fragment(void) @@ -237,6 +266,7 @@ void test_url_parse__hostname_user_pass_port_fragment(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_s(conndata.fragment, "fragment"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__hostname_user_pass_port_query_fragment(void) @@ -253,6 +283,7 @@ void test_url_parse__hostname_user_pass_port_query_fragment(void) cl_assert_equal_s(conndata.query, "query=q&foo=bar&z=asdf"); cl_assert_equal_s(conndata.fragment, "fragment"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__fragment_with_question_mark(void) @@ -269,6 +300,7 @@ void test_url_parse__fragment_with_question_mark(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_s(conndata.fragment, "fragment_with?question_mark"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } /* IPv4 addresses */ @@ -283,6 +315,7 @@ void test_url_parse__ipv4_trivial(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv4_root(void) @@ -295,6 +328,7 @@ void test_url_parse__ipv4_root(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv4_implied_root(void) @@ -307,6 +341,7 @@ void test_url_parse__ipv4_implied_root(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv4_implied_root_custom_port(void) @@ -319,6 +354,7 @@ void test_url_parse__ipv4_implied_root_custom_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv4_implied_root_empty_port(void) @@ -331,6 +367,7 @@ void test_url_parse__ipv4_implied_root_empty_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv4_encoded_password(void) @@ -344,6 +381,7 @@ void test_url_parse__ipv4_encoded_password(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_s(conndata.password, "pass/is@bad"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv4_user(void) @@ -357,6 +395,7 @@ void test_url_parse__ipv4_user(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv4_user_pass(void) @@ -370,6 +409,7 @@ void test_url_parse__ipv4_user_pass(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_s(conndata.password, "pass"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv4_port(void) @@ -383,6 +423,7 @@ void test_url_parse__ipv4_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv4_empty_port(void) @@ -395,6 +436,7 @@ void test_url_parse__ipv4_empty_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv4_user_port(void) @@ -408,6 +450,7 @@ void test_url_parse__ipv4_user_port(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv4_user_pass_port(void) @@ -421,6 +464,7 @@ void test_url_parse__ipv4_user_pass_port(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_s(conndata.password, "pass"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } /* IPv6 addresses */ @@ -435,6 +479,7 @@ void test_url_parse__ipv6_trivial(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv6_root(void) @@ -447,6 +492,7 @@ void test_url_parse__ipv6_root(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv6_implied_root(void) @@ -459,6 +505,7 @@ void test_url_parse__ipv6_implied_root(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv6_implied_root_custom_port(void) @@ -471,6 +518,7 @@ void test_url_parse__ipv6_implied_root_custom_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv6_implied_root_empty_port(void) @@ -483,6 +531,7 @@ void test_url_parse__ipv6_implied_root_empty_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv6_encoded_password(void) @@ -496,6 +545,7 @@ void test_url_parse__ipv6_encoded_password(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_s(conndata.password, "pass/is@bad"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv6_user(void) @@ -509,6 +559,7 @@ void test_url_parse__ipv6_user(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv6_user_pass(void) @@ -522,6 +573,7 @@ void test_url_parse__ipv6_user_pass(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_s(conndata.password, "pass"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv6_port(void) @@ -535,6 +587,7 @@ void test_url_parse__ipv6_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv6_empty_port(void) @@ -547,6 +600,7 @@ void test_url_parse__ipv6_empty_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__ipv6_user_port(void) @@ -560,6 +614,7 @@ void test_url_parse__ipv6_user_port(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv6_user_pass_port(void) @@ -573,6 +628,7 @@ void test_url_parse__ipv6_user_pass_port(void) cl_assert_equal_s(conndata.username, "user"); cl_assert_equal_s(conndata.password, "pass"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ipv6_invalid_addresses(void) @@ -681,6 +737,7 @@ void test_url_parse__empty_scheme(void) cl_assert_equal_p(conndata.query, NULL); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__invalid_scheme_is_relative(void) @@ -695,12 +752,14 @@ void test_url_parse__invalid_scheme_is_relative(void) cl_assert_equal_s(conndata.query, "query_string=yes"); cl_assert_equal_p(conndata.fragment, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__scheme_case_is_normalized(void) { cl_git_pass(git_net_url_parse(&conndata, "GIT+SSH://host:42/path/to/project")); cl_assert_equal_s(conndata.scheme, "git+ssh"); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__nonhierarchical_scheme(void) @@ -713,6 +772,7 @@ void test_url_parse__nonhierarchical_scheme(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__no_scheme_relative_path(void) @@ -725,6 +785,7 @@ void test_url_parse__no_scheme_relative_path(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__no_scheme_absolute_path(void) @@ -737,6 +798,7 @@ void test_url_parse__no_scheme_absolute_path(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__empty_path(void) @@ -749,6 +811,7 @@ void test_url_parse__empty_path(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__empty_path_with_empty_authority(void) @@ -761,6 +824,7 @@ void test_url_parse__empty_path_with_empty_authority(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_parse__http_follows_the_rfc(void) @@ -778,6 +842,7 @@ void test_url_parse__ssh_from_terrible_google_rfc_violating_products(void) cl_assert_equal_s(conndata.username, "my.email.address@gmail.com"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__ssh_with_password_from_terrible_google_rfc_violating_products(void) @@ -790,6 +855,7 @@ void test_url_parse__ssh_with_password_from_terrible_google_rfc_violating_produc cl_assert_equal_s(conndata.username, "my.email.address@gmail.com"); cl_assert_equal_s(conndata.password, "seekret"); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_parse__spaces_in_the_name(void) @@ -802,4 +868,5 @@ void test_url_parse__spaces_in_the_name(void) cl_assert_equal_s(conndata.username, "libgit2"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } diff --git a/tests/util/url/scp.c b/tests/util/url/scp.c index 0e0dce17eab..1fd7c313e0a 100644 --- a/tests/util/url/scp.c +++ b/tests/util/url/scp.c @@ -25,6 +25,7 @@ void test_url_scp__hostname_trivial(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__hostname_bracketed(void) @@ -37,6 +38,7 @@ void test_url_scp__hostname_bracketed(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__hostname_root(void) @@ -49,6 +51,7 @@ void test_url_scp__hostname_root(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__hostname_user(void) @@ -61,6 +64,7 @@ void test_url_scp__hostname_user(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__hostname_user_bracketed(void) @@ -73,6 +77,7 @@ void test_url_scp__hostname_user_bracketed(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__hostname_port(void) @@ -85,6 +90,20 @@ void test_url_scp__hostname_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); +} + +void test_url_scp__hostname_specified_default_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[example.com:22]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_scp__hostname_user_port(void) @@ -97,6 +116,7 @@ void test_url_scp__hostname_user_port(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_scp__ipv4_trivial(void) @@ -109,6 +129,7 @@ void test_url_scp__ipv4_trivial(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__ipv4_bracketed(void) @@ -121,6 +142,7 @@ void test_url_scp__ipv4_bracketed(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__ipv4_user(void) @@ -133,6 +155,7 @@ void test_url_scp__ipv4_user(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__ipv4_port(void) @@ -145,6 +168,7 @@ void test_url_scp__ipv4_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_scp__ipv4_user_port(void) @@ -157,6 +181,7 @@ void test_url_scp__ipv4_user_port(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_scp__ipv6_trivial(void) @@ -169,6 +194,7 @@ void test_url_scp__ipv6_trivial(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__ipv6_user(void) @@ -181,6 +207,7 @@ void test_url_scp__ipv6_user(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__ipv6_port(void) @@ -193,6 +220,7 @@ void test_url_scp__ipv6_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_scp__ipv6_user_port(void) @@ -205,6 +233,7 @@ void test_url_scp__ipv6_user_port(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_scp__hexhost_and_port(void) @@ -217,6 +246,7 @@ void test_url_scp__hexhost_and_port(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 1); } void test_url_scp__malformed_ipv6_one(void) @@ -229,6 +259,7 @@ void test_url_scp__malformed_ipv6_one(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__malformed_ipv6_two(void) @@ -241,6 +272,7 @@ void test_url_scp__malformed_ipv6_two(void) cl_assert_equal_p(conndata.username, NULL); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__malformed_ipv6_with_user(void) @@ -253,6 +285,7 @@ void test_url_scp__malformed_ipv6_with_user(void) cl_assert_equal_s(conndata.username, "git"); cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); + cl_assert_equal_i(conndata.port_specified, 0); } void test_url_scp__invalid_addresses(void) From 0db62c889c161d64e53a87562f5e6c3972f69db3 Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Fri, 12 Jul 2024 16:28:06 -0400 Subject: [PATCH 543/816] Use `git__malloc` and `git__free` over `malloc` and `free` --- src/libgit2/streams/stransport.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index b30cb8f3c1f..7c06fd574ea 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -15,6 +15,8 @@ #include "git2/transport.h" +#include "../util/alloc.h" + #include "streams/socket.h" static int stransport_error(OSStatus ret) @@ -50,7 +52,8 @@ static int stransport_error(OSStatus ret) long buffer_size = CFStringGetLength(message) * 2 + 1; /* Allocate the buffer. */ - message_c_str = malloc((size_t) buffer_size); + message_c_str = git__malloc((size_t) buffer_size); + GIT_ERROR_CHECK_ALLOC(message_c_str); /* Convert the string into a C string using the buffer. @@ -59,7 +62,7 @@ static int stransport_error(OSStatus ret) */ if (!CFStringGetCString(message, message_c_str, buffer_size, kCFStringEncodingUTF8)) { git_error_set(GIT_ERROR_NET, "CFStringGetCString error while handling a SecureTransport error"); - free(message_c_str); + git__free(message_c_str); CFRelease(message); return -1; } @@ -69,7 +72,7 @@ static int stransport_error(OSStatus ret) /* If we decided earlier that we would have to free the buffer allocation, do that. */ if (must_free) { - free(message_c_str); + git__free(message_c_str); } CFRelease(message); From c77c598c606d0b30da9d563251aad5f353591d99 Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Fri, 12 Jul 2024 17:46:28 -0400 Subject: [PATCH 544/816] Add tracing info to specific SecureTransport error caused by `SSLRead` returning -9806. --- src/libgit2/streams/stransport.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 7c06fd574ea..9f45110ddd3 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -16,6 +16,7 @@ #include "git2/transport.h" #include "../util/alloc.h" +#include "../trace.h" #include "streams/socket.h" @@ -282,6 +283,18 @@ static ssize_t stransport_read(git_stream *stream, void *data, size_t len) OSStatus ret; if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr) { + /* + This specific SecureTransport error is not well described by SecCopyErrorMessageString, + so we should at least log something to the user here so that they might see this if + they're running into the same error I am and they have tracing enabled. + */ + if (ret == -9806) { + git_trace(GIT_TRACE_FATAL, "SecureTransport error: SSLRead error: SSLRead returned -9806 (connection closed via error)."); + git_trace(GIT_TRACE_FATAL, "This means that the remote terminated the SSL connection due to an error."); + git_trace(GIT_TRACE_FATAL, "This is *possibly* similar to https://stackoverflow.com/questions/26461966/osx-10-10-curl-post-to-https-url-gives-sslread-error"); + git_trace(GIT_TRACE_FATAL, "You may find some valuable information running `security error -9806` (on macOS)."); + } + if (st->error == GIT_TIMEOUT) return GIT_TIMEOUT; From 3f6177e6344fa30983f47bb524220909128346c1 Mon Sep 17 00:00:00 2001 From: Benjamin Nickolls Date: Wed, 17 Jul 2024 10:38:12 +0100 Subject: [PATCH 545/816] Create FUNDING.json Add Open Source Collective-owned wallet address to claim project on Drips --- FUNDING.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 FUNDING.json diff --git a/FUNDING.json b/FUNDING.json new file mode 100644 index 00000000000..eb2f6310368 --- /dev/null +++ b/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0x939121dD13f796C69d0Ac4185787285518081f8D" + } + } +} From ed520ff80556cc312255b4ade6d998c327216280 Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 16 Aug 2024 16:41:17 +0800 Subject: [PATCH 546/816] Fix contradictory phrase in SECURITY.md --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index f98eebf505a..914e660b26d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ This project will always provide security fixes for the latest two released versions. E.g. if the latest version is v0.28.x, then we will provide security -fixes for both v0.28.x and v0.27.y, but no later versions. +fixes for both v0.28.x and v0.27.y, but no earlier versions. ## Reporting a Vulnerability From 30f92e8345b5f0e40834c89abc52cc042e022852 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 17 Aug 2024 17:14:40 +0800 Subject: [PATCH 547/816] Fix small issue on README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0c997ada28..e4949154108 100644 --- a/README.md +++ b/README.md @@ -290,7 +290,7 @@ To list all build options and their current value, you can do the following: # Create and set up a build directory - $ mkdir build + $ mkdir build && cd build $ cmake .. # List all build options and their values $ cmake -L From c48536607a97b79ab88746b3d1481acd3f822df1 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 17 Aug 2024 17:15:06 +0800 Subject: [PATCH 548/816] Update macOS section of README.md --- README.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e4949154108..4d84df521c1 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Table of Contents * [Installation](#installation) * [Advanced Usage](#advanced-usage) * [Compiler and linker options](#compiler-and-linker-options) - * [MacOS X](#macos-x) + * [macOS](#macos) * [Android](#android) * [MinGW](#mingw) * [Language Bindings](#language-bindings) @@ -309,12 +309,25 @@ Tell CMake where to find those specific libraries - `LINK_WITH_STATIC_LIBRARIES`: Link only with static versions of system libraries -MacOS X +macOS ------- -If you want to build a universal binary for Mac OS X, CMake sets it -all up for you if you use `-DCMAKE_OSX_ARCHITECTURES="i386;x86_64"` -when configuring. +If you'd like to work with Xcode, you can generate an Xcode project with "-G Xcode". + + # Create and set up a build directory + $ mkdir build && cd build + $ cmake -G Xcode .. + +> [!TIP] +> Universal binary support: +> +> If you want to build a universal binary for macOS 11.0+, CMake sets it +> all up for you if you use `-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"` +> when configuring. +> +> [Deprecated] If you want to build a universal binary for Mac OS X +> (10.4.4 ~ 10.6), CMake sets it all up for you if you use +> `-DCMAKE_OSX_ARCHITECTURES="i386;x86_64"` when configuring. Android ------- From 782e29c906f6e44b120843356f286b6a97d89f88 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 22 Aug 2024 13:10:29 +0100 Subject: [PATCH 549/816] ci: only publish benchmarks from libgit2/libgit2 Benchmark runs are trying to be pushed from repos that _aren't_ libgit2/libgit2. Try again with the syntax. --- .github/workflows/benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 6ee492ac443..450562a5237 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -89,7 +89,7 @@ jobs: publish: name: Publish results needs: [ build ] - if: ${{ always() && github.repository == 'libgit2/libgit2' }} + if: always() && github.repository == 'libgit2/libgit2' runs-on: ubuntu-latest steps: - name: Check out benchmark repository From ea7e18eef589a061e0a9878f3e8c198d769d11df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Wed, 28 Aug 2024 15:28:35 +0200 Subject: [PATCH 550/816] =?UTF-8?q?http:=20Initialize=20=E2=80=98on=5Fstat?= =?UTF-8?q?us=E2=80=99=20when=20using=20the=20http-parser=20backend.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a bug likely introduced in d396819101a67c652af0fa0ae65cda19a2c0430a (in 1.8.1) whereby ‘proxy_settings.on_status’ would be left uninitialized when using the ‘http-parser’ backend, eventually leading to a segfault in ‘http_parser_execute’. Valgrind would report use of the uninitialized value like so: Conditional jump or move depends on uninitialised value(s) at 0x50CD533: http_parser_execute (http_parser.c:910) by 0x4928504: git_http_parser_execute (httpparser.c:82) by 0x4925C42: client_read_and_parse (httpclient.c:1178) by 0x4926F27: git_http_client_read_response (httpclient.c:1458) by 0x49255FE: http_stream_read (http.c:427) by 0x4929B90: git_smart__recv (smart.c:29) by 0x492C147: git_smart__store_refs (smart_protocol.c:58) by 0x4929F6C: git_smart__connect (smart.c:171) by 0x4904DCE: git_remote_connect_ext (remote.c:963) by 0x48A15D2: clone_into (clone.c:449) by 0x48A15D2: git__clone (clone.c:546) by 0x4010E9: main (libgit2-proxy.c:20) --- src/libgit2/transports/httpparser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libgit2/transports/httpparser.c b/src/libgit2/transports/httpparser.c index 50ba6d2e0cd..c19499b84f4 100644 --- a/src/libgit2/transports/httpparser.c +++ b/src/libgit2/transports/httpparser.c @@ -71,6 +71,7 @@ size_t git_http_parser_execute( { struct http_parser_settings settings_proxy; + settings_proxy.on_status = NULL; settings_proxy.on_message_begin = parser->settings.on_message_begin ? on_message_begin : NULL; settings_proxy.on_url = parser->settings.on_url ? on_url : NULL; settings_proxy.on_header_field = parser->settings.on_header_field ? on_header_field : NULL; @@ -78,6 +79,8 @@ size_t git_http_parser_execute( settings_proxy.on_headers_complete = parser->settings.on_headers_complete ? on_headers_complete : NULL; settings_proxy.on_body = parser->settings.on_body ? on_body : NULL; settings_proxy.on_message_complete = parser->settings.on_message_complete ? on_message_complete : NULL; + settings_proxy.on_chunk_header = NULL; + settings_proxy.on_chunk_complete = NULL; return http_parser_execute(&parser->parser, &settings_proxy, data, len); } From e3597e9ff5ebc3807d8b78cfdea5c5e4512d9268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Thu, 29 Aug 2024 20:38:55 +0000 Subject: [PATCH 551/816] Apply suggestions from code review Co-authored-by: Edward Thomson --- src/libgit2/transports/httpparser.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libgit2/transports/httpparser.c b/src/libgit2/transports/httpparser.c index c19499b84f4..84833e61737 100644 --- a/src/libgit2/transports/httpparser.c +++ b/src/libgit2/transports/httpparser.c @@ -71,7 +71,8 @@ size_t git_http_parser_execute( { struct http_parser_settings settings_proxy; - settings_proxy.on_status = NULL; + memset(&settings_proxy, 0, sizeof(struct http_parser_settings)); + settings_proxy.on_message_begin = parser->settings.on_message_begin ? on_message_begin : NULL; settings_proxy.on_url = parser->settings.on_url ? on_url : NULL; settings_proxy.on_header_field = parser->settings.on_header_field ? on_header_field : NULL; @@ -79,8 +80,6 @@ size_t git_http_parser_execute( settings_proxy.on_headers_complete = parser->settings.on_headers_complete ? on_headers_complete : NULL; settings_proxy.on_body = parser->settings.on_body ? on_body : NULL; settings_proxy.on_message_complete = parser->settings.on_message_complete ? on_message_complete : NULL; - settings_proxy.on_chunk_header = NULL; - settings_proxy.on_chunk_complete = NULL; return http_parser_execute(&parser->parser, &settings_proxy, data, len); } From ab1b7aded5f20401b2d0e8dbc26f04e9f350f051 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Mon, 2 Sep 2024 17:09:13 +0200 Subject: [PATCH 552/816] Make packbuilder interruptible using progress callback Specifically, forward errors from packbuilder->progress_cb This allows the callback to gracefully terminate long-running operations when the application is interrupted. Interruption could be ^C in the terminal, but this could be any other condition or event, as this is up to the callback function to implement. --- include/git2/pack.h | 3 ++ src/libgit2/pack-objects.c | 56 ++++++++++++++++++++++++++------------ src/libgit2/pack-objects.h | 4 +++ 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/include/git2/pack.h b/include/git2/pack.h index 0f6bd2ab928..bee72a6c085 100644 --- a/include/git2/pack.h +++ b/include/git2/pack.h @@ -247,6 +247,9 @@ typedef int GIT_CALLBACK(git_packbuilder_progress)( * @param progress_cb Function to call with progress information during * pack building. Be aware that this is called inline with pack building * operations, so performance may be affected. + * When progress_cb returns an error, the pack building process will be + * aborted and the error will be returned from the invoked function. + * `pb` must then be freed. * @param progress_cb_payload Payload for progress callback. * @return 0 or an error code */ diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index b2d80cba954..7c331c2d547 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -932,6 +932,9 @@ static int report_delta_progress( { int ret; + if (pb->failure) + return pb->failure; + if (pb->progress_cb) { uint64_t current_time = git_time_monotonic(); uint64_t elapsed = current_time - pb->last_progress_report_time; @@ -943,8 +946,10 @@ static int report_delta_progress( GIT_PACKBUILDER_DELTAFICATION, count, pb->nr_objects, pb->progress_cb_payload); - if (ret) + if (ret) { + pb->failure = ret; return git_error_set_after_callback(ret); + } } } @@ -976,7 +981,10 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list, } pb->nr_deltified += 1; - report_delta_progress(pb, pb->nr_deltified, false); + if ((error = report_delta_progress(pb, pb->nr_deltified, false)) < 0) { + GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0); + goto on_error; + } po = *list++; (*list_size)--; @@ -1124,6 +1132,10 @@ struct thread_params { size_t depth; size_t working; size_t data_ready; + + /* A pb->progress_cb can stop the packing process by returning an error. + When that happens, all threads observe the error and stop voluntarily. */ + bool stopped; }; static void *threaded_find_deltas(void *arg) @@ -1133,7 +1145,12 @@ static void *threaded_find_deltas(void *arg) while (me->remaining) { if (find_deltas(me->pb, me->list, &me->remaining, me->window, me->depth) < 0) { - ; /* TODO */ + me->stopped = true; + GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_lock(me->pb) == 0, NULL); + me->working = false; + git_cond_signal(&me->pb->progress_cond); + GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_unlock(me->pb) == 0, NULL); + return NULL; } GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_lock(me->pb) == 0, NULL); @@ -1175,8 +1192,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, pb->nr_threads = git__online_cpus(); if (pb->nr_threads <= 1) { - find_deltas(pb, list, &list_size, window, depth); - return 0; + return find_deltas(pb, list, &list_size, window, depth); } p = git__mallocarray(pb->nr_threads, sizeof(*p)); @@ -1195,6 +1211,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, p[i].depth = depth; p[i].working = 1; p[i].data_ready = 0; + p[i].stopped = 0; /* try to split chunks on "path" boundaries */ while (sub_size && sub_size < list_size && @@ -1262,7 +1279,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, (!victim || victim->remaining < p[i].remaining)) victim = &p[i]; - if (victim) { + if (victim && !target->stopped) { sub_size = victim->remaining / 2; list = victim->list + victim->list_size - sub_size; while (sub_size && list[0]->hash && @@ -1286,7 +1303,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, } target->list_size = sub_size; target->remaining = sub_size; - target->working = 1; + target->working = 1; /* even when target->stopped, so that we don't process this thread again */ GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0); if (git_mutex_lock(&target->mutex)) { @@ -1299,7 +1316,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, git_cond_signal(&target->cond); git_mutex_unlock(&target->mutex); - if (!sub_size) { + if (target->stopped || !sub_size) { git_thread_join(&target->thread, NULL); git_cond_free(&target->cond); git_mutex_free(&target->mutex); @@ -1308,7 +1325,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, } git__free(p); - return 0; + return pb->failure; } #else @@ -1319,6 +1336,7 @@ int git_packbuilder__prepare(git_packbuilder *pb) { git_pobject **delta_list; size_t i, n = 0; + int error; if (pb->nr_objects == 0 || pb->done) return 0; /* nothing to do */ @@ -1327,8 +1345,10 @@ int git_packbuilder__prepare(git_packbuilder *pb) * Although we do not report progress during deltafication, we * at least report that we are in the deltafication stage */ - if (pb->progress_cb) - pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload); + if (pb->progress_cb) { + if ((error = pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload)) < 0) + return git_error_set_after_callback(error); + } delta_list = git__mallocarray(pb->nr_objects, sizeof(*delta_list)); GIT_ERROR_CHECK_ALLOC(delta_list); @@ -1345,31 +1365,33 @@ int git_packbuilder__prepare(git_packbuilder *pb) if (n > 1) { git__tsort((void **)delta_list, n, type_size_sort); - if (ll_find_deltas(pb, delta_list, n, + if ((error = ll_find_deltas(pb, delta_list, n, GIT_PACK_WINDOW + 1, - GIT_PACK_DEPTH) < 0) { + GIT_PACK_DEPTH)) < 0) { git__free(delta_list); - return -1; + return error; } } - report_delta_progress(pb, pb->nr_objects, true); + error = report_delta_progress(pb, pb->nr_objects, true); pb->done = true; git__free(delta_list); - return 0; + return error; } -#define PREPARE_PACK if (git_packbuilder__prepare(pb) < 0) { return -1; } +#define PREPARE_PACK error = git_packbuilder__prepare(pb); if (error < 0) { return error; } int git_packbuilder_foreach(git_packbuilder *pb, int (*cb)(void *buf, size_t size, void *payload), void *payload) { + int error; PREPARE_PACK; return write_pack(pb, cb, payload); } int git_packbuilder__write_buf(git_str *buf, git_packbuilder *pb) { + int error; PREPARE_PACK; return write_pack(pb, &write_pack_buf, buf); diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h index bbc8b9430ee..380a28ebe1f 100644 --- a/src/libgit2/pack-objects.h +++ b/src/libgit2/pack-objects.h @@ -100,6 +100,10 @@ struct git_packbuilder { uint64_t last_progress_report_time; bool done; + + /* A non-zero error code in failure causes all threads to shut themselves + down. Some functions will return this error code. */ + volatile int failure; }; int git_packbuilder__write_buf(git_str *buf, git_packbuilder *pb); From e5da88135cafac2f4615f146ed05177e686d860d Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 17 Aug 2024 18:22:48 +0800 Subject: [PATCH 553/816] Add iOS build instruction in README --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 4d84df521c1..afeaeaaa38f 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Table of Contents * [Advanced Usage](#advanced-usage) * [Compiler and linker options](#compiler-and-linker-options) * [macOS](#macos) + * [iOS](#ios) * [Android](#android) * [MinGW](#mingw) * [Language Bindings](#language-bindings) @@ -329,6 +330,30 @@ If you'd like to work with Xcode, you can generate an Xcode project with "-G Xco > (10.4.4 ~ 10.6), CMake sets it all up for you if you use > `-DCMAKE_OSX_ARCHITECTURES="i386;x86_64"` when configuring. +iOS +------- + +1. Get an iOS cmake toolchain File: + +You can use a pre-existing toolchain file like [ios-cmake](https://github.com/leetal/ios-cmake) or write your own. + +2. Specify the toolchain and system Name: + +- The CMAKE_TOOLCHAIN_FILE variable points to the toolchain file for iOS. +- The CMAKE_SYSTEM_NAME should be set to iOS. + +3. Example Command: + +Assuming you're using the ios-cmake toolchain, the command might look like this: + +``` +cmake -G Xcode -DCMAKE_TOOLCHAIN_FILE=path/to/ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 .. +``` + +4. Build the Project: + +After generating the project, open the .xcodeproj file in Xcode, select your iOS device or simulator as the target, and build your project. + Android ------- From 4b63eb5dc8c24a6bd1b9a4ca2aeb4d57a31cfa73 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 17 Aug 2024 18:22:57 +0800 Subject: [PATCH 554/816] Fix iOS build issue --- cmake/SelectGSSAPI.cmake | 2 +- cmake/SelectHTTPSBackend.cmake | 2 +- src/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/SelectGSSAPI.cmake b/cmake/SelectGSSAPI.cmake index 5bde11697df..829850a4de9 100644 --- a/cmake/SelectGSSAPI.cmake +++ b/cmake/SelectGSSAPI.cmake @@ -2,7 +2,7 @@ include(SanitizeBool) # We try to find any packages our backends might use find_package(GSSAPI) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin") +if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "iOS") include(FindGSSFramework) endif() diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index d293001f567..61bc763fce5 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -3,7 +3,7 @@ include(SanitizeBool) # We try to find any packages our backends might use find_package(OpenSSL) find_package(mbedTLS) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin") +if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "iOS") find_package(Security) find_package(CoreFoundation) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed3f4a51427..51fc67757e2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -201,7 +201,7 @@ add_feature_info(iconv GIT_USE_ICONV "iconv encoding conversion support") add_subdirectory(libgit2) add_subdirectory(util) -if(BUILD_CLI) +if(BUILD_CLI AND NOT CMAKE_SYSTEM_NAME MATCHES "iOS") add_subdirectory(cli) endif() From 8957d362280713241b507f74f1b06b68cb5ab977 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 17 Aug 2024 18:28:36 +0800 Subject: [PATCH 555/816] Add SecCopyErrorMessageString API when building for iOS SecCopyErrorMessageString is supported since iOS 11.3. I believe we do not need to use #if check here since the default IPHONEOS_DEPLOYMENT_TARGET is iOS 13.0 for Xcode 15.3. --- src/libgit2/streams/stransport.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 7a3585e246b..1b9fff584a4 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -26,16 +26,11 @@ static int stransport_error(OSStatus ret) return 0; } -#if !TARGET_OS_IPHONE message = SecCopyErrorMessageString(ret, NULL); GIT_ERROR_CHECK_ALLOC(message); git_error_set(GIT_ERROR_NET, "SecureTransport error: %s", CFStringGetCStringPtr(message, kCFStringEncodingUTF8)); CFRelease(message); -#else - git_error_set(GIT_ERROR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret); - GIT_UNUSED(message); -#endif return -1; } From 06a9dc995ac1e012426b46214859386e4599423d Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 17 Aug 2024 19:02:38 +0800 Subject: [PATCH 556/816] Add iOS CI support --- .github/workflows/main.yml | 11 +++++++++++ ci/setup-ios-benchmark.sh | 6 ++++++ ci/setup-ios-build.sh | 10 ++++++++++ 3 files changed, 27 insertions(+) create mode 100755 ci/setup-ios-benchmark.sh create mode 100755 ci/setup-ios-build.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 87e834f10db..8d71bea9c71 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -73,6 +73,17 @@ jobs: PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + - name: "iOS" + id: ios + os: macos-14 + setup-script: ios + env: + CC: clang + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 + CMAKE_GENERATOR: Ninja + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs os: windows-2019 diff --git a/ci/setup-ios-benchmark.sh b/ci/setup-ios-benchmark.sh new file mode 100755 index 00000000000..80d87682b3e --- /dev/null +++ b/ci/setup-ios-benchmark.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +set -ex + +brew update +brew install hyperfine diff --git a/ci/setup-ios-build.sh b/ci/setup-ios-build.sh new file mode 100755 index 00000000000..94af4e486de --- /dev/null +++ b/ci/setup-ios-build.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -ex + +brew update +brew install pkgconfig libssh2 ninja + +ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib + +curl -s -L https://raw.githubusercontent.com/leetal/ios-cmake/master/ios.toolchain.cmake -o ios.toolchain.cmake From 60cdd25709f7ee166d47e869aa30abf845671d85 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 18 Aug 2024 12:00:09 +0800 Subject: [PATCH 557/816] =?UTF-8?q?Align=20the=20iOS=20CI=E2=80=99s=20host?= =?UTF-8?q?=20OS=20version=20to=20fix=20the=20permission=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8d71bea9c71..bef7873aeaa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -75,7 +75,7 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "iOS" id: ios - os: macos-14 + os: macos-12 setup-script: ios env: CC: clang From 07bb47ca5ca56f3139938d3e5592223c0997765b Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 24 Aug 2024 11:42:39 +0800 Subject: [PATCH 558/816] Fix CI toolchain file location issue --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bef7873aeaa..7a570462270 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -79,7 +79,7 @@ jobs: setup-script: ios env: CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true From 841164ec395770cd2701e17a739ee6219309b945 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 24 Aug 2024 12:03:36 +0800 Subject: [PATCH 559/816] Fix regcomp_l compile issue --- .github/workflows/main.yml | 2 +- ci/setup-ios-build.sh | 2 ++ cmake/SelectRegex.cmake | 11 ++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7a570462270..f6abfcdeadb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -79,7 +79,7 @@ jobs: setup-script: ios env: CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true diff --git a/ci/setup-ios-build.sh b/ci/setup-ios-build.sh index 94af4e486de..195106c51fd 100755 --- a/ci/setup-ios-build.sh +++ b/ci/setup-ios-build.sh @@ -7,4 +7,6 @@ brew install pkgconfig libssh2 ninja ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib +# The above is copied from setup-osx-build.sh + curl -s -L https://raw.githubusercontent.com/leetal/ios-cmake/master/ios.toolchain.cmake -o ios.toolchain.cmake diff --git a/cmake/SelectRegex.cmake b/cmake/SelectRegex.cmake index 2a3a91b8cd3..0e34b733059 100644 --- a/cmake/SelectRegex.cmake +++ b/cmake/SelectRegex.cmake @@ -5,7 +5,16 @@ if(REGEX_BACKEND STREQUAL "") check_symbol_exists(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L) if(HAVE_REGCOMP_L) - set(REGEX_BACKEND "regcomp_l") + if(CMAKE_SYSTEM_NAME MATCHES "iOS") + # 'regcomp_l' has been explicitly marked unavailable on iOS_SDK + # /usr/include/xlocale/_regex.h:34:5: + # int regcomp_l(regex_t * __restrict, const char * __restrict, int, + # locale_t __restrict) + # __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_NA); + set(REGEX_BACKEND "regcomp") + else() + set(REGEX_BACKEND "regcomp_l") + endif() elseif(PCRE_FOUND) set(REGEX_BACKEND "pcre") else() From 871208e9914b43b4e3257d9076fde90cc5388cf4 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 5 Sep 2024 13:53:14 +0800 Subject: [PATCH 560/816] Fix iconv link issue --- cmake/FindIntlIconv.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/FindIntlIconv.cmake b/cmake/FindIntlIconv.cmake index 9e6ded99dc4..07959ca1a19 100644 --- a/cmake/FindIntlIconv.cmake +++ b/cmake/FindIntlIconv.cmake @@ -15,6 +15,12 @@ find_path(ICONV_INCLUDE_DIR iconv.h) check_function_exists(iconv_open libc_has_iconv) find_library(iconv_lib NAMES iconv libiconv libiconv-2 c) +# workaround the iOS issue where iconv is provided by libc +# We set it to false to force it add -liconv to the linker flags +if(CMAKE_SYSTEM_NAME MATCHES "iOS") + set(libc_has_iconv FALSE) +endif() + if(ICONV_INCLUDE_DIR AND libc_has_iconv) set(ICONV_FOUND TRUE) set(ICONV_LIBRARIES "") From 7fb1c8edcf1ed0de64c65aafa1c4f64ce4cadc3b Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 5 Sep 2024 14:03:30 +0800 Subject: [PATCH 561/816] Fix system API issue --- tests/clar/main.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/clar/main.c b/tests/clar/main.c index e3f4fe740bd..0a3ca354d3c 100644 --- a/tests/clar/main.c +++ b/tests/clar/main.c @@ -10,6 +10,15 @@ int __cdecl main(int argc, char *argv[]) #else int main(int argc, char *argv[]) #endif + +#if defined(__APPLE__) +#include +#else +#if !defined(TARGET_OS_IOS) +#define TARGET_OS_IOS 0 +#endif +#endif + { int res; char *at_exit_cmd; @@ -44,9 +53,13 @@ int main(int argc, char *argv[]) at_exit_cmd = getenv("CLAR_AT_EXIT"); if (at_exit_cmd != NULL) { + #if TARGET_OS_IOS + /* system is unavailable on iOS */ + return res; + #else int at_exit = system(at_exit_cmd); return res || at_exit; + #endif } - return res; } From b83d55c7550296060ca48d2e84395b6d8241c37c Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 5 Sep 2024 23:31:34 +0800 Subject: [PATCH 562/816] Fix rt linker issue --- src/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 51fc67757e2..2517df22fe9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -127,6 +127,13 @@ endif() # realtime support check_library_exists(rt clock_gettime "time.h" NEED_LIBRT) + +# workaround the iOS issue where clock_gettime is provided +# But we can't find rt library for some reason +if(CMAKE_SYSTEM_NAME MATCHES "iOS") + set(NEED_LIBRT FALSE) +endif() + if(NEED_LIBRT) list(APPEND LIBGIT2_SYSTEM_LIBS rt) list(APPEND LIBGIT2_PC_LIBS "-lrt") From 10c424ffc3c04d95e64810efb0791ae66571420e Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 6 Sep 2024 00:41:00 +0800 Subject: [PATCH 563/816] Skip all test on iOS temporarily --- .github/workflows/main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f6abfcdeadb..b42a5c992b6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -82,8 +82,10 @@ jobs: CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true + # Skip all tests on iOS temporarily. + # 1. We need to update the path from libgit2_tests to libgit2_tests.app/libgit2_tests + # 2. We need to find a way to specify an iOS device / iOS simulator to run the tests. + SKIP_TESTS: true - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs os: windows-2019 From a65fa028776b5a45d6655dc638b36378aa3bea9f Mon Sep 17 00:00:00 2001 From: Sergey Kazmin <43613813+yerseg@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:43:18 +0300 Subject: [PATCH 564/816] push: report a push status even the push has failed --- src/libgit2/remote.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 8b486ea3550..e74b7061af6 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2998,6 +2998,14 @@ int git_remote_upload( (error = git_push_status_foreach(push, connect_opts.callbacks.push_update_reference, connect_opts.callbacks.payload)) < 0) goto cleanup; + error = git_push_finish(push); + + if (connect_opts.callbacks.push_update_reference) { + const int cb_error = git_push_status_foreach(push, connect_opts.callbacks.push_update_reference, connect_opts.callbacks.payload); + if (!error) + error = cb_error; + } + cleanup: git_remote_connect_options_dispose(&connect_opts); return error; From 152e2beef6d071a53f994906b96883ade6a751ea Mon Sep 17 00:00:00 2001 From: Sergey Kazmin Date: Fri, 6 Sep 2024 14:41:48 +0300 Subject: [PATCH 565/816] fix --- src/libgit2/remote.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index e74b7061af6..63f63e81b56 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2991,13 +2991,6 @@ int git_remote_upload( goto cleanup; } - if ((error = git_push_finish(push)) < 0) - goto cleanup; - - if (connect_opts.callbacks.push_update_reference && - (error = git_push_status_foreach(push, connect_opts.callbacks.push_update_reference, connect_opts.callbacks.payload)) < 0) - goto cleanup; - error = git_push_finish(push); if (connect_opts.callbacks.push_update_reference) { From ad04bf2566ff0477abff8c32662853c2ecc582a7 Mon Sep 17 00:00:00 2001 From: Sergey Kazmin Date: Fri, 6 Sep 2024 14:59:37 +0300 Subject: [PATCH 566/816] ssl: ability to add raw X509 certs to the cert store --- include/git2/common.h | 7 +++++++ src/libgit2/settings.c | 12 ++++++++++++ src/libgit2/streams/openssl.c | 18 ++++++++++++++++++ src/libgit2/streams/openssl.h | 1 + 4 files changed, 38 insertions(+) diff --git a/include/git2/common.h b/include/git2/common.h index b7cf20b31c9..400f2f611e4 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -199,6 +199,7 @@ typedef enum { GIT_OPT_GET_TEMPLATE_PATH, GIT_OPT_SET_TEMPLATE_PATH, GIT_OPT_SET_SSL_CERT_LOCATIONS, + GIT_OPT_ADD_SSL_X509_CERT, GIT_OPT_SET_USER_AGENT, GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, @@ -336,6 +337,12 @@ typedef enum { * > certificates, one per file. * > * > Either parameter may be `NULL`, but not both. + * + * * opts(GIT_OPT_ADD_SSL_X509_CERT, const X509 *cert) + * + * > Add a raw X509 certificate into the SSL certs store. + * > + * > - `cert` is the raw X509 cert will be added to cert store. * * * opts(GIT_OPT_SET_USER_AGENT, const char *user_agent) * diff --git a/src/libgit2/settings.c b/src/libgit2/settings.c index 4a41830b8fd..f4c2453a433 100644 --- a/src/libgit2/settings.c +++ b/src/libgit2/settings.c @@ -222,6 +222,18 @@ int git_libgit2_opts(int key, ...) #endif break; + case GIT_OPT_ADD_SSL_X509_CERT: +#ifdef GIT_OPENSSL + { + X509 *cert = va_arg(ap, X509 *); + error = git_openssl__add_x509_cert(cert); + } +#else + git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support adding of the raw certs"); + error = -1; +#endif + break; + case GIT_OPT_SET_USER_AGENT: { const char *new_agent = va_arg(ap, const char *); diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index 7cb8f7f927c..afc43edf3ca 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -722,6 +722,24 @@ int git_openssl__set_cert_location(const char *file, const char *path) return 0; } +int git_openssl__add_x509_cert(X509 *cert) +{ + X509_STORE *cert_store; + + if (openssl_ensure_initialized() < 0) + return -1; + + if (!(cert_store = SSL_CTX_get_cert_store(git__ssl_ctx))) + return -1; + + if (cert && X509_STORE_add_cert(cert_store, cert) == 0) { + git_error_set(GIT_ERROR_SSL, "OpenSSL error: failed to add raw X509 certificate"); + return -1; + } + + return 0; +} + #else #include "stream.h" diff --git a/src/libgit2/streams/openssl.h b/src/libgit2/streams/openssl.h index 89fb60a82ee..e503cbc6df6 100644 --- a/src/libgit2/streams/openssl.h +++ b/src/libgit2/streams/openssl.h @@ -24,6 +24,7 @@ extern int git_openssl_stream_global_init(void); #ifdef GIT_OPENSSL extern int git_openssl__set_cert_location(const char *file, const char *path); +extern int git_openssl__add_x509_cert(X509 *cert); extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port); extern int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host); #endif From 6c9ef79aeb84d48617fc14530561a75fcf151358 Mon Sep 17 00:00:00 2001 From: Sergey Kazmin Date: Mon, 9 Sep 2024 11:11:39 +0300 Subject: [PATCH 567/816] more verbose doc --- include/git2/common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/git2/common.h b/include/git2/common.h index 400f2f611e4..8566b290ece 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -341,6 +341,10 @@ typedef enum { * * opts(GIT_OPT_ADD_SSL_X509_CERT, const X509 *cert) * * > Add a raw X509 certificate into the SSL certs store. + * > The added certificate is not persisted and will be used + * > only during application lifetime. Also there is no ability + * > to remove a certificate from the store during app lifetime + * > after it was added. * > * > - `cert` is the raw X509 cert will be added to cert store. * From 88bd589f7c01a9106c74f09815c8a0e5ca066b67 Mon Sep 17 00:00:00 2001 From: Hamed Masafi Date: Sat, 14 Sep 2024 12:03:17 +0330 Subject: [PATCH 568/816] Add VER_CHECK macro --- include/git2/version.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/git2/version.h b/include/git2/version.h index 60675c88be5..714e2d20e6a 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -40,4 +40,20 @@ */ #define LIBGIT2_SOVERSION "1.8" +/* + * LIBGIT2_VERSION_CHECK: + * This macro can be used to compare against a specific libgit2 version. + * It takes the major, minor, and patch version as parameters. + * + * Usage Example: + * + * #if LIBGIT2_VERSION_CHECK(1, 7, 0) >= LIBGIT2_VERSION_NUMBER + * // This code will only compile if libgit2 version is >= 1.7.0 + * #endif + */ +#define LIBGIT2_VER_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +/* Macro to get the current version as a single integer */ +#define LIBGIT2_VER_NUMBER LIBGIT2_VERSION_CHECK(LIBGIT2_VER_MAJOR, LIBGIT2_VER_MINOR, LIBGIT2_VER_PATCH) + #endif From 34432d99e788dc5a7257d736a15b195ca792fe91 Mon Sep 17 00:00:00 2001 From: lstoppa <77723162+lstoppa@users.noreply.github.com> Date: Fri, 20 Sep 2024 23:22:59 +0200 Subject: [PATCH 569/816] Fix leak in truncate_racily_clean in index.c In truncate_racily_clean, when git_diff_index_to_workdir fails, we leak the local variable git_vector paths. --- src/libgit2/index.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 670fbc5cf15..fe6f72ab3db 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -786,8 +786,10 @@ static int truncate_racily_clean(git_index *index) diff_opts.pathspec.count = paths.length; diff_opts.pathspec.strings = (char **)paths.contents; - if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0) - return error; + if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0) { + git_vector_free(&paths); + return error; + } git_vector_foreach(&diff->deltas, i, delta) { entry = (git_index_entry *)git_index_get_bypath(index, delta->old_file.path, 0); From d2389b2caae065c1c4bcbc16dd4d19a23100ebed Mon Sep 17 00:00:00 2001 From: Jaeyong Choi Date: Thu, 4 Jul 2024 10:49:34 +0900 Subject: [PATCH 570/816] ssh: Omit port option from ssh command unless specified in remote url Omit `-p 22` option from ssh command by default. Adding `-p 22` option when a port is not in a remote url causes that `Port` option in a ssh config is ignored. --- src/libgit2/transports/ssh_exec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c index a09c1db9441..5b4bbb87e2d 100644 --- a/src/libgit2/transports/ssh_exec.c +++ b/src/libgit2/transports/ssh_exec.c @@ -158,9 +158,10 @@ static int get_ssh_cmdline( else if ((error = git_config__get_string_buf(&ssh_cmd, cfg, "core.sshcommand")) < 0 && error != GIT_ENOTFOUND) goto done; - error = git_str_printf(out, "%s -p %s \"%s%s%s\" \"%s\" \"%s\"", + error = git_str_printf(out, "%s %s %s \"%s%s%s\" \"%s\" \"%s\"", ssh_cmd.size > 0 ? ssh_cmd.ptr : default_ssh_cmd, - url->port, + url->port_specified ? "-p" : "", + url->port_specified ? url->port : "", url->username ? url->username : "", url->username ? "@" : "", url->host, From b139fe04a48e5595a7be0742046d7c7169b3dffb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 24 Sep 2024 14:01:30 +0200 Subject: [PATCH 571/816] repo: support the preciousObjects extension libgit2 implicitly supports precious objects, since there's no gc command, nor even any option in our object database functionality to delete an object from the odb. In the future, when we support deleting objects, or a gc functionality, we will need to honor the preciousObjects extension and reject those APIs when it is set. In the meantime, since users cannot use libgit2 (directly) to delete an object, we can simply add this to our allowlist. --- src/libgit2/repository.c | 1 + tests/libgit2/core/opts.c | 20 ++++++++++++-------- tests/libgit2/repo/extensions.c | 10 ++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 8e449a6df09..1277d7a2821 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1881,6 +1881,7 @@ static const char *builtin_extensions[] = { "noop", "objectformat", "worktreeconfig", + "preciousobjects" }; static git_vector user_extensions = { 0, git__strcmp_cb }; diff --git a/tests/libgit2/core/opts.c b/tests/libgit2/core/opts.c index cbef29f991d..1580fb2f5dc 100644 --- a/tests/libgit2/core/opts.c +++ b/tests/libgit2/core/opts.c @@ -34,10 +34,11 @@ void test_core_opts__extensions_query(void) cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 3); + cl_assert_equal_sz(out.count, 4); cl_assert_equal_s("noop", out.strings[0]); cl_assert_equal_s("objectformat", out.strings[1]); - cl_assert_equal_s("worktreeconfig", out.strings[2]); + cl_assert_equal_s("preciousobjects", out.strings[2]); + cl_assert_equal_s("worktreeconfig", out.strings[3]); git_strarray_dispose(&out); } @@ -50,11 +51,12 @@ void test_core_opts__extensions_add(void) cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 4); + cl_assert_equal_sz(out.count, 5); cl_assert_equal_s("foo", out.strings[0]); cl_assert_equal_s("noop", out.strings[1]); cl_assert_equal_s("objectformat", out.strings[2]); - cl_assert_equal_s("worktreeconfig", out.strings[3]); + cl_assert_equal_s("preciousobjects", out.strings[3]); + cl_assert_equal_s("worktreeconfig", out.strings[4]); git_strarray_dispose(&out); } @@ -67,11 +69,12 @@ void test_core_opts__extensions_remove(void) cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 4); + cl_assert_equal_sz(out.count, 5); cl_assert_equal_s("bar", out.strings[0]); cl_assert_equal_s("baz", out.strings[1]); cl_assert_equal_s("objectformat", out.strings[2]); - cl_assert_equal_s("worktreeconfig", out.strings[3]); + cl_assert_equal_s("preciousobjects", out.strings[3]); + cl_assert_equal_s("worktreeconfig", out.strings[4]); git_strarray_dispose(&out); } @@ -84,12 +87,13 @@ void test_core_opts__extensions_uniq(void) cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in))); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out)); - cl_assert_equal_sz(out.count, 5); + cl_assert_equal_sz(out.count, 6); cl_assert_equal_s("bar", out.strings[0]); cl_assert_equal_s("foo", out.strings[1]); cl_assert_equal_s("noop", out.strings[2]); cl_assert_equal_s("objectformat", out.strings[3]); - cl_assert_equal_s("worktreeconfig", out.strings[4]); + cl_assert_equal_s("preciousobjects", out.strings[4]); + cl_assert_equal_s("worktreeconfig", out.strings[5]); git_strarray_dispose(&out); } diff --git a/tests/libgit2/repo/extensions.c b/tests/libgit2/repo/extensions.c index 105cdae12f4..cb62c53a8eb 100644 --- a/tests/libgit2/repo/extensions.c +++ b/tests/libgit2/repo/extensions.c @@ -70,3 +70,13 @@ void test_repo_extensions__adds_extension(void) cl_assert(git__suffixcmp(git_repository_path(extended), "/") == 0); git_repository_free(extended); } + +void test_repo_extensions__preciousobjects(void) +{ + git_repository *extended = NULL; + + cl_repo_set_string(repo, "extensions.preciousObjects", "true"); + + cl_git_pass(git_repository_open(&extended, "empty_bare.git")); + git_repository_free(extended); +} From a8779b2b67a3c24ff39cc7cc5fc830e63be7c3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 24 Sep 2024 18:47:27 +0200 Subject: [PATCH 572/816] diff: add a test for printing just the header This was a regression leading up to 1.8. --- tests/libgit2/diff/header.c | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/libgit2/diff/header.c diff --git a/tests/libgit2/diff/header.c b/tests/libgit2/diff/header.c new file mode 100644 index 00000000000..b5b73698c32 --- /dev/null +++ b/tests/libgit2/diff/header.c @@ -0,0 +1,69 @@ +#include "clar_libgit2.h" +#include "git2/sys/repository.h" + +#include "diff_helpers.h" +#include "diff.h" +#include "repository.h" + +static git_repository *g_repo = NULL; + +void test_diff_header__initialize(void) +{ +} + +void test_diff_header__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +#define EXPECTED_HEADER "diff --git a/subdir.txt b/subdir.txt\n" \ + "deleted file mode 100644\n" \ + "index e8ee89e..0000000\n" \ + "--- a/subdir.txt\n" \ + "+++ /dev/null\n" + +static int check_header_cb( + const git_diff_delta *delta, + const git_diff_hunk *hunk, + const git_diff_line *line, + void *payload) +{ + int *counter = (int *) payload; + + GIT_UNUSED(delta); + + switch (line->origin) { + case GIT_DIFF_LINE_FILE_HDR: + cl_assert(hunk == NULL); + (*counter)++; + break; + default: + /* unexpected code path */ + return -1; + } + + return 0; +} + +void test_diff_header__can_print_just_headers(void) +{ + const char *one_sha = "26a125e"; + git_tree *one; + git_diff *diff; + int counter = 0; + + g_repo = cl_git_sandbox_init("status"); + + one = resolve_commit_oid_to_tree(g_repo, one_sha); + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, NULL)); + + cl_git_pass(git_diff_print( + diff, GIT_DIFF_FORMAT_PATCH_HEADER, check_header_cb, &counter)); + + cl_assert_equal_i(8, counter); + + git_diff_free(diff); + + git_tree_free(one); +} From 79fec1ada0de7443d193666fba093cd0f0f75eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 24 Sep 2024 19:19:33 +0200 Subject: [PATCH 573/816] diff: print the file header on GIT_DIFF_FORMAT_PATCH_HEADER In `diff_print_patch_file` we try to avoid printing the file if we're not sure that there will be some content. This works fine if we have any later functions that might get called as part of printing. But when given the format `GIT_DIFF_FORMAT_PATCH_HEADER`, this is the only function to get called. Add the binary and hunk functions to those to be called when given this option and have them exit after printing the header. This takes care of printing the header if we would be issuing a hunk, but we skip that part. --- src/libgit2/diff_print.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libgit2/diff_print.c b/src/libgit2/diff_print.c index daeefca50ca..96950cc60ea 100644 --- a/src/libgit2/diff_print.c +++ b/src/libgit2/diff_print.c @@ -667,6 +667,13 @@ static int diff_print_patch_binary( if ((error = flush_file_header(delta, pi)) < 0) return error; + /* + * If the caller only wants the header, we just needed to make sure to + * call flush_file_header + */ + if (pi->format == GIT_DIFF_FORMAT_PATCH_HEADER) + return 0; + git_str_clear(pi->buf); if ((error = diff_print_patch_file_binary( @@ -694,6 +701,13 @@ static int diff_print_patch_hunk( if ((error = flush_file_header(d, pi)) < 0) return error; + /* + * If the caller only wants the header, we just needed to make sure to + * call flush_file_header + */ + if (pi->format == GIT_DIFF_FORMAT_PATCH_HEADER) + return 0; + pi->line.origin = GIT_DIFF_LINE_HUNK_HDR; pi->line.content = h->header; pi->line.content_len = h->header_len; @@ -748,6 +762,8 @@ int git_diff_print( break; case GIT_DIFF_FORMAT_PATCH_HEADER: print_file = diff_print_patch_file; + print_binary = diff_print_patch_binary; + print_hunk = diff_print_patch_hunk; break; case GIT_DIFF_FORMAT_RAW: print_file = diff_print_one_raw; From 656e75147ac2ec89c373508c35e60ac7a64fe75e Mon Sep 17 00:00:00 2001 From: Jan Chren ~rindeal Date: Wed, 25 Sep 2024 14:45:41 +0000 Subject: [PATCH 574/816] transport: do not filter tags based on ref dir in local Let git_object_type() do the filtering instead. Fixes: https://github.com/libgit2/libgit2/issues/6275 --- src/libgit2/transports/local.c | 4 ---- tests/libgit2/network/remote/local.c | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libgit2/transports/local.c b/src/libgit2/transports/local.c index 68ff1c1c12c..6c01141ce43 100644 --- a/src/libgit2/transports/local.c +++ b/src/libgit2/transports/local.c @@ -108,10 +108,6 @@ static int add_ref(transport_local *t, const char *name) return error; } - /* If it's not a tag, we don't need to try to peel it */ - if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) - return 0; - if ((error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJECT_ANY)) < 0) return error; diff --git a/tests/libgit2/network/remote/local.c b/tests/libgit2/network/remote/local.c index d70d0ebf7a6..f69502c7b15 100644 --- a/tests/libgit2/network/remote/local.c +++ b/tests/libgit2/network/remote/local.c @@ -61,7 +61,7 @@ void test_network_remote_local__retrieve_advertised_references(void) cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); - cl_assert_equal_i(refs_len, 30); + cl_assert_equal_i(refs_len, 31); } void test_network_remote_local__retrieve_advertised_before_connect(void) @@ -85,7 +85,7 @@ void test_network_remote_local__retrieve_advertised_references_after_disconnect( cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); - cl_assert_equal_i(refs_len, 30); + cl_assert_equal_i(refs_len, 31); } void test_network_remote_local__retrieve_advertised_references_from_spaced_repository(void) @@ -100,7 +100,7 @@ void test_network_remote_local__retrieve_advertised_references_from_spaced_repos cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); - cl_assert_equal_i(refs_len, 30); + cl_assert_equal_i(refs_len, 31); git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */ remote = NULL; From d3d9b8da6dfaa7fd5ef70ea73c9d31582bbbbe44 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 26 Sep 2024 16:33:41 +0200 Subject: [PATCH 575/816] stransport: updates for stransport errors Minor refactorings to the stransport error conditions. --- src/libgit2/streams/stransport.c | 93 ++++++++++++-------------------- 1 file changed, 33 insertions(+), 60 deletions(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 9f45110ddd3..52217187088 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -13,19 +13,16 @@ #include #include +#include "common.h" +#include "trace.h" #include "git2/transport.h" - -#include "../util/alloc.h" -#include "../trace.h" - #include "streams/socket.h" static int stransport_error(OSStatus ret) { - CFStringRef message; - char * message_c_str; - /* Use a boolean to track if we allocate a buffer for message_c_str that we need to free later. */ - bool must_free = false; + CFStringRef message_ref; + const char *message_cstr; + char *message_ptr = NULL; if (ret == noErr || ret == errSSLClosedGraceful) { git_error_clear(); @@ -33,54 +30,38 @@ static int stransport_error(OSStatus ret) } #if !TARGET_OS_IPHONE - message = SecCopyErrorMessageString(ret, NULL); - GIT_ERROR_CHECK_ALLOC(message); - - /* Attempt to cheaply convert the CoreFoundations string ref to a C-style null terminated string. */ - message_c_str = (char *) CFStringGetCStringPtr(message, kCFStringEncodingUTF8); - - /* - CFStringGetCStringPtr can return null in some instances, where the message conversion is not cheap. - In these cases, it's more valuable to print the actual error message than to be cheap/efficient. - Call the (more expensive) - */ - if (( must_free = (message_c_str == NULL) )) { - /* - Before we allocate a buffer, get the size of the buffer we need to allocate (in bytes). - CFStringGetLength gives us the number of UTF-16 code-pairs (16 bit characters) in the string. - Multiply by 2 (since 2 8-bit bytes make a 16 bit char). Add one for the null terminator. - */ - long buffer_size = CFStringGetLength(message) * 2 + 1; - - /* Allocate the buffer. */ - message_c_str = git__malloc((size_t) buffer_size); - GIT_ERROR_CHECK_ALLOC(message_c_str); - - /* - Convert the string into a C string using the buffer. - This returns a bool, which we check using this block. - If getting the CString failed (unlikely) we return early. - */ - if (!CFStringGetCString(message, message_c_str, buffer_size, kCFStringEncodingUTF8)) { - git_error_set(GIT_ERROR_NET, "CFStringGetCString error while handling a SecureTransport error"); - git__free(message_c_str); - CFRelease(message); - return -1; + message_ref = SecCopyErrorMessageString(ret, NULL); + GIT_ERROR_CHECK_ALLOC(message_ref); + + /* + * Attempt the cheap CFString conversion; this can return NULL + * when that would be expensive. In that case, call the more + * expensive function. + */ + message_cstr = CFStringGetCStringPtr(message_ref, kCFStringEncodingUTF8); + + if (!message_cstr) { + /* Provide buffer to convert from UTF16 to UTF8 */ + size_t message_size = CFStringGetLength(message_ref) * 2 + 1; + + message_cstr = message_ptr = git__malloc(message_size); + GIT_ERROR_CHECK_ALLOC(message_ptr); + + if (!CFStringGetCString(message_ref, message_ptr, message_size, kCFStringEncodingUTF8)) { + git_error_set(GIT_ERROR_NET, "SecureTransport error: %d", (unsigned int)ret); + goto done; } } - git_error_set(GIT_ERROR_NET, "SecureTransport error: %s", message_c_str); + git_error_set(GIT_ERROR_NET, "SecureTransport error: %s", message_cstr); - /* If we decided earlier that we would have to free the buffer allocation, do that. */ - if (must_free) { - git__free(message_c_str); - } - - CFRelease(message); +done: + git__free(message_ptr); + CFRelease(message_ref); #else git_error_set(GIT_ERROR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret); GIT_UNUSED(message); - GIT_UNUSED(message_c_str); + GIT_UNUSED(message_cstr); GIT_UNUSED(must_free); #endif @@ -283,17 +264,9 @@ static ssize_t stransport_read(git_stream *stream, void *data, size_t len) OSStatus ret; if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr) { - /* - This specific SecureTransport error is not well described by SecCopyErrorMessageString, - so we should at least log something to the user here so that they might see this if - they're running into the same error I am and they have tracing enabled. - */ - if (ret == -9806) { - git_trace(GIT_TRACE_FATAL, "SecureTransport error: SSLRead error: SSLRead returned -9806 (connection closed via error)."); - git_trace(GIT_TRACE_FATAL, "This means that the remote terminated the SSL connection due to an error."); - git_trace(GIT_TRACE_FATAL, "This is *possibly* similar to https://stackoverflow.com/questions/26461966/osx-10-10-curl-post-to-https-url-gives-sslread-error"); - git_trace(GIT_TRACE_FATAL, "You may find some valuable information running `security error -9806` (on macOS)."); - } + /* This specific SecureTransport error is not well described */ + if (ret == -9806) + git_trace(GIT_TRACE_INFO, "SecureTraceport error during SSLRead: returned -9806 (connection closed via error)"); if (st->error == GIT_TIMEOUT) return GIT_TIMEOUT; From 41f6f729104c770f59767d44efba60f1366ed571 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 26 Sep 2024 16:59:53 +0200 Subject: [PATCH 576/816] iOS Updates Some minor refactoring for iOS: - Roll back clar changes; these should be a bit more measured, and occur in clar upstream. - Move iOS to nightly builds --- .github/workflows/main.yml | 13 ------------- .github/workflows/nightly.yml | 10 ++++++++++ ci/setup-ios-benchmark.sh | 6 ------ ci/setup-ios-build.sh | 2 -- cmake/SelectRegex.cmake | 6 +----- src/CMakeLists.txt | 8 +------- tests/clar/main.c | 15 +-------------- 7 files changed, 13 insertions(+), 47 deletions(-) delete mode 100755 ci/setup-ios-benchmark.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b42a5c992b6..87e834f10db 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -73,19 +73,6 @@ jobs: PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "iOS" - id: ios - os: macos-12 - setup-script: ios - env: - CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 - CMAKE_GENERATOR: Ninja - PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig - # Skip all tests on iOS temporarily. - # 1. We need to update the path from libgit2_tests to libgit2_tests.app/libgit2_tests - # 2. We need to find a way to specify an iOS device / iOS simulator to run the tests. - SKIP_TESTS: true - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs os: windows-2019 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 28a06189d98..f66febbfda6 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -74,6 +74,16 @@ jobs: PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + - name: "iOS" + id: ios + os: macos-12 + setup-script: ios + env: + CC: clang + CMAKE_OPTIONS: -DBUILD_TESTS=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 + CMAKE_GENERATOR: Ninja + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_TESTS: true # Cannot exec iOS app on macOS - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs os: windows-2019 diff --git a/ci/setup-ios-benchmark.sh b/ci/setup-ios-benchmark.sh deleted file mode 100755 index 80d87682b3e..00000000000 --- a/ci/setup-ios-benchmark.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -set -ex - -brew update -brew install hyperfine diff --git a/ci/setup-ios-build.sh b/ci/setup-ios-build.sh index 195106c51fd..94af4e486de 100755 --- a/ci/setup-ios-build.sh +++ b/ci/setup-ios-build.sh @@ -7,6 +7,4 @@ brew install pkgconfig libssh2 ninja ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib -# The above is copied from setup-osx-build.sh - curl -s -L https://raw.githubusercontent.com/leetal/ios-cmake/master/ios.toolchain.cmake -o ios.toolchain.cmake diff --git a/cmake/SelectRegex.cmake b/cmake/SelectRegex.cmake index 0e34b733059..840ec7f349f 100644 --- a/cmake/SelectRegex.cmake +++ b/cmake/SelectRegex.cmake @@ -5,12 +5,8 @@ if(REGEX_BACKEND STREQUAL "") check_symbol_exists(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L) if(HAVE_REGCOMP_L) + # 'regcomp_l' has been explicitly marked unavailable on iOS_SDK if(CMAKE_SYSTEM_NAME MATCHES "iOS") - # 'regcomp_l' has been explicitly marked unavailable on iOS_SDK - # /usr/include/xlocale/_regex.h:34:5: - # int regcomp_l(regex_t * __restrict, const char * __restrict, int, - # locale_t __restrict) - # __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_NA); set(REGEX_BACKEND "regcomp") else() set(REGEX_BACKEND "regcomp_l") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2517df22fe9..73c46e21043 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -128,13 +128,7 @@ endif() check_library_exists(rt clock_gettime "time.h" NEED_LIBRT) -# workaround the iOS issue where clock_gettime is provided -# But we can't find rt library for some reason -if(CMAKE_SYSTEM_NAME MATCHES "iOS") - set(NEED_LIBRT FALSE) -endif() - -if(NEED_LIBRT) +if(NEED_LIBRT AND NOT CMAKE_SYSTEM_NAME MATCHES "iOS") list(APPEND LIBGIT2_SYSTEM_LIBS rt) list(APPEND LIBGIT2_PC_LIBS "-lrt") endif() diff --git a/tests/clar/main.c b/tests/clar/main.c index 0a3ca354d3c..e3f4fe740bd 100644 --- a/tests/clar/main.c +++ b/tests/clar/main.c @@ -10,15 +10,6 @@ int __cdecl main(int argc, char *argv[]) #else int main(int argc, char *argv[]) #endif - -#if defined(__APPLE__) -#include -#else -#if !defined(TARGET_OS_IOS) -#define TARGET_OS_IOS 0 -#endif -#endif - { int res; char *at_exit_cmd; @@ -53,13 +44,9 @@ int main(int argc, char *argv[]) at_exit_cmd = getenv("CLAR_AT_EXIT"); if (at_exit_cmd != NULL) { - #if TARGET_OS_IOS - /* system is unavailable on iOS */ - return res; - #else int at_exit = system(at_exit_cmd); return res || at_exit; - #endif } + return res; } From f27bbe03283458ed8dbf6bd719390c03bc016c5b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 26 Sep 2024 17:40:44 +0200 Subject: [PATCH 577/816] Update stransport.c stransport: correct unused on ios --- src/libgit2/streams/stransport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 52217187088..44261276529 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -60,9 +60,9 @@ static int stransport_error(OSStatus ret) CFRelease(message_ref); #else git_error_set(GIT_ERROR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret); - GIT_UNUSED(message); + GIT_UNUSED(message_ref); GIT_UNUSED(message_cstr); - GIT_UNUSED(must_free); + GIT_UNUSED(message_ptr); #endif return -1; From 9919b3a52b34716c054fa9aeb6225a17b219af5b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Sep 2024 11:12:22 +0200 Subject: [PATCH 578/816] stransport: initialize for iOS The unused variables in the stransport code should be initialized to avoid compiler warnings. :eyeroll: --- src/libgit2/streams/stransport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 44261276529..863616dcc77 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -20,8 +20,8 @@ static int stransport_error(OSStatus ret) { - CFStringRef message_ref; - const char *message_cstr; + CFStringRef message_ref = NULL; + const char *message_cstr = NULL; char *message_ptr = NULL; if (ret == noErr || ret == errSSLClosedGraceful) { From ffdacef6ffb4ccb093cfc6bc3ea6bb1c2fd77891 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Sep 2024 12:22:49 +0200 Subject: [PATCH 579/816] ci: update codeql nighly build --- .github/workflows/nightly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f66febbfda6..a1cdbfdc698 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -481,7 +481,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: 'cpp' @@ -489,7 +489,7 @@ jobs: run: | mkdir build cd build - cmake .. -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON + cmake .. -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON cmake --build . - name: Perform CodeQL Analysis From 60f6ff57bad35539e1113989b05e6f170a6c04de Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Sep 2024 12:24:09 +0200 Subject: [PATCH 580/816] ci: avoid compiler warnings for unused in pcre --- deps/pcre/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/deps/pcre/CMakeLists.txt b/deps/pcre/CMakeLists.txt index 431dda01a02..53b5cee86d5 100644 --- a/deps/pcre/CMakeLists.txt +++ b/deps/pcre/CMakeLists.txt @@ -22,6 +22,7 @@ check_type_size("unsigned long long" UNSIGNED_LONG_LONG) disable_warnings(unused-function) disable_warnings(implicit-fallthrough) +disable_warnings(unused-but-set-variable) # User-configurable options From f9c35fb50998d1c9d26293a18ade3d7c32f6ecb0 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Mon, 2 Sep 2024 17:20:08 +0200 Subject: [PATCH 581/816] Add git_mempack_write_thin_pack Unlike existing functions, this produces a _thin_ packfile by making use of the fact that only new objects appear in the mempack Object Database. A thin packfile only contains certain objects, but not its whole closure of references. This makes it suitable for efficiently writing sets of new objects to a local repository, by avoiding many small I/O operations. This relies on write_pack (e.g. git_packbuilder_write_buf) to implement the "recency order" optimization step. Basic measurements comparing against the writing of individual objects show a speedup during when writing large amounts of content on machines with comparatively slow I/O operations, and little to no change on machines with fast I/O operations. --- include/git2/sys/mempack.h | 19 +++++++++++++++++++ src/libgit2/odb_mempack.c | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/git2/sys/mempack.h b/include/git2/sys/mempack.h index 17da590a383..96bd8a7e86e 100644 --- a/include/git2/sys/mempack.h +++ b/include/git2/sys/mempack.h @@ -44,6 +44,25 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_mempack_new(git_odb_backend **out); +/** + * Write a thin packfile with the objects in the memory store. + * + * A thin packfile is a packfile that does not contain its transitive closure of + * references. This is useful for efficiently distributing additions to a + * repository over the network, but also finds use in the efficient bulk + * addition of objects to a repository, locally. + * + * This operation performs the (shallow) insert operations into the + * `git_packbuilder`, but does not write the packfile to disk; + * see `git_packbuilder_write_buf`. + * + * It also does not reset the in-memory object database; see `git_mempack_reset`. + * + * @param backend The mempack backend + * @param pb The packbuilder to use to write the packfile + */ +GIT_EXTERN(int) git_mempack_write_thin_pack(git_odb_backend *backend, git_packbuilder *pb); + /** * Dump all the queued in-memory writes to a packfile. * diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c index 6f27f45f870..fb4391f8dcf 100644 --- a/src/libgit2/odb_mempack.c +++ b/src/libgit2/odb_mempack.c @@ -132,6 +132,29 @@ static int git_mempack__dump( return err; } +int git_mempack_write_thin_pack(git_odb_backend *backend, git_packbuilder *pb) +{ + struct memory_packer_db *db = (struct memory_packer_db *)backend; + const git_oid *oid; + size_t iter = 0; + int err; + + while (true) { + err = git_oidmap_iterate(NULL, db->objects, &iter, &oid); + + if (err == GIT_ITEROVER) + break; + else if (err != 0) + return err; + + err = git_packbuilder_insert(pb, oid, NULL); + if (err != 0) + return err; + } + + return 0; +} + int git_mempack_dump( git_buf *pack, git_repository *repo, From 54100fc08100799e2aa8e48414b0fbf270b027b5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 22:58:39 +0100 Subject: [PATCH 582/816] Update include/git2/common.h --- include/git2/common.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 8566b290ece..c4d494be38c 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -340,11 +340,11 @@ typedef enum { * * * opts(GIT_OPT_ADD_SSL_X509_CERT, const X509 *cert) * - * > Add a raw X509 certificate into the SSL certs store. - * > The added certificate is not persisted and will be used - * > only during application lifetime. Also there is no ability - * > to remove a certificate from the store during app lifetime - * > after it was added. + * > Add a raw X509 certificate into the SSL certs store. + * > The added certificate is not persisted and will be used + * > only during application lifetime. Also there is no ability + * > to remove a certificate from the store during app lifetime + * > after it was added. * > * > - `cert` is the raw X509 cert will be added to cert store. * From d50b501e7e1fb5e52196733f24e7e30df7e47593 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Sep 2024 12:48:09 +0200 Subject: [PATCH 583/816] ci: update to download-artifact v4 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 87e834f10db..a84bfc56119 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -240,7 +240,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download test results - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Generate test summary uses: test-summary/action@v2 with: From 12eecf0abc8132b06fe8231e2f39850198901d06 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Sep 2024 12:44:28 +0200 Subject: [PATCH 584/816] ci: update to (mostly) latest images Update to the latest CI images, except macOS - where there's a memory leak in macos-14. --- .github/workflows/benchmark.yml | 20 ++++++++++---------- .github/workflows/experimental.yml | 2 +- .github/workflows/main.yml | 14 +++++++------- .github/workflows/nightly.yml | 26 +++++++++++++------------- ci/setup-ios-build.sh | 6 ++++-- ci/setup-osx-build.sh | 6 ++++-- 6 files changed, 39 insertions(+), 35 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 450562a5237..8b513d94dc2 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -23,31 +23,31 @@ jobs: matrix: platform: - name: "Linux (clang, OpenSSL)" + id: linux + os: ubuntu-latest + setup-script: ubuntu env: CC: clang CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release CMAKE_BUILD_OPTIONS: --config Release - id: linux - os: ubuntu-latest - setup-script: ubuntu - name: "macOS" - os: macos-12 + id: macos + os: macos-latest + setup-script: osx env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release CMAKE_BUILD_OPTIONS: --config Release PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig - id: macos - setup-script: osx - name: "Windows (amd64, Visual Studio)" - os: windows-2019 + id: windows + os: windows-2022 + setup-script: win32 env: ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release CMAKE_BUILD_OPTIONS: --config Release - id: windows - setup-script: win32 fail-fast: false name: "Benchmark ${{ matrix.platform.name }}" env: ${{ matrix.platform.env }} diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml index 5bfea2c0028..2ab745f18ac 100644 --- a/.github/workflows/experimental.yml +++ b/.github/workflows/experimental.yml @@ -37,7 +37,7 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON - name: "macOS (SHA256)" id: macos-sha256 - os: macos-12 + os: macos-13 setup-script: osx env: CC: clang diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a84bfc56119..ad1eded47e3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,7 +64,7 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - name: "macOS" id: macos - os: macos-12 + os: macos-13 setup-script: osx env: CC: clang @@ -75,11 +75,11 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs - os: windows-2019 + os: windows-2022 setup-script: win32 env: ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp @@ -87,11 +87,11 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (x86, Visual Studio, WinHTTP)" id: windows-x86-vs - os: windows-2019 + os: windows-2022 setup-script: win32 env: ARCH: x86 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp @@ -99,7 +99,7 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (amd64, mingw, WinHTTP)" id: windows-amd64-mingw - os: windows-2019 + os: windows-2022 setup-script: mingw env: ARCH: amd64 @@ -111,7 +111,7 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (x86, mingw, Schannel)" id: windows-x86-mingw - os: windows-2019 + os: windows-2022 setup-script: mingw env: ARCH: x86 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a1cdbfdc698..3bed061fdec 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -65,7 +65,7 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - name: "macOS" id: macos - os: macos-12 + os: macos-13 setup-script: osx env: CC: clang @@ -76,7 +76,7 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "iOS" id: ios - os: macos-12 + os: macos-13 setup-script: ios env: CC: clang @@ -86,11 +86,11 @@ jobs: SKIP_TESTS: true # Cannot exec iOS app on macOS - name: "Windows (amd64, Visual Studio, Schannel)" id: windows-amd64-vs - os: windows-2019 + os: windows-2022 setup-script: win32 env: ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp @@ -98,11 +98,11 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (x86, Visual Studio, WinHTTP)" id: windows-x86-vs - os: windows-2019 + os: windows-2022 setup-script: win32 env: ARCH: x86 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp @@ -110,7 +110,7 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (amd64, mingw, WinHTTP)" id: windows-amd64-mingw - os: windows-2019 + os: windows-2022 setup-script: mingw env: ARCH: amd64 @@ -122,7 +122,7 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (x86, mingw, Schannel)" id: windows-x86-mingw - os: windows-2019 + os: windows-2022 setup-script: mingw env: ARCH: x86 @@ -324,10 +324,10 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (no mmap)" id: windows-nommap - os: windows-2019 + os: windows-2022 env: ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CFLAGS: -DNO_MMAP CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON SKIP_SSH_TESTS: true @@ -356,7 +356,7 @@ jobs: os: ubuntu-latest - name: "macOS (SHA256)" id: macos-sha256 - os: macos-12 + os: macos-13 setup-script: osx env: CC: clang @@ -366,10 +366,10 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (SHA256, amd64, Visual Studio)" id: windows-sha256 - os: windows-2019 + os: windows-2022 env: ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true diff --git a/ci/setup-ios-build.sh b/ci/setup-ios-build.sh index 94af4e486de..623b135cf24 100755 --- a/ci/setup-ios-build.sh +++ b/ci/setup-ios-build.sh @@ -3,8 +3,10 @@ set -ex brew update -brew install pkgconfig libssh2 ninja +brew install ninja -ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib +sudo mkdir /usr/local/lib || true +sudo chmod 0755 /usr/local/lib +sudo ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib curl -s -L https://raw.githubusercontent.com/leetal/ios-cmake/master/ios.toolchain.cmake -o ios.toolchain.cmake diff --git a/ci/setup-osx-build.sh b/ci/setup-osx-build.sh index 511d886cb17..5598902546d 100755 --- a/ci/setup-osx-build.sh +++ b/ci/setup-osx-build.sh @@ -3,6 +3,8 @@ set -ex brew update -brew install pkgconfig libssh2 ninja +brew install ninja -ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib +sudo mkdir /usr/local/lib || true +sudo chmod 0755 /usr/local/lib +sudo ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib From 54e7701ebdf624b2b1de1c7a3b288d4e81b2f64c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 22:52:28 +0100 Subject: [PATCH 585/816] libssh2: compatibility fixups --- src/libgit2/transports/ssh_libssh2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index 1993ffe5c3a..7011674f74e 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -115,8 +115,8 @@ static int ssh_stream_read( size_t buf_size, size_t *bytes_read) { - int rc; ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); + ssize_t rc; *bytes_read = 0; @@ -135,7 +135,7 @@ static int ssh_stream_read( */ if (rc == 0) { if ((rc = libssh2_channel_read_stderr(s->channel, buffer, buf_size)) > 0) { - git_error_set(GIT_ERROR_SSH, "%*s", rc, buffer); + git_error_set(GIT_ERROR_SSH, "%*s", (int)rc, buffer); return GIT_EEOF; } else if (rc < LIBSSH2_ERROR_NONE) { ssh_error(s->session, "SSH could not read stderr"); @@ -143,7 +143,6 @@ static int ssh_stream_read( } } - *bytes_read = rc; return 0; @@ -1015,7 +1014,8 @@ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *use *out = 0; - list = libssh2_userauth_list(session, username, strlen(username)); + list = libssh2_userauth_list(session, username, + (unsigned int)strlen(username)); /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */ if (list == NULL && !libssh2_userauth_authenticated(session)) { From 03ebf63d2f8f94902b0a4606da33ddd183188911 Mon Sep 17 00:00:00 2001 From: Sergey Kazmin Date: Mon, 30 Sep 2024 15:12:12 +0300 Subject: [PATCH 586/816] support dynamic linking --- src/libgit2/streams/openssl_dynamic.c | 2 ++ src/libgit2/streams/openssl_dynamic.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/libgit2/streams/openssl_dynamic.c b/src/libgit2/streams/openssl_dynamic.c index 222c1099d6b..fc65fc6195e 100644 --- a/src/libgit2/streams/openssl_dynamic.c +++ b/src/libgit2/streams/openssl_dynamic.c @@ -80,6 +80,7 @@ int (*X509_NAME_get_index_by_NID)(X509_NAME *name, int nid, int lastpos); void (*X509_free)(X509 *a); void *(*X509_get_ext_d2i)(const X509 *x, int nid, int *crit, int *idx); X509_NAME *(*X509_get_subject_name)(const X509 *x); +int (*X509_STORE_add_cert)(X509_STORE *ctx, X509 *x); int (*i2d_X509)(X509 *a, unsigned char **ppout); @@ -209,6 +210,7 @@ int git_openssl_stream_dynamic_init(void) X509_free = (void (*)(X509 *))openssl_sym(&err, "X509_free", true); X509_get_ext_d2i = (void *(*)(const X509 *x, int nid, int *crit, int *idx))openssl_sym(&err, "X509_get_ext_d2i", true); X509_get_subject_name = (X509_NAME *(*)(const X509 *))openssl_sym(&err, "X509_get_subject_name", true); + X509_STORE_add_cert = (int (*)(X509_STORE *ctx, X509 *x))openssl_sym(&err, "X509_STORE_add_cert", true); i2d_X509 = (int (*)(X509 *a, unsigned char **ppout))openssl_sym(&err, "i2d_X509", true); diff --git a/src/libgit2/streams/openssl_dynamic.h b/src/libgit2/streams/openssl_dynamic.h index a9969191003..34f7c749bf8 100644 --- a/src/libgit2/streams/openssl_dynamic.h +++ b/src/libgit2/streams/openssl_dynamic.h @@ -326,6 +326,7 @@ extern int (*X509_NAME_get_index_by_NID)(X509_NAME *name, int nid, int lastpos); extern void (*X509_free)(X509 *a); extern void *(*X509_get_ext_d2i)(const X509 *x, int nid, int *crit, int *idx); extern X509_NAME *(*X509_get_subject_name)(const X509 *x); +extern int (*X509_STORE_add_cert)(X509_STORE *ctx, X509 *x); extern int (*i2d_X509)(X509 *a, unsigned char **ppout); From ceab2087c000905c9b88f18723b0e5ef3bd29abe Mon Sep 17 00:00:00 2001 From: Sergey Kazmin Date: Mon, 30 Sep 2024 15:12:28 +0300 Subject: [PATCH 587/816] test impl --- tests/libgit2/online/customcert.c | 33 ++++++++++++++++++++++++++++- tests/resources/self-signed.pem.raw | 1 + 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/resources/self-signed.pem.raw diff --git a/tests/libgit2/online/customcert.c b/tests/libgit2/online/customcert.c index 7932a9e68f3..d25b6282b3b 100644 --- a/tests/libgit2/online/customcert.c +++ b/tests/libgit2/online/customcert.c @@ -1,3 +1,4 @@ +#include "clar.h" #include "clar_libgit2.h" #include "path.h" @@ -6,6 +7,8 @@ #include "remote.h" #include "futils.h" #include "refs.h" +#include "str.h" +#include "streams/openssl.h" /* * Certificate one is in the `certs` folder; certificate two is in the @@ -17,6 +20,9 @@ #define CUSTOM_CERT_TWO_URL "https://test.libgit2.org:2443/anonymous/test.git" #define CUSTOM_CERT_TWO_FILE "self-signed.pem" +#define CUSTOM_CERT_THREE_URL "https://test.libgit2.org:3443/anonymous/test.git" +#define CUSTOM_CERT_THREE_FILE "self-signed.pem.raw" + #if (GIT_OPENSSL || GIT_MBEDTLS) static git_repository *g_repo; static int initialized = false; @@ -28,22 +34,38 @@ void test_online_customcert__initialize(void) g_repo = NULL; if (!initialized) { - git_str path = GIT_STR_INIT, file = GIT_STR_INIT; + git_str path = GIT_STR_INIT, file = GIT_STR_INIT, raw_file = GIT_STR_INIT, raw_file_buf = GIT_STR_INIT, raw_cert = GIT_STR_INIT; char cwd[GIT_PATH_MAX]; + const unsigned char* raw_cert_bytes = NULL; + X509* x509_cert = NULL; cl_fixture_sandbox(CUSTOM_CERT_ONE_PATH); cl_fixture_sandbox(CUSTOM_CERT_TWO_FILE); + cl_fixture_sandbox(CUSTOM_CERT_THREE_FILE); cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX)); cl_git_pass(git_str_joinpath(&path, cwd, CUSTOM_CERT_ONE_PATH)); cl_git_pass(git_str_joinpath(&file, cwd, CUSTOM_CERT_TWO_FILE)); + cl_git_pass(git_str_joinpath(&raw_file, cwd, CUSTOM_CERT_THREE_FILE)); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, file.ptr, path.ptr)); + +#if (GIT_OPENSSL) + cl_git_pass(git_futils_readbuffer(&raw_file_buf, git_str_cstr(&raw_file))); + cl_git_pass(git_str_decode_base64(&raw_cert, git_str_cstr(&raw_file_buf), git_str_len(&raw_file_buf))); + + raw_cert_bytes = (const unsigned char*)git_str_cstr(&raw_cert); + x509_cert = d2i_X509(NULL, &raw_cert_bytes, git_str_len(&raw_cert)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ADD_SSL_X509_CERT, x509_cert)); + X509_free(x509_cert); +#endif + initialized = true; git_str_dispose(&file); git_str_dispose(&path); + git_str_dispose(&raw_file); } #endif } @@ -59,6 +81,7 @@ void test_online_customcert__cleanup(void) cl_fixture_cleanup("./cloned"); cl_fixture_cleanup(CUSTOM_CERT_ONE_PATH); cl_fixture_cleanup(CUSTOM_CERT_TWO_FILE); + cl_fixture_cleanup(CUSTOM_CERT_THREE_FILE); #endif } @@ -77,3 +100,11 @@ void test_online_customcert__path(void) cl_assert(git_fs_path_exists("./cloned/master.txt")); #endif } + +void test_online_customcert__raw_x509(void) +{ +#if (GIT_OPENSSL) + cl_git_pass(git_clone(&g_repo, CUSTOM_CERT_THREE_URL, "./cloned", NULL)); + cl_assert(git_fs_path_exists("./cloned/master.txt")); +#endif +} diff --git a/tests/resources/self-signed.pem.raw b/tests/resources/self-signed.pem.raw new file mode 100644 index 00000000000..d16446ba04c --- /dev/null +++ b/tests/resources/self-signed.pem.raw @@ -0,0 +1 @@ +MIIDUzCCAjsCFAb11im6DYQyGJ0GNQCIehXtegq6MA0GCSqGSIb3DQEBCwUAMGYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxEDAOBgNVBAoMB2xpYmdpdDIxGTAXBgNVBAMMEHRlc3QubGliZ2l0Mi5vcmcwHhcNMjEwODMwMDAyMTQyWhcNMzEwODI4MDAyMTQyWjBmMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMRAwDgYDVQQKDAdsaWJnaXQyMRkwFwYDVQQDDBB0ZXN0LmxpYmdpdDIub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtqe6b1vnMni+z8Z+a2bGtykIITvBged15rn+0qG6Fz+sn9bYG+ceFupztFfoN3cVpUgQDBTzr3CaAx036BlV0z8iCrG0Oh/XGL+9TITQLumEe4iGi8NoMSujBAyXPSNgmpzDmCTGrNFfmq3HzUtO8t3xi8OT7d9qCVjFimLvZbgnfHGQ38xvt1XyPgYIVqDQczmMEZ5BdYWB0A1VmnWuP2dHBgjwPEC3HwMmm1+PL0VoPTdvE5Su092Qdt8QsiA56466DQyll1d/omnOJfrK7z0NOnfDmnDpARSTy6vDofEAYUQoc3dyvBUk8IIzv2UDcR7fTVvYqseQReIOTEnXmQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBmUEq+JhwWTbB5ODGOKrMG1fKJ+sf6ZH6Mc4BgLEcdoi/nOTfPuw+ols72LuhH7NKaEcqxWev0jGF0WKqMcM8AGVbywZJ3mBWosKdh6rAGFNkikW4TzhjtDfFbMR45Didl28Be7ieHQL4CQ0Lse3RMOxp250WpiEYVW2hIKMwIqOLKGShVD7lI+eHlv+QSH4yOYKHfRHve8s82Tac5OXinc8CJm9ySOtkOMfLgfkHtHdFBnV6OVbf4p/596MfMXdwT/bBxT6WPkDGc1AYhoDlmLFTpRgHIDCSK2wgV+qHppl7Kn+p3mFQ9sW/1IaRd+jNZOrgZ8Uu5tJ00OaqR/LVG \ No newline at end of file From e78eec28c32207143be7e9cf16ed74d9b2bf2ad4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 21:17:57 +0100 Subject: [PATCH 588/816] vector: free is now dispose In keeping with the libgit2 pattern, we _dispose_ a structure that is not heap allocated, and _free_ a structure's contents _and the structure itself_. --- fuzzers/standalone_driver.c | 2 +- src/cli/common.c | 2 +- src/libgit2/apply.c | 4 +-- src/libgit2/attr.c | 2 +- src/libgit2/attr_file.c | 4 +-- src/libgit2/blame.c | 4 +-- src/libgit2/checkout.c | 6 ++-- src/libgit2/commit_graph.c | 2 +- src/libgit2/config.c | 4 +-- src/libgit2/describe.c | 2 +- src/libgit2/diff_generate.c | 2 +- src/libgit2/diff_parse.c | 4 +-- src/libgit2/diff_tform.c | 6 ++-- src/libgit2/filter.c | 4 +-- src/libgit2/graph.c | 2 +- src/libgit2/ignore.c | 4 +-- src/libgit2/index.c | 28 ++++++++--------- src/libgit2/indexer.c | 4 +-- src/libgit2/iterator.c | 8 ++--- src/libgit2/mailmap.c | 2 +- src/libgit2/merge.c | 22 ++++++------- src/libgit2/merge_driver.c | 4 +-- src/libgit2/midx.c | 6 ++-- src/libgit2/mwindow.c | 4 +-- src/libgit2/odb.c | 4 +-- src/libgit2/odb_pack.c | 6 ++-- src/libgit2/pack.c | 2 +- src/libgit2/pathspec.c | 2 +- src/libgit2/push.c | 20 ++++++------ src/libgit2/refdb_fs.c | 2 +- src/libgit2/reflog.c | 2 +- src/libgit2/refs.c | 2 +- src/libgit2/remote.c | 40 ++++++++++++------------ src/libgit2/repository.c | 2 +- src/libgit2/status.c | 2 +- src/libgit2/submodule.c | 6 ++-- src/libgit2/tag.c | 2 +- src/libgit2/transport.c | 2 +- src/libgit2/transports/httpclient.c | 6 ++-- src/libgit2/transports/local.c | 4 +-- src/libgit2/transports/smart.c | 12 +++---- src/libgit2/tree.c | 4 +-- src/util/pool.c | 2 +- src/util/pqueue.h | 2 +- src/util/sortedcache.c | 4 +-- src/util/unix/process.c | 2 +- src/util/vector.c | 6 ++-- src/util/vector.h | 4 +-- tests/libgit2/checkout/conflict.c | 2 +- tests/libgit2/checkout/crlf.c | 2 +- tests/libgit2/diff/drivers.c | 2 +- tests/libgit2/diff/workdir.c | 4 +-- tests/libgit2/fetchhead/nonetwork.c | 4 +-- tests/libgit2/graph/reachable_from_any.c | 2 +- tests/libgit2/index/crlf.c | 4 +-- tests/libgit2/iterator/index.c | 18 +++++------ tests/libgit2/iterator/tree.c | 10 +++--- tests/libgit2/iterator/workdir.c | 14 ++++----- tests/libgit2/network/remote/rename.c | 2 +- tests/libgit2/online/push.c | 6 ++-- tests/libgit2/online/push_util.c | 4 +-- tests/libgit2/pack/packbuilder.c | 2 +- tests/libgit2/refs/iterator.c | 4 +-- tests/util/process/env.c | 2 +- tests/util/vector.c | 20 ++++++------ 65 files changed, 187 insertions(+), 187 deletions(-) diff --git a/fuzzers/standalone_driver.c b/fuzzers/standalone_driver.c index cd4f71751ae..17b54de952e 100644 --- a/fuzzers/standalone_driver.c +++ b/fuzzers/standalone_driver.c @@ -67,7 +67,7 @@ int main(int argc, char **argv) fprintf(stderr, "Done %d runs\n", i); exit: - git_vector_free_deep(&corpus_files); + git_vector_dispose_deep(&corpus_files); git_libgit2_shutdown(); return error; } diff --git a/src/cli/common.c b/src/cli/common.c index 60b0358662b..fcb3676cef0 100644 --- a/src/cli/common.c +++ b/src/cli/common.c @@ -105,7 +105,7 @@ static int parse_common_options( if (error && backend) backend->free(backend); git_config_free(config); - git_vector_free_deep(&cmdline); + git_vector_dispose_deep(&cmdline); return error; } diff --git a/src/libgit2/apply.c b/src/libgit2/apply.c index 6b55b812fa4..202d2d2b8f0 100644 --- a/src/libgit2/apply.c +++ b/src/libgit2/apply.c @@ -96,7 +96,7 @@ static void patch_image_free(patch_image *image) return; git_pool_clear(&image->pool); - git_vector_free(&image->lines); + git_vector_dispose(&image->lines); } static bool match_hunk( @@ -730,7 +730,7 @@ static int git_apply__to_workdir( error = git_checkout_index(repo, postimage, &checkout_opts); done: - git_vector_free(&paths); + git_vector_dispose(&paths); return error; } diff --git a/src/libgit2/attr.c b/src/libgit2/attr.c index 1db90b59c7e..4cbb7d987f9 100644 --- a/src/libgit2/attr.c +++ b/src/libgit2/attr.c @@ -618,7 +618,7 @@ static void release_attr_files(git_vector *files) git_attr_file__free(file); files->contents[i] = NULL; } - git_vector_free(files); + git_vector_dispose(files); } static int collect_attr_files( diff --git a/src/libgit2/attr_file.c b/src/libgit2/attr_file.c index 108ed744630..c19921e2491 100644 --- a/src/libgit2/attr_file.c +++ b/src/libgit2/attr_file.c @@ -69,7 +69,7 @@ int git_attr_file__clear_rules(git_attr_file *file, bool need_lock) git_vector_foreach(&file->rules, i, rule) git_attr_rule__free(rule); - git_vector_free(&file->rules); + git_vector_dispose(&file->rules); if (need_lock) git_mutex_unlock(&file->lock); @@ -996,7 +996,7 @@ static void git_attr_rule__clear(git_attr_rule *rule) if (!(rule->match.flags & GIT_ATTR_FNMATCH_IGNORE)) { git_vector_foreach(&rule->assigns, i, assign) GIT_REFCOUNT_DEC(assign, git_attr_assignment__free); - git_vector_free(&rule->assigns); + git_vector_dispose(&rule->assigns); } /* match.pattern is stored in a git_pool, so no need to free */ diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index 2ed7d2011f7..693e39b5e82 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -165,9 +165,9 @@ void git_blame_free(git_blame *blame) git_vector_foreach(&blame->hunks, i, hunk) free_hunk(hunk); - git_vector_free(&blame->hunks); + git_vector_dispose(&blame->hunks); - git_vector_free_deep(&blame->paths); + git_vector_dispose_deep(&blame->paths); git_array_clear(blame->line_index); diff --git a/src/libgit2/checkout.c b/src/libgit2/checkout.c index 6a4643196b0..cd5cf21ca56 100644 --- a/src/libgit2/checkout.c +++ b/src/libgit2/checkout.c @@ -2316,11 +2316,11 @@ static void checkout_data_clear(checkout_data *data) data->opts.baseline = NULL; } - git_vector_free(&data->removes); + git_vector_dispose(&data->removes); git_pool_clear(&data->pool); - git_vector_free_deep(&data->remove_conflicts); - git_vector_free_deep(&data->update_conflicts); + git_vector_dispose_deep(&data->remove_conflicts); + git_vector_dispose_deep(&data->update_conflicts); git__free(data->pfx); data->pfx = NULL; diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index 4edd7110640..47803be4ac6 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -730,7 +730,7 @@ void git_commit_graph_writer_free(git_commit_graph_writer *w) git_vector_foreach (&w->commits, i, packed_commit) packed_commit_free(packed_commit); - git_vector_free(&w->commits); + git_vector_dispose(&w->commits); git_str_dispose(&w->objects_info_dir); git__free(w); } diff --git a/src/libgit2/config.c b/src/libgit2/config.c index 597928caec9..b16d981d869 100644 --- a/src/libgit2/config.c +++ b/src/libgit2/config.c @@ -78,8 +78,8 @@ static void config_free(git_config *config) git__free(entry); } - git_vector_free(&config->readers); - git_vector_free(&config->writers); + git_vector_dispose(&config->readers); + git_vector_dispose(&config->writers); git__free(config); } diff --git a/src/libgit2/describe.c b/src/libgit2/describe.c index 04453472330..7fed8e859a2 100644 --- a/src/libgit2/describe.c +++ b/src/libgit2/describe.c @@ -627,7 +627,7 @@ static int describe( git__free(match); } } - git_vector_free(&all_matches); + git_vector_dispose(&all_matches); git_pqueue_free(&list); git_revwalk_free(walk); return error; diff --git a/src/libgit2/diff_generate.c b/src/libgit2/diff_generate.c index 78fe510e748..6eeb3b544aa 100644 --- a/src/libgit2/diff_generate.c +++ b/src/libgit2/diff_generate.c @@ -429,7 +429,7 @@ static void diff_generated_free(git_diff *d) git_diff_generated *diff = (git_diff_generated *)d; git_attr_session__free(&diff->base.attrsession); - git_vector_free_deep(&diff->base.deltas); + git_vector_dispose_deep(&diff->base.deltas); git_pathspec__vfree(&diff->pathspec); git_pool_clear(&diff->base.pool); diff --git a/src/libgit2/diff_parse.c b/src/libgit2/diff_parse.c index 04603969e40..02eb21ef82c 100644 --- a/src/libgit2/diff_parse.c +++ b/src/libgit2/diff_parse.c @@ -20,9 +20,9 @@ static void diff_parsed_free(git_diff *d) git_vector_foreach(&diff->patches, i, patch) git_patch_free(patch); - git_vector_free(&diff->patches); + git_vector_dispose(&diff->patches); - git_vector_free(&diff->base.deltas); + git_vector_dispose(&diff->base.deltas); git_pool_clear(&diff->base.pool); git__memzero(diff, sizeof(*diff)); diff --git a/src/libgit2/diff_tform.c b/src/libgit2/diff_tform.c index 9fa3cef8358..33ed2d11cda 100644 --- a/src/libgit2/diff_tform.c +++ b/src/libgit2/diff_tform.c @@ -190,7 +190,7 @@ int git_diff__merge( git_pool_strdup_safe(&onto->pool, onto->opts.new_prefix); } - git_vector_free_deep(&onto_new); + git_vector_dispose_deep(&onto_new); git_pool_clear(&onto_pool); return error; @@ -424,13 +424,13 @@ static int apply_splits_and_deletes( /* swap new delta list into place */ git_vector_swap(&diff->deltas, &onto); - git_vector_free(&onto); + git_vector_dispose(&onto); git_vector_sort(&diff->deltas); return 0; on_error: - git_vector_free_deep(&onto); + git_vector_dispose_deep(&onto); return -1; } diff --git a/src/libgit2/filter.c b/src/libgit2/filter.c index fdfc409a287..9e0910c8c26 100644 --- a/src/libgit2/filter.c +++ b/src/libgit2/filter.c @@ -239,7 +239,7 @@ static void git_filter_global_shutdown(void) git__free(fdef); } - git_vector_free(&filter_registry.filters); + git_vector_dispose(&filter_registry.filters); git_rwlock_wrunlock(&filter_registry.lock); git_rwlock_free(&filter_registry.lock); @@ -1106,7 +1106,7 @@ static void filter_streams_free(git_vector *streams) git_vector_foreach(streams, i, stream) stream->free(stream); - git_vector_free(streams); + git_vector_dispose(streams); } int git_filter_list_stream_file( diff --git a/src/libgit2/graph.c b/src/libgit2/graph.c index 35e914f7462..3cce7fd1185 100644 --- a/src/libgit2/graph.c +++ b/src/libgit2/graph.c @@ -243,7 +243,7 @@ int git_graph_reachable_from_any( done: git_commit_list_free(&result); - git_vector_free(&list); + git_vector_dispose(&list); git_revwalk_free(walk); return error; } diff --git a/src/libgit2/ignore.c b/src/libgit2/ignore.c index cee58d7f15f..7856d2c385f 100644 --- a/src/libgit2/ignore.c +++ b/src/libgit2/ignore.c @@ -428,13 +428,13 @@ void git_ignore__free(git_ignores *ignores) git_attr_file__free(file); ignores->ign_path.contents[i] = NULL; } - git_vector_free(&ignores->ign_path); + git_vector_dispose(&ignores->ign_path); git_vector_foreach(&ignores->ign_global, i, file) { git_attr_file__free(file); ignores->ign_global.contents[i] = NULL; } - git_vector_free(&ignores->ign_global); + git_vector_dispose(&ignores->ign_global); git_str_dispose(&ignores->dir); } diff --git a/src/libgit2/index.c b/src/libgit2/index.c index fe6f72ab3db..632720dc6c3 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -503,10 +503,10 @@ static void index_free(git_index *index) git_index_clear(index); git_idxmap_free(index->entries_map); - git_vector_free(&index->entries); - git_vector_free(&index->names); - git_vector_free(&index->reuc); - git_vector_free(&index->deleted); + git_vector_dispose(&index->entries); + git_vector_dispose(&index->names); + git_vector_dispose(&index->reuc); + git_vector_dispose(&index->deleted); git__free(index->index_file_path); @@ -786,10 +786,10 @@ static int truncate_racily_clean(git_index *index) diff_opts.pathspec.count = paths.length; diff_opts.pathspec.strings = (char **)paths.contents; - if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0) { - git_vector_free(&paths); - return error; - } + if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0) { + git_vector_dispose(&paths); + return error; + } git_vector_foreach(&diff->deltas, i, delta) { entry = (git_index_entry *)git_index_get_bypath(index, delta->old_file.path, 0); @@ -805,7 +805,7 @@ static int truncate_racily_clean(git_index *index) done: git_diff_free(diff); - git_vector_free(&paths); + git_vector_dispose(&paths); return 0; } @@ -3091,7 +3091,7 @@ static int write_entries(git_index *index, git_filebuf *file) } done: - git_vector_free(&case_sorted); + git_vector_dispose(&case_sorted); return error; } @@ -3414,7 +3414,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree) index->dirty = 1; cleanup: - git_vector_free(&entries); + git_vector_dispose(&entries); git_idxmap_free(entries_map); if (error < 0) return error; @@ -3558,8 +3558,8 @@ static int git_index_read_iterator( done: git_idxmap_free(new_entries_map); - git_vector_free(&new_entries); - git_vector_free(&remove_entries); + git_vector_dispose(&new_entries); + git_vector_dispose(&remove_entries); git_iterator_free(index_iterator); return error; } @@ -3860,7 +3860,7 @@ int git_index_snapshot_new(git_vector *snap, git_index *index) void git_index_snapshot_release(git_vector *snap, git_index *index) { - git_vector_free(snap); + git_vector_dispose(snap); git_atomic32_dec(&index->readers); diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index e559a194235..d51d373b0f3 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -1456,7 +1456,7 @@ void git_indexer_free(git_indexer *idx) if (idx->have_stream) git_packfile_stream_dispose(&idx->stream); - git_vector_free_deep(&idx->objects); + git_vector_dispose_deep(&idx->objects); if (idx->pack->idx_cache) { struct git_pack_entry *pentry; @@ -1467,7 +1467,7 @@ void git_indexer_free(git_indexer *idx) git_oidmap_free(idx->pack->idx_cache); } - git_vector_free_deep(&idx->deltas); + git_vector_dispose_deep(&idx->deltas); git_packfile_free(idx->pack, !idx->pack_committed); diff --git a/src/libgit2/iterator.c b/src/libgit2/iterator.c index bef9c609079..5b3e0248539 100644 --- a/src/libgit2/iterator.c +++ b/src/libgit2/iterator.c @@ -696,7 +696,7 @@ static int tree_iterator_frame_pop(tree_iterator *iter) frame = git_array_pop(iter->frames); - git_vector_free(&frame->entries); + git_vector_dispose(&frame->entries); git_tree_free(frame->tree); do { @@ -709,7 +709,7 @@ static int tree_iterator_frame_pop(tree_iterator *iter) git_vector_foreach(&frame->similar_trees, i, tree) git_tree_free(tree); - git_vector_free(&frame->similar_trees); + git_vector_dispose(&frame->similar_trees); git_str_dispose(&frame->path); @@ -1501,7 +1501,7 @@ GIT_INLINE(int) filesystem_iterator_frame_pop(filesystem_iterator *iter) filesystem_iterator_frame_pop_ignores(iter); git_pool_clear(&frame->entry_pool); - git_vector_free(&frame->entries); + git_vector_dispose(&frame->entries); return 0; } @@ -2336,7 +2336,7 @@ void git_iterator_free(git_iterator *iter) iter->cb->free(iter); - git_vector_free(&iter->pathlist); + git_vector_dispose(&iter->pathlist); git__free(iter->start); git__free(iter->end); diff --git a/src/libgit2/mailmap.c b/src/libgit2/mailmap.c index 4336fe3e549..05c88ff02c1 100644 --- a/src/libgit2/mailmap.c +++ b/src/libgit2/mailmap.c @@ -173,7 +173,7 @@ void git_mailmap_free(git_mailmap *mm) git_vector_foreach(&mm->entries, idx, entry) mailmap_entry_free(entry); - git_vector_free(&mm->entries); + git_vector_dispose(&mm->entries); git__free(mm); } diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 21e5ef6a8f9..8f3fc460216 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -124,11 +124,11 @@ static int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_r *out = result; *walk_out = walk; - git_vector_free(&list); + git_vector_dispose(&list); return 0; on_error: - git_vector_free(&list); + git_vector_dispose(&list); git_revwalk_free(walk); return error; } @@ -511,7 +511,7 @@ static int remove_redundant(git_revwalk *walk, git_vector *commits, uint32_t min done: git__free(redundant); git__free(filled_index); - git_vector_free(&work); + git_vector_dispose(&work); return error; } @@ -570,7 +570,7 @@ int git_merge__bases_many( if ((error = clear_commit_marks(one, ALL_FLAGS)) < 0 || (error = clear_commit_marks_many(twos, ALL_FLAGS)) < 0 || (error = remove_redundant(walk, &redundant, minimum_generation)) < 0) { - git_vector_free(&redundant); + git_vector_dispose(&redundant); return error; } @@ -579,7 +579,7 @@ int git_merge__bases_many( git_commit_list_insert_by_date(two, &result); } - git_vector_free(&redundant); + git_vector_dispose(&redundant); } *out = result; @@ -1866,9 +1866,9 @@ void git_merge_diff_list__free(git_merge_diff_list *diff_list) if (!diff_list) return; - git_vector_free(&diff_list->staged); - git_vector_free(&diff_list->conflicts); - git_vector_free(&diff_list->resolved); + git_vector_dispose(&diff_list->staged); + git_vector_dispose(&diff_list->conflicts); + git_vector_dispose(&diff_list->resolved); git_pool_clear(&diff_list->pool); git__free(diff_list); } @@ -2836,7 +2836,7 @@ static int write_merge_msg( git_str_dispose(&file_path); - git_vector_free(&matching); + git_vector_dispose(&matching); git__free(entries); return error; @@ -3015,7 +3015,7 @@ static int merge_check_index(size_t *conflicts, git_repository *repo, git_index git_iterator_free(iter_new); git_diff_free(staged_diff_list); git_diff_free(index_diff_list); - git_vector_free(&staged_paths); + git_vector_dispose(&staged_paths); return error; } @@ -3112,7 +3112,7 @@ int git_merge__check_result(git_repository *repo, git_index *index_new) } done: - git_vector_free(&paths); + git_vector_dispose(&paths); git_tree_free(head_tree); git_iterator_free(iter_head); git_iterator_free(iter_new); diff --git a/src/libgit2/merge_driver.c b/src/libgit2/merge_driver.c index 19b35ac0ea6..300964afdea 100644 --- a/src/libgit2/merge_driver.c +++ b/src/libgit2/merge_driver.c @@ -218,7 +218,7 @@ int git_merge_driver_global_init(void) done: if (error < 0) - git_vector_free_deep(&merge_driver_registry.drivers); + git_vector_dispose_deep(&merge_driver_registry.drivers); return error; } @@ -238,7 +238,7 @@ static void git_merge_driver_global_shutdown(void) git__free(entry); } - git_vector_free(&merge_driver_registry.drivers); + git_vector_dispose(&merge_driver_registry.drivers); git_rwlock_wrunlock(&merge_driver_registry.lock); git_rwlock_free(&merge_driver_registry.lock); diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index 71bbb1d0eaf..9ec1c3dcd0e 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -484,7 +484,7 @@ int git_midx_close(git_midx_file *idx) if (idx->index_map.data) git_futils_mmap_free(&idx->index_map); - git_vector_free(&idx->packfile_names); + git_vector_dispose(&idx->packfile_names); return 0; } @@ -554,7 +554,7 @@ void git_midx_writer_free(git_midx_writer *w) git_vector_foreach (&w->packs, i, p) git_mwindow_put_pack(p); - git_vector_free(&w->packs); + git_vector_dispose(&w->packs); git_str_dispose(&w->pack_dir); git__free(w); } @@ -869,7 +869,7 @@ static int midx_write( cleanup: git_array_clear(object_entries_array); - git_vector_free(&object_entries); + git_vector_dispose(&object_entries); git_str_dispose(&packfile_names); git_str_dispose(&oid_lookup); git_str_dispose(&object_offsets); diff --git a/src/libgit2/mwindow.c b/src/libgit2/mwindow.c index b8295d9d119..2c50e068aaf 100644 --- a/src/libgit2/mwindow.c +++ b/src/libgit2/mwindow.c @@ -152,7 +152,7 @@ static int git_mwindow_free_all_locked(git_mwindow_file *mwf) } if (ctl->windowfiles.length == 0) { - git_vector_free(&ctl->windowfiles); + git_vector_dispose(&ctl->windowfiles); ctl->windowfiles.contents = NULL; } @@ -505,7 +505,7 @@ int git_mwindow_file_register(git_mwindow_file *mwf) } cleanup: - git_vector_free(&closed_files); + git_vector_dispose(&closed_files); return error; } diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 00e8bb5065b..2c308c97772 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -915,7 +915,7 @@ static void odb_free(git_odb *db) git_mutex_unlock(&db->lock); git_commit_graph_free(db->cgraph); - git_vector_free(&db->backends); + git_vector_dispose(&db->backends); git_cache_dispose(&db->own_cache); git_mutex_free(&db->lock); @@ -1609,7 +1609,7 @@ int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload) } cleanup: - git_vector_free(&backends); + git_vector_dispose(&backends); return error; } diff --git a/src/libgit2/odb_pack.c b/src/libgit2/odb_pack.c index fc533ae83e2..96d3a2be476 100644 --- a/src/libgit2/odb_pack.c +++ b/src/libgit2/odb_pack.c @@ -863,8 +863,8 @@ static void pack_backend__free(git_odb_backend *_backend) git_mwindow_put_pack(p); git_midx_free(backend->midx); - git_vector_free(&backend->midx_packs); - git_vector_free(&backend->packs); + git_vector_dispose(&backend->midx_packs); + git_vector_dispose(&backend->packs); git__free(backend->pack_folder); git__free(backend); } @@ -883,7 +883,7 @@ static int pack_backend__alloc( } if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) { - git_vector_free(&backend->midx_packs); + git_vector_dispose(&backend->midx_packs); git__free(backend); return -1; } diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index 1ff0eb0c9d9..642dcb8a004 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -1351,7 +1351,7 @@ int git_pack_foreach_entry( git_vector_insert(&oids, (void*)¤t[4]); } - git_vector_free(&offsets); + git_vector_dispose(&offsets); p->ids = (unsigned char **)git_vector_detach(NULL, NULL, &oids); } diff --git a/src/libgit2/pathspec.c b/src/libgit2/pathspec.c index 3e44643c675..26684c08104 100644 --- a/src/libgit2/pathspec.c +++ b/src/libgit2/pathspec.c @@ -105,7 +105,7 @@ int git_pathspec__vinit( /* free data from the pathspec vector */ void git_pathspec__vfree(git_vector *vspec) { - git_vector_free_deep(vspec); + git_vector_dispose_deep(vspec); } struct pathspec_match_context { diff --git a/src/libgit2/push.c b/src/libgit2/push.c index e065858826a..db5b5a63d3a 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -56,22 +56,22 @@ int git_push_new(git_push **out, git_remote *remote, const git_push_options *opt } if (git_vector_init(&p->status, 0, push_status_ref_cmp) < 0) { - git_vector_free(&p->specs); + git_vector_dispose(&p->specs); git__free(p); return -1; } if (git_vector_init(&p->updates, 0, NULL) < 0) { - git_vector_free(&p->status); - git_vector_free(&p->specs); + git_vector_dispose(&p->status); + git_vector_dispose(&p->specs); git__free(p); return -1; } if (git_vector_init(&p->remote_push_options, 0, git__strcmp_cb) < 0) { - git_vector_free(&p->status); - git_vector_free(&p->specs); - git_vector_free(&p->updates); + git_vector_dispose(&p->status); + git_vector_dispose(&p->specs); + git_vector_dispose(&p->updates); git__free(p); return -1; } @@ -568,24 +568,24 @@ void git_push_free(git_push *push) git_vector_foreach(&push->specs, i, spec) { free_refspec(spec); } - git_vector_free(&push->specs); + git_vector_dispose(&push->specs); git_vector_foreach(&push->status, i, status) { git_push_status_free(status); } - git_vector_free(&push->status); + git_vector_dispose(&push->status); git_vector_foreach(&push->updates, i, update) { git__free(update->src_refname); git__free(update->dst_refname); git__free(update); } - git_vector_free(&push->updates); + git_vector_dispose(&push->updates); git_vector_foreach(&push->remote_push_options, i, option) { git__free(option); } - git_vector_free(&push->remote_push_options); + git_vector_dispose(&push->remote_push_options); git__free(push); } diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 9a5c38ed63d..62727462012 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -801,7 +801,7 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter) { refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent); - git_vector_free(&iter->loose); + git_vector_dispose(&iter->loose); git_pool_clear(&iter->pool); git_sortedcache_free(iter->cache); git__free(iter); diff --git a/src/libgit2/reflog.c b/src/libgit2/reflog.c index 86d4355e336..2aebbc5285d 100644 --- a/src/libgit2/reflog.c +++ b/src/libgit2/reflog.c @@ -40,7 +40,7 @@ void git_reflog_free(git_reflog *reflog) git_reflog_entry__free(entry); } - git_vector_free(&reflog->entries); + git_vector_dispose(&reflog->entries); git__free(reflog->ref_name); git__free(reflog); } diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index c1ed04d233a..007af37fd18 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -808,7 +808,7 @@ int git_reference_list( if (git_reference_foreach_name( repo, &cb__reflist_add, (void *)&ref_list) < 0) { - git_vector_free(&ref_list); + git_vector_dispose(&ref_list); return -1; } diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 63f63e81b56..070b7df0665 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1293,9 +1293,9 @@ static int git_remote__download( free_refspecs(&remote->active_refspecs); error = dwim_refspecs(&remote->active_refspecs, to_active, &refs); - git_vector_free(&refs); + git_vector_dispose(&refs); free_refspecs(&specs); - git_vector_free(&specs); + git_vector_dispose(&specs); if (error < 0) goto on_error; @@ -1311,9 +1311,9 @@ static int git_remote__download( error = git_fetch_download_pack(remote); on_error: - git_vector_free(&refs); + git_vector_dispose(&refs); free_refspecs(&specs); - git_vector_free(&specs); + git_vector_dispose(&specs); return error; } @@ -1589,7 +1589,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git for (i = 0; i < fetchhead_refs.length; ++i) git_fetchhead_ref_free(fetchhead_refs.contents[i]); - git_vector_free(&fetchhead_refs); + git_vector_dispose(&fetchhead_refs); git_reference_free(head_ref); return error; @@ -1735,8 +1735,8 @@ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks) } cleanup: - git_vector_free(&remote_refs); - git_vector_free_deep(&candidates); + git_vector_dispose(&remote_refs); + git_vector_dispose_deep(&candidates); return error; } @@ -1947,12 +1947,12 @@ static int update_tips_for_spec( goto on_error; git_refspec__dispose(&tagspec); - git_vector_free(&update_heads); + git_vector_dispose(&update_heads); return 0; on_error: git_refspec__dispose(&tagspec); - git_vector_free(&update_heads); + git_vector_dispose(&update_heads); return -1; } @@ -2123,7 +2123,7 @@ int git_remote_update_tips( error = opportunistic_updates(remote, callbacks, &refs, reflog_message); out: - git_vector_free(&refs); + git_vector_dispose(&refs); git_refspec__dispose(&tagspec); return error; } @@ -2182,19 +2182,19 @@ void git_remote_free(git_remote *remote) remote->transport = NULL; } - git_vector_free(&remote->refs); + git_vector_dispose(&remote->refs); free_refspecs(&remote->refspecs); - git_vector_free(&remote->refspecs); + git_vector_dispose(&remote->refspecs); free_refspecs(&remote->active_refspecs); - git_vector_free(&remote->active_refspecs); + git_vector_dispose(&remote->active_refspecs); free_refspecs(&remote->passive_refspecs); - git_vector_free(&remote->passive_refspecs); + git_vector_dispose(&remote->passive_refspecs); free_heads(&remote->local_heads); - git_vector_free(&remote->local_heads); + git_vector_dispose(&remote->local_heads); git_push_free(remote->push); git__free(remote->url); @@ -2237,7 +2237,7 @@ int git_remote_list(git_strarray *remotes_list, git_repository *repo) cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list); if (error < 0) { - git_vector_free_deep(&list); + git_vector_dispose_deep(&list); return error; } @@ -2518,7 +2518,7 @@ static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const git_vector_foreach(problems, i, str) git__free(str); - git_vector_free(problems); + git_vector_dispose(problems); } return error; @@ -2558,7 +2558,7 @@ int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, cleanup: if (error < 0) - git_vector_free(&problem_refspecs); + git_vector_dispose(&problem_refspecs); git_remote_free(remote); return error; @@ -2665,7 +2665,7 @@ static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned return 0; on_error: - git_vector_free_deep(&refspecs); + git_vector_dispose_deep(&refspecs); return -1; } @@ -2813,7 +2813,7 @@ static int remove_refs(git_repository *repo, const git_refspec *spec) git_vector_foreach(&refs, i, dup) { git__free(dup); } - git_vector_free(&refs); + git_vector_dispose(&refs); return error; } diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 1277d7a2821..01fc25519a3 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -2107,7 +2107,7 @@ int git_repository__set_extensions(const char **extensions, size_t len) void git_repository__free_extensions(void) { - git_vector_free_deep(&user_extensions); + git_vector_dispose_deep(&user_extensions); } int git_repository_create_head(const char *git_dir, const char *ref_name) diff --git a/src/libgit2/status.c b/src/libgit2/status.c index df0f7450731..06356ad8b8b 100644 --- a/src/libgit2/status.c +++ b/src/libgit2/status.c @@ -414,7 +414,7 @@ void git_status_list_free(git_status_list *status) git_diff_free(status->head2idx); git_diff_free(status->idx2wd); - git_vector_free_deep(&status->paired); + git_vector_dispose_deep(&status->paired); git__memzero(status, sizeof(*status)); git__free(status); diff --git a/src/libgit2/submodule.c b/src/libgit2/submodule.c index 830d41c7d22..005085e99f2 100644 --- a/src/libgit2/submodule.c +++ b/src/libgit2/submodule.c @@ -668,7 +668,7 @@ int git_submodule_foreach( done: git_vector_foreach(&snapshot, i, sm) git_submodule_free(sm); - git_vector_free(&snapshot); + git_vector_dispose(&snapshot); git_strmap_foreach_value(submodules, sm, { git_submodule_free(sm); @@ -1338,11 +1338,11 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio /* Get the status of the submodule to determine if it is already initialized */ if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0) goto done; - + /* If the submodule is configured but hasn't been added, skip it */ if (submodule_status == GIT_SUBMODULE_STATUS_IN_CONFIG) goto done; - + /* * If submodule work dir is not already initialized, check to see * what we need to do (initialize, clone, return error...) diff --git a/src/libgit2/tag.c b/src/libgit2/tag.c index 562ec13eaed..cad9e416e5c 100644 --- a/src/libgit2/tag.c +++ b/src/libgit2/tag.c @@ -548,7 +548,7 @@ int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_reposit error = git_tag_foreach(repo, &tag_list_cb, (void *)&filter); if (error < 0) - git_vector_free(&taglist); + git_vector_dispose(&taglist); tag_names->strings = (char **)git_vector_detach(&tag_names->count, NULL, &taglist); diff --git a/src/libgit2/transport.c b/src/libgit2/transport.c index c61d0a68b7e..c31fca3a490 100644 --- a/src/libgit2/transport.c +++ b/src/libgit2/transport.c @@ -203,7 +203,7 @@ int git_transport_unregister(const char *scheme) git__free(d); if (!custom_transports.length) - git_vector_free(&custom_transports); + git_vector_dispose(&custom_transports); error = 0; goto done; diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index a0c4002e806..e25e0a73a6c 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -1442,9 +1442,9 @@ int git_http_client_read_response( git_http_response_dispose(response); if (client->current_server == PROXY) { - git_vector_free_deep(&client->proxy.auth_challenges); + git_vector_dispose_deep(&client->proxy.auth_challenges); } else if(client->current_server == SERVER) { - git_vector_free_deep(&client->server.auth_challenges); + git_vector_dispose_deep(&client->server.auth_challenges); } client->state = READING_RESPONSE; @@ -1605,7 +1605,7 @@ GIT_INLINE(void) http_server_close(git_http_server *server) git_net_url_dispose(&server->url); - git_vector_free_deep(&server->auth_challenges); + git_vector_dispose_deep(&server->auth_challenges); free_auth_context(server); } diff --git a/src/libgit2/transports/local.c b/src/libgit2/transports/local.c index 6c01141ce43..854390534f2 100644 --- a/src/libgit2/transports/local.c +++ b/src/libgit2/transports/local.c @@ -58,7 +58,7 @@ static void free_heads(git_vector *heads) git_vector_foreach(heads, i, head) free_head(head); - git_vector_free(heads); + git_vector_dispose(heads); } static int add_ref(transport_local *t, const char *name) @@ -182,7 +182,7 @@ static int store_refs(transport_local *t) return 0; on_error: - git_vector_free(&t->refs); + git_vector_dispose(&t->refs); git_strarray_dispose(&ref_names); return -1; } diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index be0cb7b05e4..7bf964ac2d9 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -124,7 +124,7 @@ static void free_symrefs(git_vector *symrefs) git__free(spec); } - git_vector_free(symrefs); + git_vector_dispose(symrefs); } static int git_smart__connect( @@ -402,7 +402,7 @@ static int git_smart__close(git_transport *transport) git_vector_foreach(common, i, p) git_pkt_free(p); - git_vector_free(common); + git_vector_dispose(common); if (t->url) { git__free(t->url); @@ -427,11 +427,11 @@ static void git_smart__free(git_transport *transport) /* Free the subtransport */ t->wrapped->free(t->wrapped); - git_vector_free(&t->heads); + git_vector_dispose(&t->heads); git_vector_foreach(refs, i, p) git_pkt_free(p); - git_vector_free(refs); + git_vector_dispose(refs); git_remote_connect_options_dispose(&t->connect_opts); @@ -524,8 +524,8 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0 || git_vector_init(&t->heads, 16, ref_name_cmp) < 0 || definition->callback(&t->wrapped, &t->parent, definition->param) < 0) { - git_vector_free(&t->refs); - git_vector_free(&t->heads); + git_vector_dispose(&t->refs); + git_vector_dispose(&t->heads); git__free(t); return -1; } diff --git a/src/libgit2/tree.c b/src/libgit2/tree.c index 18278d34e77..3e8d4fa3829 100644 --- a/src/libgit2/tree.c +++ b/src/libgit2/tree.c @@ -547,7 +547,7 @@ static int git_treebuilder__write_with_buffer( error = git_odb_write(oid, odb, buf->ptr, buf->size, GIT_OBJECT_TREE); out: - git_vector_free(&entries); + git_vector_dispose(&entries); return error; } @@ -1312,7 +1312,7 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli git_str_dispose(&component); git_array_clear(stack); - git_vector_free(&entries); + git_vector_dispose(&entries); return error; } diff --git a/src/util/pool.c b/src/util/pool.c index 16ffa398d65..afbae452a7b 100644 --- a/src/util/pool.c +++ b/src/util/pool.c @@ -144,7 +144,7 @@ int git_pool_init(git_pool *pool, size_t item_size) void git_pool_clear(git_pool *pool) { - git_vector_free_deep(&pool->allocations); + git_vector_dispose_deep(&pool->allocations); } static void *pool_alloc(git_pool *pool, size_t size) { diff --git a/src/util/pqueue.h b/src/util/pqueue.h index 97232b4a9fd..a8ef018454e 100644 --- a/src/util/pqueue.h +++ b/src/util/pqueue.h @@ -33,7 +33,7 @@ extern int git_pqueue_init( size_t init_size, git_vector_cmp cmp); -#define git_pqueue_free git_vector_free +#define git_pqueue_free git_vector_dispose #define git_pqueue_clear git_vector_clear #define git_pqueue_size git_vector_length #define git_pqueue_get git_vector_get diff --git a/src/util/sortedcache.c b/src/util/sortedcache.c index 7ff900efe33..6e421aa2e81 100644 --- a/src/util/sortedcache.c +++ b/src/util/sortedcache.c @@ -47,7 +47,7 @@ int git_sortedcache_new( fail: git_strmap_free(sc->map); - git_vector_free(&sc->items); + git_vector_dispose(&sc->items); git_pool_clear(&sc->pool); git__free(sc); return -1; @@ -88,7 +88,7 @@ static void sortedcache_free(git_sortedcache *sc) return; sortedcache_clear(sc); - git_vector_free(&sc->items); + git_vector_dispose(&sc->items); git_strmap_free(sc->map); git_sortedcache_wunlock(sc); diff --git a/src/util/unix/process.c b/src/util/unix/process.c index 68c0384a4c4..a1a2cf11648 100644 --- a/src/util/unix/process.c +++ b/src/util/unix/process.c @@ -104,7 +104,7 @@ static int merge_env( return 0; on_error: - git_vector_free_deep(&merged); + git_vector_dispose_deep(&merged); return error; } diff --git a/src/util/vector.c b/src/util/vector.c index 4a4bc8c0e44..34ac3bb9c5b 100644 --- a/src/util/vector.c +++ b/src/util/vector.c @@ -76,7 +76,7 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) return 0; } -void git_vector_free(git_vector *v) +void git_vector_dispose(git_vector *v) { if (!v) return; @@ -88,7 +88,7 @@ void git_vector_free(git_vector *v) v->_alloc_size = 0; } -void git_vector_free_deep(git_vector *v) +void git_vector_dispose_deep(git_vector *v) { size_t i; @@ -100,7 +100,7 @@ void git_vector_free_deep(git_vector *v) v->contents[i] = NULL; } - git_vector_free(v); + git_vector_dispose(v); } int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp) diff --git a/src/util/vector.h b/src/util/vector.h index e50cdfefcbd..02f82b30d03 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -28,8 +28,8 @@ typedef struct git_vector { GIT_WARN_UNUSED_RESULT int git_vector_init( git_vector *v, size_t initial_size, git_vector_cmp cmp); -void git_vector_free(git_vector *v); -void git_vector_free_deep(git_vector *v); /* free each entry and self */ +void git_vector_dispose(git_vector *v); +void git_vector_dispose_deep(git_vector *v); /* free each entry and self */ void git_vector_clear(git_vector *v); GIT_WARN_UNUSED_RESULT int git_vector_dup( git_vector *v, const git_vector *src, git_vector_cmp cmp); diff --git a/tests/libgit2/checkout/conflict.c b/tests/libgit2/checkout/conflict.c index 3539c8b2dee..d6cb6fff231 100644 --- a/tests/libgit2/checkout/conflict.c +++ b/tests/libgit2/checkout/conflict.c @@ -1141,5 +1141,5 @@ void test_checkout_conflict__report_progress(void) git_vector_foreach(&paths, i, path) git__free(path); - git_vector_free(&paths); + git_vector_dispose(&paths); } diff --git a/tests/libgit2/checkout/crlf.c b/tests/libgit2/checkout/crlf.c index 21f8a852a64..2ab970cd0b8 100644 --- a/tests/libgit2/checkout/crlf.c +++ b/tests/libgit2/checkout/crlf.c @@ -197,7 +197,7 @@ static void empty_workdir(const char *name) if (cmp) cl_git_pass(p_unlink(fn)); } - git_vector_free_deep(&contents); + git_vector_dispose_deep(&contents); } void test_checkout_crlf__matches_core_git(void) diff --git a/tests/libgit2/diff/drivers.c b/tests/libgit2/diff/drivers.c index 304a54b56dc..0dc2879800b 100644 --- a/tests/libgit2/diff/drivers.c +++ b/tests/libgit2/diff/drivers.c @@ -249,7 +249,7 @@ void test_diff_drivers__builtins(void) git_buf_dispose(&actual); git_str_dispose(&file); git_str_dispose(&expected); - git_vector_free(&files); + git_vector_dispose(&files); } void test_diff_drivers__invalid_pattern(void) diff --git a/tests/libgit2/diff/workdir.c b/tests/libgit2/diff/workdir.c index 504ece6fc91..c2a0c79283e 100644 --- a/tests/libgit2/diff/workdir.c +++ b/tests/libgit2/diff/workdir.c @@ -2136,7 +2136,7 @@ void test_diff_workdir__to_index_pathlist(void) git_diff_free(diff); git_index_free(index); - git_vector_free(&pathlist); + git_vector_dispose(&pathlist); } void test_diff_workdir__symlink_changed_on_non_symlink_platform(void) @@ -2198,7 +2198,7 @@ void test_diff_workdir__symlink_changed_on_non_symlink_platform(void) cl_git_pass(git_futils_rmdir_r("symlink", NULL, GIT_RMDIR_REMOVE_FILES)); git_tree_free(tree); - git_vector_free(&pathlist); + git_vector_dispose(&pathlist); } void test_diff_workdir__order(void) diff --git a/tests/libgit2/fetchhead/nonetwork.c b/tests/libgit2/fetchhead/nonetwork.c index 2519d895e29..e92b85fa53c 100644 --- a/tests/libgit2/fetchhead/nonetwork.c +++ b/tests/libgit2/fetchhead/nonetwork.c @@ -106,7 +106,7 @@ void test_fetchhead_nonetwork__write(void) git_fetchhead_ref_free(fetchhead_ref); } - git_vector_free(&fetchhead_vector); + git_vector_dispose(&fetchhead_vector); cl_assert(equals); } @@ -166,7 +166,7 @@ void test_fetchhead_nonetwork__read(void) git_fetchhead_ref_free(fetchhead_ref); } - git_vector_free(&fetchhead_vector); + git_vector_dispose(&fetchhead_vector); } static int read_old_style_cb(const char *name, const char *url, diff --git a/tests/libgit2/graph/reachable_from_any.c b/tests/libgit2/graph/reachable_from_any.c index 8e1c23874d9..04706fbb456 100644 --- a/tests/libgit2/graph/reachable_from_any.c +++ b/tests/libgit2/graph/reachable_from_any.c @@ -231,6 +231,6 @@ void test_graph_reachable_from_any__exhaustive(void) git_vector_foreach (&mc.commits, child_idx, child_commit) git_commit_free(child_commit); git_bitvec_free(&reachable); - git_vector_free(&mc.commits); + git_vector_dispose(&mc.commits); git_odb_free(mc.db); } diff --git a/tests/libgit2/index/crlf.c b/tests/libgit2/index/crlf.c index 666ac1a0c4c..0a7d51aed4d 100644 --- a/tests/libgit2/index/crlf.c +++ b/tests/libgit2/index/crlf.c @@ -190,7 +190,7 @@ static void set_up_workingdir(const char *name) continue; p_unlink(fn); } - git_vector_free_deep(&contents); + git_vector_dispose_deep(&contents); /* copy input files */ git_fs_path_dirload(&contents, cl_fixture("crlf"), 0, 0); @@ -207,7 +207,7 @@ static void set_up_workingdir(const char *name) git__free(basename); git_str_dispose(&dest_filename); } - git_vector_free_deep(&contents); + git_vector_dispose_deep(&contents); } void test_index_crlf__matches_core_git(void) diff --git a/tests/libgit2/iterator/index.c b/tests/libgit2/iterator/index.c index a0083479d39..e5ebec60c18 100644 --- a/tests/libgit2/iterator/index.c +++ b/tests/libgit2/iterator/index.c @@ -627,7 +627,7 @@ void test_iterator_index__pathlist(void) } git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__pathlist_with_dirs(void) @@ -728,7 +728,7 @@ void test_iterator_index__pathlist_with_dirs(void) } git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__pathlist_with_dirs_include_trees(void) @@ -759,7 +759,7 @@ void test_iterator_index__pathlist_with_dirs_include_trees(void) git_iterator_free(i); git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__pathlist_1(void) @@ -799,7 +799,7 @@ void test_iterator_index__pathlist_1(void) git_iterator_free(i); git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__pathlist_2(void) @@ -841,7 +841,7 @@ void test_iterator_index__pathlist_2(void) git_iterator_free(i); git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__pathlist_four(void) @@ -883,7 +883,7 @@ void test_iterator_index__pathlist_four(void) git_iterator_free(i); git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__pathlist_icase(void) @@ -946,7 +946,7 @@ void test_iterator_index__pathlist_icase(void) cl_git_pass(git_index_set_caps(index, caps)); git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__pathlist_with_directory(void) @@ -973,7 +973,7 @@ void test_iterator_index__pathlist_with_directory(void) git_index_free(index); git_tree_free(tree); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } static void create_paths(git_index *index, const char *root, int depth) @@ -1131,7 +1131,7 @@ void test_iterator_index__pathlist_for_deeply_nested_item(void) } git_index_free(index); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_index__advance_over(void) diff --git a/tests/libgit2/iterator/tree.c b/tests/libgit2/iterator/tree.c index 7dfee28be51..81035bb8deb 100644 --- a/tests/libgit2/iterator/tree.c +++ b/tests/libgit2/iterator/tree.c @@ -911,7 +911,7 @@ void test_iterator_tree__pathlist(void) expect_iterator_items(i, expect, NULL, expect, NULL); git_iterator_free(i); - git_vector_free(&filelist); + git_vector_dispose(&filelist); git_tree_free(tree); } @@ -968,7 +968,7 @@ void test_iterator_tree__pathlist_icase(void) expect_iterator_items(i, 2, NULL, 2, NULL); git_iterator_free(i); - git_vector_free(&filelist); + git_vector_dispose(&filelist); git_tree_free(tree); } @@ -1021,7 +1021,7 @@ void test_iterator_tree__pathlist_with_directory(void) git_iterator_free(i); git_tree_free(tree); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_tree__pathlist_with_directory_include_tree_nodes(void) @@ -1050,7 +1050,7 @@ void test_iterator_tree__pathlist_with_directory_include_tree_nodes(void) git_iterator_free(i); git_tree_free(tree); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_tree__pathlist_no_match(void) @@ -1075,6 +1075,6 @@ void test_iterator_tree__pathlist_no_match(void) git_iterator_free(i); git_tree_free(tree); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } diff --git a/tests/libgit2/iterator/workdir.c b/tests/libgit2/iterator/workdir.c index af47d8b3601..327f1f65b66 100644 --- a/tests/libgit2/iterator/workdir.c +++ b/tests/libgit2/iterator/workdir.c @@ -917,7 +917,7 @@ void test_iterator_workdir__pathlist(void) git_iterator_free(i); } - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_workdir__pathlist_with_dirs(void) @@ -1014,7 +1014,7 @@ void test_iterator_workdir__pathlist_with_dirs(void) git_iterator_free(i); } - git_vector_free(&filelist); + git_vector_dispose(&filelist); } static void create_paths(const char *root, int depth) @@ -1175,7 +1175,7 @@ void test_iterator_workdir__pathlist_for_deeply_nested_item(void) git_iterator_free(i); } - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_workdir__bounded_submodules(void) @@ -1258,7 +1258,7 @@ void test_iterator_workdir__bounded_submodules(void) git_iterator_free(i); } - git_vector_free(&filelist); + git_vector_dispose(&filelist); git_index_free(index); git_tree_free(head); } @@ -1380,7 +1380,7 @@ void test_iterator_workdir__advance_over_with_pathlist(void) cl_git_fail_with(GIT_ITEROVER, git_iterator_advance(NULL, i)); git_iterator_free(i); - git_vector_free(&pathlist); + git_vector_dispose(&pathlist); } void test_iterator_workdir__advance_into(void) @@ -1447,7 +1447,7 @@ void test_iterator_workdir__pathlist_with_directory(void) expect_iterator_items(i, expected_len, expected, expected_len, expected); git_iterator_free(i); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_workdir__pathlist_with_directory_include_trees(void) @@ -1473,7 +1473,7 @@ void test_iterator_workdir__pathlist_with_directory_include_trees(void) expect_iterator_items(i, expected_len, expected, expected_len, expected); git_iterator_free(i); - git_vector_free(&filelist); + git_vector_dispose(&filelist); } void test_iterator_workdir__hash_when_requested(void) diff --git a/tests/libgit2/network/remote/rename.c b/tests/libgit2/network/remote/rename.c index 21ea216545c..e02a4ce35c3 100644 --- a/tests/libgit2/network/remote/rename.c +++ b/tests/libgit2/network/remote/rename.c @@ -238,7 +238,7 @@ void test_network_remote_rename__symref_head(void) cl_assert_equal_s("be3563ae3f795b2b4353bcce3a527ad0a4f7f644", idstr); git_reference_free(ref); - git_vector_free(&refs); + git_vector_dispose(&refs); cl_git_fail_with(GIT_ITEROVER, git_branch_next(&ref, &btype, iter)); git_branch_iterator_free(iter); diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index e5693bf346c..dd221f44443 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -165,7 +165,7 @@ static void do_verify_push_status(record_callbacks_data *data, const push_status git__free(s); } - git_vector_free(actual); + git_vector_dispose(actual); } /** @@ -272,7 +272,7 @@ static void verify_tracking_branches(git_remote *remote, expected_ref expected_r git_vector_foreach(&actual_refs, i, actual_ref) git__free(actual_ref); - git_vector_free(&actual_refs); + git_vector_dispose(&actual_refs); git_str_dispose(&msg); git_buf_dispose(&ref_name); } @@ -416,7 +416,7 @@ void test_online_push__initialize(void) } git_remote_disconnect(_remote); - git_vector_free_deep(&delete_specs); + git_vector_dispose_deep(&delete_specs); /* Now that we've deleted everything, fetch from the remote */ memcpy(&fetch_opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks)); diff --git a/tests/libgit2/online/push_util.c b/tests/libgit2/online/push_util.c index 94919e9b2a2..372eec8aab2 100644 --- a/tests/libgit2/online/push_util.c +++ b/tests/libgit2/online/push_util.c @@ -24,12 +24,12 @@ void record_callbacks_data_clear(record_callbacks_data *data) git_vector_foreach(&data->updated_tips, i, tip) updated_tip_free(tip); - git_vector_free(&data->updated_tips); + git_vector_dispose(&data->updated_tips); git_vector_foreach(&data->statuses, i, status) push_status_free(status); - git_vector_free(&data->statuses); + git_vector_dispose(&data->statuses); data->pack_progress_calls = 0; data->transfer_progress_calls = 0; diff --git a/tests/libgit2/pack/packbuilder.c b/tests/libgit2/pack/packbuilder.c index 7da3877e451..05dea29d10e 100644 --- a/tests/libgit2/pack/packbuilder.c +++ b/tests/libgit2/pack/packbuilder.c @@ -42,7 +42,7 @@ void test_pack_packbuilder__cleanup(void) git_vector_foreach(&_commits, i, o) { git__free(o); } - git_vector_free(&_commits); + git_vector_dispose(&_commits); } git_packbuilder_free(_packbuilder); diff --git a/tests/libgit2/refs/iterator.c b/tests/libgit2/refs/iterator.c index 706fd1ef7e0..020ee01a484 100644 --- a/tests/libgit2/refs/iterator.c +++ b/tests/libgit2/refs/iterator.c @@ -96,7 +96,7 @@ static void assert_all_refnames_match(const char **expected, git_vector *names) } cl_assert(expected[i] == NULL); - git_vector_free(names); + git_vector_dispose(names); } void test_refs_iterator__list(void) @@ -222,7 +222,7 @@ void test_refs_iterator__foreach_name(void) git__free(name); } - git_vector_free(&output); + git_vector_dispose(&output); } static int refs_foreach_name_cancel_cb(const char *name, void *payload) diff --git a/tests/util/process/env.c b/tests/util/process/env.c index bb7dbcdcdfd..a6dc62e7e42 100644 --- a/tests/util/process/env.c +++ b/tests/util/process/env.c @@ -19,7 +19,7 @@ void test_process_env__initialize(void) void test_process_env__cleanup(void) { - git_vector_free(&env_result); + git_vector_dispose(&env_result); git_str_dispose(&accumulator); git_str_dispose(&env_cmd); } diff --git a/tests/util/vector.c b/tests/util/vector.c index 04afaa49658..66f6b383406 100644 --- a/tests/util/vector.c +++ b/tests/util/vector.c @@ -12,7 +12,7 @@ void test_vector__0(void) for (i = 0; i < 10; ++i) { git_vector_insert(&x, (void*) 0xabc); } - git_vector_free(&x); + git_vector_dispose(&x); } @@ -27,7 +27,7 @@ void test_vector__1(void) git_vector_insert(&x, (void*) 0x123); git_vector_remove(&x, 0); /* used to read past array bounds. */ - git_vector_free(&x); + git_vector_dispose(&x); } @@ -59,7 +59,7 @@ void test_vector__2(void) git_vector_uniq(&x, NULL); cl_assert(x.length == 2); - git_vector_free(&x); + git_vector_dispose(&x); git__free(ptrs[0]); git__free(ptrs[1]); @@ -91,7 +91,7 @@ void test_vector__3(void) cl_assert(git_vector_get(&x, i) == (void*)(i + 1)); } - git_vector_free(&x); + git_vector_dispose(&x); } /* insert_sorted with duplicates */ @@ -122,7 +122,7 @@ void test_vector__4(void) cl_assert(git_vector_get(&x, i) == (void*)(i / 2 + 1)); } - git_vector_free(&x); + git_vector_dispose(&x); } typedef struct { @@ -189,7 +189,7 @@ void test_vector__5(void) _struct_count--; } - git_vector_free(&x); + git_vector_dispose(&x); } static int remove_ones(const git_vector *v, size_t idx, void *p) @@ -274,7 +274,7 @@ void test_vector__remove_matching(void) git_vector_remove_matching(&x, remove_ones, NULL); cl_assert(x.length == 4); - git_vector_free(&x); + git_vector_dispose(&x); } static void assert_vector(git_vector *x, void *expected[], size_t len) @@ -376,7 +376,7 @@ void test_vector__grow_and_shrink(void) git_vector_remove_range(&x, 0, 1); assert_vector(&x, NULL, 0); - git_vector_free(&x); + git_vector_dispose(&x); } void test_vector__reverse(void) @@ -407,7 +407,7 @@ void test_vector__reverse(void) for (i = 0; i < 5; i++) cl_assert_equal_p(out2[i], git_vector_get(&v, i)); - git_vector_free(&v); + git_vector_dispose(&v); } void test_vector__dup_empty_vector(void) @@ -426,5 +426,5 @@ void test_vector__dup_empty_vector(void) cl_assert_equal_i(8, dup._alloc_size); cl_assert_equal_i(1, dup.length); - git_vector_free(&dup); + git_vector_dispose(&dup); } From e0b8b4b960af58efb87a698c59c919f66ed02a89 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:13:44 +0100 Subject: [PATCH 589/816] Add LIBGIT2_VERSION_CHECK and LIBGIT2_VERSION_NUMBER --- include/git2/version.h | 31 ++++++++++++++++++------------- tests/libgit2/core/version.c | 12 ++++++++++++ 2 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 tests/libgit2/core/version.c diff --git a/include/git2/version.h b/include/git2/version.h index 714e2d20e6a..e11c3c582d8 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -40,20 +40,25 @@ */ #define LIBGIT2_SOVERSION "1.8" -/* - * LIBGIT2_VERSION_CHECK: - * This macro can be used to compare against a specific libgit2 version. - * It takes the major, minor, and patch version as parameters. - * - * Usage Example: - * - * #if LIBGIT2_VERSION_CHECK(1, 7, 0) >= LIBGIT2_VERSION_NUMBER - * // This code will only compile if libgit2 version is >= 1.7.0 - * #endif +/** + * An integer value representing the libgit2 version number. For example, + * libgit2 1.6.3 is 1060300. */ -#define LIBGIT2_VER_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) +#define LIBGIT2_VERSION_NUMBER ( \ + (LIBGIT2_VER_MAJOR * 1000000) + \ + (LIBGIT2_VER_MINOR * 10000) + \ + (LIBGIT2_VER_REVISION * 100)) -/* Macro to get the current version as a single integer */ -#define LIBGIT2_VER_NUMBER LIBGIT2_VERSION_CHECK(LIBGIT2_VER_MAJOR, LIBGIT2_VER_MINOR, LIBGIT2_VER_PATCH) +/** + * Compare the libgit2 version against a given version. Evaluates to true + * if the given major, minor, and revision values are greater than or equal + * to the currently running libgit2 version. For example: + * + * #if LIBGIT2_VERSION_CHECK(1, 6, 3) + * # error libgit2 version is >= 1.6.3 + * #endif + */ +#define LIBGIT2_VERSION_CHECK(major, minor, revision) \ + (LIBGIT2_VERSION_NUMBER >= ((major)*1000000)+((minor)*10000)+((revision)*100)) #endif diff --git a/tests/libgit2/core/version.c b/tests/libgit2/core/version.c new file mode 100644 index 00000000000..32498c41d3f --- /dev/null +++ b/tests/libgit2/core/version.c @@ -0,0 +1,12 @@ +#include "clar_libgit2.h" + +void test_core_version__check(void) +{ +#if !LIBGIT2_VERSION_CHECK(1,6,3) + cl_fail("version check"); +#endif + +#if LIBGIT2_VERSION_CHECK(99,99,99) + cl_fail("version check"); +#endif +} From 50d492063a3382f09920b1e132b180285232a686 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:22:56 +0100 Subject: [PATCH 590/816] Rename version constants to LIBGIT2_VERSION For consistency, use LIBGIT2_VERSION_... as the constant name; deprecate LIBGIT2_VER_... names. --- include/git2/deprecated.h | 18 ++++++++++++++++++ include/git2/version.h | 20 ++++++++++---------- src/libgit2/git2.rc | 4 ++-- src/libgit2/libgit2.c | 8 ++++---- tests/libgit2/core/features.c | 6 +++--- 5 files changed, 37 insertions(+), 19 deletions(-) diff --git a/include/git2/deprecated.h b/include/git2/deprecated.h index 52864ebe166..49ac9c87f7d 100644 --- a/include/git2/deprecated.h +++ b/include/git2/deprecated.h @@ -892,6 +892,24 @@ GIT_EXTERN(void) git_strarray_free(git_strarray *array); /**@}*/ +/** @name Deprecated Version Constants + * + * These constants are retained for backward compatibility. The newer + * versions of these constants should be preferred in all new code. + * + * There is no plan to remove these backward compatibility constants at + * this time. + */ +/**@{*/ + +#define LIBGIT2_VER_MAJOR LIBGIT2_VERSION_MAJOR +#define LIBGIT2_VER_MINOR LIBGIT2_VERSION_MINOR +#define LIBGIT2_VER_REVISION LIBGIT2_VERSION_REVISION +#define LIBGIT2_VER_PATCH LIBGIT2_VERSION_PATCH +#define LIBGIT2_VER_PRERELEASE LIBGIT2_VERSION_PRERELEASE + +/**@}*/ + /** @name Deprecated Options Initialization Functions * * These functions are retained for backward compatibility. The newer diff --git a/include/git2/version.h b/include/git2/version.h index e11c3c582d8..8cde510d67e 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,19 +11,19 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.8.2" +#define LIBGIT2_VERSION "1.8.2" /** The major version number for this version of libgit2. */ -#define LIBGIT2_VER_MAJOR 1 +#define LIBGIT2_VERSION_MAJOR 1 /** The minor version number for this version of libgit2. */ -#define LIBGIT2_VER_MINOR 8 +#define LIBGIT2_VERSION_MINOR 8 /** The revision ("teeny") version number for this version of libgit2. */ -#define LIBGIT2_VER_REVISION 2 +#define LIBGIT2_VERSION_REVISION 2 /** The Windows DLL patch number for this version of libgit2. */ -#define LIBGIT2_VER_PATCH 0 +#define LIBGIT2_VERSION_PATCH 0 /** * The prerelease string for this version of libgit2. For development @@ -31,23 +31,23 @@ * a prerelease name like "beta" or "rc1". For final releases, this will * be `NULL`. */ -#define LIBGIT2_VER_PRERELEASE NULL +#define LIBGIT2_VERSION_PRERELEASE NULL /** * The library ABI soversion for this version of libgit2. This should * only be changed when the library has a breaking ABI change, and so * may trail the library's version number. */ -#define LIBGIT2_SOVERSION "1.8" +#define LIBGIT2_SOVERSION "1.8" /** * An integer value representing the libgit2 version number. For example, * libgit2 1.6.3 is 1060300. */ #define LIBGIT2_VERSION_NUMBER ( \ - (LIBGIT2_VER_MAJOR * 1000000) + \ - (LIBGIT2_VER_MINOR * 10000) + \ - (LIBGIT2_VER_REVISION * 100)) + (LIBGIT2_VERSION_MAJOR * 1000000) + \ + (LIBGIT2_VERSION_MINOR * 10000) + \ + (LIBGIT2_VERSION_REVISION * 100)) /** * Compare the libgit2 version against a given version. Evaluates to true diff --git a/src/libgit2/git2.rc b/src/libgit2/git2.rc index b94ecafd774..07592d15220 100644 --- a/src/libgit2/git2.rc +++ b/src/libgit2/git2.rc @@ -25,8 +25,8 @@ VS_VERSION_INFO VERSIONINFO #else VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE #endif - FILEVERSION LIBGIT2_VER_MAJOR,LIBGIT2_VER_MINOR,LIBGIT2_VER_REVISION,LIBGIT2_VER_PATCH - PRODUCTVERSION LIBGIT2_VER_MAJOR,LIBGIT2_VER_MINOR,LIBGIT2_VER_REVISION,LIBGIT2_VER_PATCH + FILEVERSION LIBGIT2_VERSION_MAJOR,LIBGIT2_VERSION_MINOR,LIBGIT2_VERSION_REVISION,LIBGIT2_VERSION_PATCH + PRODUCTVERSION LIBGIT2_VERSION_MAJOR,LIBGIT2_VERSION_MINOR,LIBGIT2_VERSION_REVISION,LIBGIT2_VERSION_PATCH FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 1b6f1a1f846..1375d87afc3 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -66,16 +66,16 @@ int git_libgit2_shutdown(void) int git_libgit2_version(int *major, int *minor, int *rev) { - *major = LIBGIT2_VER_MAJOR; - *minor = LIBGIT2_VER_MINOR; - *rev = LIBGIT2_VER_REVISION; + *major = LIBGIT2_VERSION_MAJOR; + *minor = LIBGIT2_VERSION_MINOR; + *rev = LIBGIT2_VERSION_REVISION; return 0; } const char *git_libgit2_prerelease(void) { - return LIBGIT2_VER_PRERELEASE; + return LIBGIT2_VERSION_PRERELEASE; } int git_libgit2_features(void) diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 7b28cc0cb41..a0f18b65941 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -5,9 +5,9 @@ void test_core_features__0(void) int major, minor, rev, caps; git_libgit2_version(&major, &minor, &rev); - cl_assert_equal_i(LIBGIT2_VER_MAJOR, major); - cl_assert_equal_i(LIBGIT2_VER_MINOR, minor); - cl_assert_equal_i(LIBGIT2_VER_REVISION, rev); + cl_assert_equal_i(LIBGIT2_VERSION_MAJOR, major); + cl_assert_equal_i(LIBGIT2_VERSION_MINOR, minor); + cl_assert_equal_i(LIBGIT2_VERSION_REVISION, rev); caps = git_libgit2_features(); From 7dfa08bec289fbd62fa7a0dd349fe237ccca5ae1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 16:19:35 +0100 Subject: [PATCH 591/816] openssl: provide internal context reset function We provide functionality for callers to mutate the SSL context. We want to test these various mutations, but OpenSSL does not provide a mechanism to _reset_ these mutations (short of burning down the SSL context). Provide an internal mechanism to reset the state for our own tests. --- src/libgit2/streams/openssl.c | 10 ++++++++-- src/libgit2/streams/openssl.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index afc43edf3ca..f531d1bc8f1 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -729,17 +729,23 @@ int git_openssl__add_x509_cert(X509 *cert) if (openssl_ensure_initialized() < 0) return -1; - if (!(cert_store = SSL_CTX_get_cert_store(git__ssl_ctx))) + if (!(cert_store = SSL_CTX_get_cert_store(git__ssl_ctx))) return -1; if (cert && X509_STORE_add_cert(cert_store, cert) == 0) { git_error_set(GIT_ERROR_SSL, "OpenSSL error: failed to add raw X509 certificate"); return -1; } - + return 0; } +int git_openssl__reset_context(void) +{ + shutdown_ssl(); + return openssl_init(); +} + #else #include "stream.h" diff --git a/src/libgit2/streams/openssl.h b/src/libgit2/streams/openssl.h index e503cbc6df6..a3ef1a93343 100644 --- a/src/libgit2/streams/openssl.h +++ b/src/libgit2/streams/openssl.h @@ -25,6 +25,7 @@ extern int git_openssl_stream_global_init(void); #ifdef GIT_OPENSSL extern int git_openssl__set_cert_location(const char *file, const char *path); extern int git_openssl__add_x509_cert(X509 *cert); +extern int git_openssl__reset_context(void); extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port); extern int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host); #endif From 33938b3df7321fb9e5f86163cae24a699602e10e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 16:19:01 +0100 Subject: [PATCH 592/816] openssl: update custom cert tests Update the custom cert tests to test various custom certificates. --- tests/libgit2/online/customcert.c | 95 ++++++++++++++++------------ tests/resources/certs/README | 5 ++ tests/resources/certs/one/61f2ddb6.0 | 31 +++++++++ tests/resources/certs/one/db4f60b0.0 | 31 +++++++++ tests/resources/certs/three.pem | 33 ++++++++++ tests/resources/certs/three.pem.raw | 1 + tests/resources/certs/two.pem | 20 ++++++ 7 files changed, 174 insertions(+), 42 deletions(-) create mode 100644 tests/resources/certs/README create mode 100644 tests/resources/certs/one/61f2ddb6.0 create mode 100644 tests/resources/certs/one/db4f60b0.0 create mode 100644 tests/resources/certs/three.pem create mode 100644 tests/resources/certs/three.pem.raw create mode 100644 tests/resources/certs/two.pem diff --git a/tests/libgit2/online/customcert.c b/tests/libgit2/online/customcert.c index d25b6282b3b..3acb880641e 100644 --- a/tests/libgit2/online/customcert.c +++ b/tests/libgit2/online/customcert.c @@ -10,63 +10,49 @@ #include "str.h" #include "streams/openssl.h" +#ifdef GIT_OPENSSL +# include +# include +# include +#endif + /* - * Certificate one is in the `certs` folder; certificate two is in the - * `self-signed.pem` file. + * Certificates for https://test.libgit2.org/ are in the `certs` folder. */ +#define CUSTOM_CERT_DIR "certs" + #define CUSTOM_CERT_ONE_URL "https://test.libgit2.org:1443/anonymous/test.git" -#define CUSTOM_CERT_ONE_PATH "certs" +#define CUSTOM_CERT_ONE_PATH "one" #define CUSTOM_CERT_TWO_URL "https://test.libgit2.org:2443/anonymous/test.git" -#define CUSTOM_CERT_TWO_FILE "self-signed.pem" +#define CUSTOM_CERT_TWO_FILE "two.pem" #define CUSTOM_CERT_THREE_URL "https://test.libgit2.org:3443/anonymous/test.git" -#define CUSTOM_CERT_THREE_FILE "self-signed.pem.raw" +#define CUSTOM_CERT_THREE_FILE "three.pem.raw" #if (GIT_OPENSSL || GIT_MBEDTLS) static git_repository *g_repo; -static int initialized = false; #endif void test_online_customcert__initialize(void) { #if (GIT_OPENSSL || GIT_MBEDTLS) + git_str path = GIT_STR_INIT, file = GIT_STR_INIT; + char cwd[GIT_PATH_MAX]; + g_repo = NULL; - if (!initialized) { - git_str path = GIT_STR_INIT, file = GIT_STR_INIT, raw_file = GIT_STR_INIT, raw_file_buf = GIT_STR_INIT, raw_cert = GIT_STR_INIT; - char cwd[GIT_PATH_MAX]; - const unsigned char* raw_cert_bytes = NULL; - X509* x509_cert = NULL; - - cl_fixture_sandbox(CUSTOM_CERT_ONE_PATH); - cl_fixture_sandbox(CUSTOM_CERT_TWO_FILE); - cl_fixture_sandbox(CUSTOM_CERT_THREE_FILE); - - cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX)); - cl_git_pass(git_str_joinpath(&path, cwd, CUSTOM_CERT_ONE_PATH)); - cl_git_pass(git_str_joinpath(&file, cwd, CUSTOM_CERT_TWO_FILE)); - cl_git_pass(git_str_joinpath(&raw_file, cwd, CUSTOM_CERT_THREE_FILE)); - - cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, - file.ptr, path.ptr)); - -#if (GIT_OPENSSL) - cl_git_pass(git_futils_readbuffer(&raw_file_buf, git_str_cstr(&raw_file))); - cl_git_pass(git_str_decode_base64(&raw_cert, git_str_cstr(&raw_file_buf), git_str_len(&raw_file_buf))); - - raw_cert_bytes = (const unsigned char*)git_str_cstr(&raw_cert); - x509_cert = d2i_X509(NULL, &raw_cert_bytes, git_str_len(&raw_cert)); - cl_git_pass(git_libgit2_opts(GIT_OPT_ADD_SSL_X509_CERT, x509_cert)); - X509_free(x509_cert); -#endif + cl_fixture_sandbox(CUSTOM_CERT_DIR); - initialized = true; + cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX)); + cl_git_pass(git_str_join_n(&path, '/', 3, cwd, CUSTOM_CERT_DIR, CUSTOM_CERT_ONE_PATH)); + cl_git_pass(git_str_join_n(&file, '/', 3, cwd, CUSTOM_CERT_DIR, CUSTOM_CERT_TWO_FILE)); - git_str_dispose(&file); - git_str_dispose(&path); - git_str_dispose(&raw_file); - } + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, + file.ptr, path.ptr)); + + git_str_dispose(&file); + git_str_dispose(&path); #endif } @@ -79,9 +65,11 @@ void test_online_customcert__cleanup(void) } cl_fixture_cleanup("./cloned"); - cl_fixture_cleanup(CUSTOM_CERT_ONE_PATH); - cl_fixture_cleanup(CUSTOM_CERT_TWO_FILE); - cl_fixture_cleanup(CUSTOM_CERT_THREE_FILE); + cl_fixture_cleanup(CUSTOM_CERT_DIR); +#endif + +#ifdef GIT_OPENSSL + git_openssl__reset_context(); #endif } @@ -103,8 +91,31 @@ void test_online_customcert__path(void) void test_online_customcert__raw_x509(void) { -#if (GIT_OPENSSL) +#ifdef GIT_OPENSSL + X509* x509_cert = NULL; + char cwd[GIT_PATH_MAX]; + git_str raw_file = GIT_STR_INIT, + raw_file_data = GIT_STR_INIT, + raw_cert = GIT_STR_INIT; + const unsigned char *raw_cert_bytes = NULL; + + cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX)); + + cl_git_pass(git_str_join_n(&raw_file, '/', 3, cwd, CUSTOM_CERT_DIR, CUSTOM_CERT_THREE_FILE)); + + cl_git_pass(git_futils_readbuffer(&raw_file_data, git_str_cstr(&raw_file))); + cl_git_pass(git_str_decode_base64(&raw_cert, git_str_cstr(&raw_file_data), git_str_len(&raw_file_data))); + + raw_cert_bytes = (const unsigned char *)git_str_cstr(&raw_cert); + x509_cert = d2i_X509(NULL, &raw_cert_bytes, git_str_len(&raw_cert)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ADD_SSL_X509_CERT, x509_cert)); + X509_free(x509_cert); + cl_git_pass(git_clone(&g_repo, CUSTOM_CERT_THREE_URL, "./cloned", NULL)); cl_assert(git_fs_path_exists("./cloned/master.txt")); + + git_str_dispose(&raw_cert); + git_str_dispose(&raw_file_data); + git_str_dispose(&raw_file); #endif } diff --git a/tests/resources/certs/README b/tests/resources/certs/README new file mode 100644 index 00000000000..6a4fc4c68e0 --- /dev/null +++ b/tests/resources/certs/README @@ -0,0 +1,5 @@ +These are self-signed certificates for https://test.libgit2.org/. + +* one/ - contains certificates for https://test.libgit2.org:1443/ +* two.pem - contains a certificate for https://test.libgit2.org:2443/ +* three.pem - contains a certificate for https://test.libgit2.org:3443/ diff --git a/tests/resources/certs/one/61f2ddb6.0 b/tests/resources/certs/one/61f2ddb6.0 new file mode 100644 index 00000000000..7d9ef6fce2a --- /dev/null +++ b/tests/resources/certs/one/61f2ddb6.0 @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFWzCCA0MCFESY816VkhBPUOsdp7djKW5q4ZVzMA0GCSqGSIb3DQEBCwUAMGox +CzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlD +YW1icmlkZ2UxFDASBgNVBAoMC2xpYmdpdDIub3JnMRkwFwYDVQQDDBB0ZXN0Lmxp +YmdpdDIub3JnMB4XDTIxMDgyNTE4NTExMVoXDTMxMDgyMzE4NTExMVowajELMAkG +A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJy +aWRnZTEUMBIGA1UECgwLbGliZ2l0Mi5vcmcxGTAXBgNVBAMMEHRlc3QubGliZ2l0 +Mi5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvaRUaM3IJh9N +G6Yc7tHioUsIGU0MkzSvy/X6O/vONnuuioiJQyPIvfRSvZR2iQj8THTypDGhWn3r +6h2wk5eOUGwJH2N9FrrlEBdpsMc7SKdiJXwTI30mkK3/qru8NzE71dgCkYp1xhKw +edTkAFK+PkvyVLFL7K35cx8Bxfamyssdb+qGWa7g4P27CWUdvQgmurrzzPIMZiLD +/cI1Kwer/N7nTY/6CSs9dcHTlanyZdf+mQ50+//vI4F6+OduGHJkxRF48jLUz1rz +P3WGRMRbHjCmvWpX/9DLgqGk7XTy0hNgNUCit6kawwcv5y7SP/ii86MkynAHn5i8 +d+zhXjdrSSy8i0IbRJafnxmtrsmjGeIzraJSRqMlv7KKWEBz+alm6vlePnRUbWB7 +0po5uSsRPya6kJJCzMjIfKq1dgXq33m9jCG2wU+L4fEHVlEkFGXYTspMlIBNUjTc +c45+e1EpamF8aHm32PP8gTF8fGZzQjOXmNW5g7t0joWMGZ+Ao2jYc1pG3SOARi36 +azrmB5/XJqbbfVZEzIue01fO/5R8RgabOP1qWUjH2KLb8zTDok+CW0ULNseU+MKf +PHXG2OjxcR0vTqop2V6JlKTXXx3/TOD16/+mSrrPzNDejLrkvAH9oN38YpMBM8eg +vfivHNRm0jjdGbv2OOPEBLEf1cNimQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQBZ +znFta24sWoqdgKXKAK5RHAh/HyOvTInwcXi9RU4XjYlbqNVs0ODR74VRZINoyAL2 +bo+x/iUuAp9+b8fjr79fpVof3nSMU7UtMcT1nvzVmaUYSkKQ0f/9vK4yg0kao1bV +WwhIc0slKgOJjEicPVs3kd+duv5vakQeUajLPGM8SiS1F/nF67rIuZLdJn2Qp+im +w5Q3Pjgqw5VrJxyk3AaUcntKHpWy1POLyNV79tXra6BxbtQVlRS0+h1MHELARDFx +1ZtgyAe5YbWM7WrIiFKD4mmKZu4GMnJDXVpfUub5g0U/e7L/gg6Z1UyYZuln6axw +RojuAHo1uAWFUsjhWLYV/7P/l/dC+7gFjvSsUqb1+U7jXObzfKjXo/FwYcy4VsVv +xNbglbhdVjAo/YBTJuf3L0UZjSbxvQIYS+v8u1ECeWE6SH6cHRzryeo5wO4h8NJR +n30xsvocHFbs4LWy5BVfMUo6wGUy0Y+1gSwSqVMv3JPuLwxUsv0HPdeC00Ab9cHq +kYXPNZXg3a6orTDa4hJLdAm2V/fn/2KKJYlNj7iCL664QgoCHl7LFyLMiwFVCu5h +4JjGL3Q+8MondaLZlq5YDmvtj979AyM/7qL4XAE2oofQ4J5dqnKKpMkWdAM/fI/9 +N5DK/4zMXJWgIED0yo2SSZHQmuqZplacOhmfjjZigQ== +-----END CERTIFICATE----- diff --git a/tests/resources/certs/one/db4f60b0.0 b/tests/resources/certs/one/db4f60b0.0 new file mode 100644 index 00000000000..7d9ef6fce2a --- /dev/null +++ b/tests/resources/certs/one/db4f60b0.0 @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFWzCCA0MCFESY816VkhBPUOsdp7djKW5q4ZVzMA0GCSqGSIb3DQEBCwUAMGox +CzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlD +YW1icmlkZ2UxFDASBgNVBAoMC2xpYmdpdDIub3JnMRkwFwYDVQQDDBB0ZXN0Lmxp +YmdpdDIub3JnMB4XDTIxMDgyNTE4NTExMVoXDTMxMDgyMzE4NTExMVowajELMAkG +A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJy +aWRnZTEUMBIGA1UECgwLbGliZ2l0Mi5vcmcxGTAXBgNVBAMMEHRlc3QubGliZ2l0 +Mi5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvaRUaM3IJh9N +G6Yc7tHioUsIGU0MkzSvy/X6O/vONnuuioiJQyPIvfRSvZR2iQj8THTypDGhWn3r +6h2wk5eOUGwJH2N9FrrlEBdpsMc7SKdiJXwTI30mkK3/qru8NzE71dgCkYp1xhKw +edTkAFK+PkvyVLFL7K35cx8Bxfamyssdb+qGWa7g4P27CWUdvQgmurrzzPIMZiLD +/cI1Kwer/N7nTY/6CSs9dcHTlanyZdf+mQ50+//vI4F6+OduGHJkxRF48jLUz1rz +P3WGRMRbHjCmvWpX/9DLgqGk7XTy0hNgNUCit6kawwcv5y7SP/ii86MkynAHn5i8 +d+zhXjdrSSy8i0IbRJafnxmtrsmjGeIzraJSRqMlv7KKWEBz+alm6vlePnRUbWB7 +0po5uSsRPya6kJJCzMjIfKq1dgXq33m9jCG2wU+L4fEHVlEkFGXYTspMlIBNUjTc +c45+e1EpamF8aHm32PP8gTF8fGZzQjOXmNW5g7t0joWMGZ+Ao2jYc1pG3SOARi36 +azrmB5/XJqbbfVZEzIue01fO/5R8RgabOP1qWUjH2KLb8zTDok+CW0ULNseU+MKf +PHXG2OjxcR0vTqop2V6JlKTXXx3/TOD16/+mSrrPzNDejLrkvAH9oN38YpMBM8eg +vfivHNRm0jjdGbv2OOPEBLEf1cNimQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQBZ +znFta24sWoqdgKXKAK5RHAh/HyOvTInwcXi9RU4XjYlbqNVs0ODR74VRZINoyAL2 +bo+x/iUuAp9+b8fjr79fpVof3nSMU7UtMcT1nvzVmaUYSkKQ0f/9vK4yg0kao1bV +WwhIc0slKgOJjEicPVs3kd+duv5vakQeUajLPGM8SiS1F/nF67rIuZLdJn2Qp+im +w5Q3Pjgqw5VrJxyk3AaUcntKHpWy1POLyNV79tXra6BxbtQVlRS0+h1MHELARDFx +1ZtgyAe5YbWM7WrIiFKD4mmKZu4GMnJDXVpfUub5g0U/e7L/gg6Z1UyYZuln6axw +RojuAHo1uAWFUsjhWLYV/7P/l/dC+7gFjvSsUqb1+U7jXObzfKjXo/FwYcy4VsVv +xNbglbhdVjAo/YBTJuf3L0UZjSbxvQIYS+v8u1ECeWE6SH6cHRzryeo5wO4h8NJR +n30xsvocHFbs4LWy5BVfMUo6wGUy0Y+1gSwSqVMv3JPuLwxUsv0HPdeC00Ab9cHq +kYXPNZXg3a6orTDa4hJLdAm2V/fn/2KKJYlNj7iCL664QgoCHl7LFyLMiwFVCu5h +4JjGL3Q+8MondaLZlq5YDmvtj979AyM/7qL4XAE2oofQ4J5dqnKKpMkWdAM/fI/9 +N5DK/4zMXJWgIED0yo2SSZHQmuqZplacOhmfjjZigQ== +-----END CERTIFICATE----- diff --git a/tests/resources/certs/three.pem b/tests/resources/certs/three.pem new file mode 100644 index 00000000000..b63f09301bc --- /dev/null +++ b/tests/resources/certs/three.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIUIGLmUoxDx3fh8dGDdrw81kDLWJgwDQYJKoZIhvcNAQEL +BQAwajELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNV +BAcMCUNhbWJyaWRnZTEUMBIGA1UECgwLbGliZ2l0Mi5vcmcxGTAXBgNVBAMMEHRl +c3QubGliZ2l0Mi5vcmcwHhcNMjQxMDAxMDkwODEzWhcNMzQwOTI5MDkwODEzWjBq +MQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czESMBAGA1UEBwwJ +Q2FtYnJpZGdlMRQwEgYDVQQKDAtsaWJnaXQyLm9yZzEZMBcGA1UEAwwQdGVzdC5s +aWJnaXQyLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL7tLetm +ORd4uklvSeFn9eJfHCrhmNkWHd1VVuMhjcKkjk+N7GNdq1UMsSZU0xnJMICjJcnq +plZ9WnO6VkRibyIf/Xp5dh3sQh9jvuTNhvWAOYv9tjxX1sxA0WeHAZj/5qUMtvH3 +mr0gqNbtIrmEFAeWgcYSJbXhnWit7YEnGReHc17F50hbbLOgl5HLQAzIAEkj4nKX +hR8KKgyQk3dNfoc9orSjUxDp8fq9Z2prcEOYFmkItvC8rtqLB9EBJ1moGjB1BWEd +3Eg28TUXubRGwrTbpMWP5UWQWuS2Adnd/oQE7NVe5xhxzad8qlReEodF+ptSux5G +Nw+qy5l5GbMdNfgmXXp34vUldl8dH1BAtC0QH/fmAg5Ea7Ys0bnM9c0MRHJlX7QC +3fk/pVCSw7ozuceTyJyqhHMRUAcKeGJETJoBz/nmWm2oG5VjZ54k6ktvjjKNGpuL +44dR+xpZljESmHOm7c10AKBiuMjSG5i1o7wzWEDDfCPKo/5Uf5mMcTn78yrO83zt +yhIIYfm1kDTbAMMDo1MYHnsqXROxc0ShyLM5fLf7hWh+p8p0MrLUWbAtdETOOx9Y +qOla6qOGwmKmZaDR82GBCNcLkkqiuWC9oWb2YCtw7UB6cT7BSR7z8mLzfKrzryuJ +2IRawZ9JuuHmBMhvLmDWXoLy6zbxTc8eIaffAgMBAAGjUzBRMB0GA1UdDgQWBBTE +X4I8cLBkgHHuPS6wu1Z2CFVwNjAfBgNVHSMEGDAWgBTEX4I8cLBkgHHuPS6wu1Z2 +CFVwNjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBzgWp1dk0Y +ezID9uD4QRdKarPsRwH4EiXi4sk0udjrOljiPWrUTTvg4Zo/PszaJGmFUtoKGrSD +RqaCHMeSOT3NGuxqvfdSvxT6I7b6mDTRiJGncQ/h6Efj/9M04lHvfPsv33055ZF/ +FZBNznG+FYJM0iOMsgsRq95sM28/Z0eG65YJ/4o4Y9eC+zKUqC+ksVvrEDiinFPP +XPzrqJ5aW6TgUgQ583Q1u/Ijj3Z+LxlV3fe2OVgFKCL82XOsZPRCQq71vnNXA3KN +RpmXw4fNgZYmYDzUuEaeP+0jL38sTIZaHOEOPlghjny9c+UgqAWUEiN9M1HC59Dc +7ViTzRYlWUSbLOzh2vmT7nv7l9eRRNVp5gfWVhI6yu6lZ4tsH1BvMoJ3tgJ+c9pf +WMZEIKuErZl0u58Zs09ozzXaXXnMjx6pnTrqwMqaHJe5SFHh3XvvycGjCXRy4vjh +xs+BpmGqB44DRtYBbW6n4UDc481QVEoWd9DOQ7Y2OQJ1pHFTLLqkWSXw3KmO0cAX +51H9Ab46WfmYhrtmGNrYWUB7fGSsJ1C/4fiuo8Hx5sq+NP11H80q8TOBcPGRyeTj +K8L5y6T907tfZMlfloiBcbBFSbOf4+KCyVOYaM0O/LrroH+zZaNJiEP1By7Qsn/2 +Ekw0zxtlImc0SQ3NqnkfAsp6nfYMJPylZA== +-----END CERTIFICATE----- diff --git a/tests/resources/certs/three.pem.raw b/tests/resources/certs/three.pem.raw new file mode 100644 index 00000000000..63e35f85d23 --- /dev/null +++ b/tests/resources/certs/three.pem.raw @@ -0,0 +1 @@ +MIIFtTCCA52gAwIBAgIUIGLmUoxDx3fh8dGDdrw81kDLWJgwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEUMBIGA1UECgwLbGliZ2l0Mi5vcmcxGTAXBgNVBAMMEHRlc3QubGliZ2l0Mi5vcmcwHhcNMjQxMDAxMDkwODEzWhcNMzQwOTI5MDkwODEzWjBqMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMRQwEgYDVQQKDAtsaWJnaXQyLm9yZzEZMBcGA1UEAwwQdGVzdC5saWJnaXQyLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL7tLetmORd4uklvSeFn9eJfHCrhmNkWHd1VVuMhjcKkjk+N7GNdq1UMsSZU0xnJMICjJcnqplZ9WnO6VkRibyIf/Xp5dh3sQh9jvuTNhvWAOYv9tjxX1sxA0WeHAZj/5qUMtvH3mr0gqNbtIrmEFAeWgcYSJbXhnWit7YEnGReHc17F50hbbLOgl5HLQAzIAEkj4nKXhR8KKgyQk3dNfoc9orSjUxDp8fq9Z2prcEOYFmkItvC8rtqLB9EBJ1moGjB1BWEd3Eg28TUXubRGwrTbpMWP5UWQWuS2Adnd/oQE7NVe5xhxzad8qlReEodF+ptSux5GNw+qy5l5GbMdNfgmXXp34vUldl8dH1BAtC0QH/fmAg5Ea7Ys0bnM9c0MRHJlX7QC3fk/pVCSw7ozuceTyJyqhHMRUAcKeGJETJoBz/nmWm2oG5VjZ54k6ktvjjKNGpuL44dR+xpZljESmHOm7c10AKBiuMjSG5i1o7wzWEDDfCPKo/5Uf5mMcTn78yrO83ztyhIIYfm1kDTbAMMDo1MYHnsqXROxc0ShyLM5fLf7hWh+p8p0MrLUWbAtdETOOx9YqOla6qOGwmKmZaDR82GBCNcLkkqiuWC9oWb2YCtw7UB6cT7BSR7z8mLzfKrzryuJ2IRawZ9JuuHmBMhvLmDWXoLy6zbxTc8eIaffAgMBAAGjUzBRMB0GA1UdDgQWBBTEX4I8cLBkgHHuPS6wu1Z2CFVwNjAfBgNVHSMEGDAWgBTEX4I8cLBkgHHuPS6wu1Z2CFVwNjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBzgWp1dk0YezID9uD4QRdKarPsRwH4EiXi4sk0udjrOljiPWrUTTvg4Zo/PszaJGmFUtoKGrSDRqaCHMeSOT3NGuxqvfdSvxT6I7b6mDTRiJGncQ/h6Efj/9M04lHvfPsv33055ZF/FZBNznG+FYJM0iOMsgsRq95sM28/Z0eG65YJ/4o4Y9eC+zKUqC+ksVvrEDiinFPPXPzrqJ5aW6TgUgQ583Q1u/Ijj3Z+LxlV3fe2OVgFKCL82XOsZPRCQq71vnNXA3KNRpmXw4fNgZYmYDzUuEaeP+0jL38sTIZaHOEOPlghjny9c+UgqAWUEiN9M1HC59Dc7ViTzRYlWUSbLOzh2vmT7nv7l9eRRNVp5gfWVhI6yu6lZ4tsH1BvMoJ3tgJ+c9pfWMZEIKuErZl0u58Zs09ozzXaXXnMjx6pnTrqwMqaHJe5SFHh3XvvycGjCXRy4vjhxs+BpmGqB44DRtYBbW6n4UDc481QVEoWd9DOQ7Y2OQJ1pHFTLLqkWSXw3KmO0cAX51H9Ab46WfmYhrtmGNrYWUB7fGSsJ1C/4fiuo8Hx5sq+NP11H80q8TOBcPGRyeTjK8L5y6T907tfZMlfloiBcbBFSbOf4+KCyVOYaM0O/LrroH+zZaNJiEP1By7Qsn/2Ekw0zxtlImc0SQ3NqnkfAsp6nfYMJPylZA== \ No newline at end of file diff --git a/tests/resources/certs/two.pem b/tests/resources/certs/two.pem new file mode 100644 index 00000000000..e13417e483a --- /dev/null +++ b/tests/resources/certs/two.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUzCCAjsCFAb11im6DYQyGJ0GNQCIehXtegq6MA0GCSqGSIb3DQEBCwUAMGYx +CzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlD +YW1icmlkZ2UxEDAOBgNVBAoMB2xpYmdpdDIxGTAXBgNVBAMMEHRlc3QubGliZ2l0 +Mi5vcmcwHhcNMjEwODMwMDAyMTQyWhcNMzEwODI4MDAyMTQyWjBmMQswCQYDVQQG +EwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdl +MRAwDgYDVQQKDAdsaWJnaXQyMRkwFwYDVQQDDBB0ZXN0LmxpYmdpdDIub3JnMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtqe6b1vnMni+z8Z+a2bGtykI +ITvBged15rn+0qG6Fz+sn9bYG+ceFupztFfoN3cVpUgQDBTzr3CaAx036BlV0z8i +CrG0Oh/XGL+9TITQLumEe4iGi8NoMSujBAyXPSNgmpzDmCTGrNFfmq3HzUtO8t3x +i8OT7d9qCVjFimLvZbgnfHGQ38xvt1XyPgYIVqDQczmMEZ5BdYWB0A1VmnWuP2dH +BgjwPEC3HwMmm1+PL0VoPTdvE5Su092Qdt8QsiA56466DQyll1d/omnOJfrK7z0N +OnfDmnDpARSTy6vDofEAYUQoc3dyvBUk8IIzv2UDcR7fTVvYqseQReIOTEnXmQID +AQABMA0GCSqGSIb3DQEBCwUAA4IBAQBmUEq+JhwWTbB5ODGOKrMG1fKJ+sf6ZH6M +c4BgLEcdoi/nOTfPuw+ols72LuhH7NKaEcqxWev0jGF0WKqMcM8AGVbywZJ3mBWo +sKdh6rAGFNkikW4TzhjtDfFbMR45Didl28Be7ieHQL4CQ0Lse3RMOxp250WpiEYV +W2hIKMwIqOLKGShVD7lI+eHlv+QSH4yOYKHfRHve8s82Tac5OXinc8CJm9ySOtkO +MfLgfkHtHdFBnV6OVbf4p/596MfMXdwT/bBxT6WPkDGc1AYhoDlmLFTpRgHIDCSK +2wgV+qHppl7Kn+p3mFQ9sW/1IaRd+jNZOrgZ8Uu5tJ00OaqR/LVG +-----END CERTIFICATE----- From fa5b8325449240a331836d9b494abcf0aaf26a6b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 16:22:42 +0100 Subject: [PATCH 593/816] openssl: point out the interaction between certs The OpenSSL certificate setting functions _may_ interact; try to document that a bit better. --- include/git2/common.h | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index c4d494be38c..8d015704439 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -336,17 +336,20 @@ typedef enum { * > - `path` is the location of a directory holding several * > certificates, one per file. * > + * > Calling `GIT_OPT_ADD_SSL_X509_CERT` may override the + * > data in `path`. + * > * > Either parameter may be `NULL`, but not both. - * + * * * opts(GIT_OPT_ADD_SSL_X509_CERT, const X509 *cert) - * - * > Add a raw X509 certificate into the SSL certs store. - * > The added certificate is not persisted and will be used - * > only during application lifetime. Also there is no ability - * > to remove a certificate from the store during app lifetime - * > after it was added. - * > - * > - `cert` is the raw X509 cert will be added to cert store. + * + * > Add a raw X509 certificate into the SSL certs store. + * > This certificate is only used by libgit2 invocations + * > during the application lifetime and is not persisted + * > to disk. This certificate cannot be removed from the + * > application once is has been added. + * > + * > - `cert` is the raw X509 cert will be added to cert store. * * * opts(GIT_OPT_SET_USER_AGENT, const char *user_agent) * From 2a494d36692a18e2f791f274db06bebe4c385d3f Mon Sep 17 00:00:00 2001 From: Francis McKenzie Date: Tue, 22 Jun 2021 15:52:53 +0200 Subject: [PATCH 594/816] Added test network::remote::tag --- tests/libgit2/network/remote/tag.c | 92 ++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tests/libgit2/network/remote/tag.c diff --git a/tests/libgit2/network/remote/tag.c b/tests/libgit2/network/remote/tag.c new file mode 100644 index 00000000000..267cc7fed3c --- /dev/null +++ b/tests/libgit2/network/remote/tag.c @@ -0,0 +1,92 @@ +#include "clar_libgit2.h" +#include "git2/sys/commit.h" + +static git_remote *_remote; +static git_repository *_repo, *_dummy; + +void test_network_remote_tag__initialize(void) +{ + cl_fixture_sandbox("testrepo.git"); + git_repository_open(&_repo, "testrepo.git"); + + /* We need a repository to have a remote */ + cl_git_pass(git_repository_init(&_dummy, "dummytag.git", true)); + cl_git_pass(git_remote_create(&_remote, _dummy, "origin", cl_git_path_url("testrepo.git"))); +} + +void test_network_remote_tag__cleanup(void) +{ + git_remote_free(_remote); + _remote = NULL; + + git_repository_free(_repo); + _repo = NULL; + + git_repository_free(_dummy); + _dummy = NULL; + + cl_fixture_cleanup("testrepo.git"); + cl_fixture_cleanup("dummytag.git"); +} + +/* + * Create one commit, one tree, one blob. + * Create two tags: one for the commit, one for the blob. + */ +void create_commit_with_tags(git_reference **out, git_oid *out_commit_tag_id, git_oid *out_blob_tag_id, git_repository *repo) +{ + git_treebuilder *treebuilder; + git_oid blob_id, tree_id, commit_id; + git_signature *sig; + git_object *target; + + cl_git_pass(git_treebuilder_new(&treebuilder, repo, NULL)); + + cl_git_pass(git_blob_create_from_buffer(&blob_id, repo, "", 0)); + cl_git_pass(git_treebuilder_insert(NULL, treebuilder, "README.md", &blob_id, 0100644)); + cl_git_pass(git_treebuilder_write(&tree_id, treebuilder)); + + cl_git_pass(git_signature_now(&sig, "Pusher Joe", "pjoe")); + cl_git_pass(git_commit_create_from_ids(&commit_id, repo, NULL, sig, sig, + NULL, "Tree with tags\n", &tree_id, 0, NULL)); + cl_git_pass(git_reference_create(out, repo, "refs/heads/tree-with-tags", &commit_id, true, "commit yo")); + + cl_git_pass(git_object_lookup(&target, repo, &commit_id, GIT_OBJECT_COMMIT)); + cl_git_pass(git_tag_create_lightweight(out_commit_tag_id, repo, "tagged-commit", target, true)); + + cl_git_pass(git_object_lookup(&target, repo, &blob_id, GIT_OBJECT_BLOB)); + cl_git_pass(git_tag_create_lightweight(out_blob_tag_id, repo, "tagged-blob", target, true)); + + git_object_free(target); + git_treebuilder_free(treebuilder); + git_signature_free(sig); +} + +void test_network_remote_tag__push_different_tag_types(void) +{ + git_push_options opts = GIT_PUSH_OPTIONS_INIT; + git_reference *ref; + git_oid commit_tag_id, blob_tag_id; + char* refspec_tree = "refs/heads/tree-with-tags"; + char* refspec_tagged_commit = "refs/tags/tagged-commit"; + char* refspec_tagged_blob = "refs/tags/tagged-blob"; + const git_strarray refspecs_tree = { &refspec_tree, 1 }; + const git_strarray refspecs_tagged_commit = { &refspec_tagged_commit, 1 }; + const git_strarray refspecs_tagged_blob = { &refspec_tagged_blob, 1 }; + + create_commit_with_tags(&ref, &commit_tag_id, &blob_tag_id, _dummy); + + /* Push tree */ + cl_git_pass(git_remote_push(_remote, &refspecs_tree, &opts)); + git_reference_free(ref); + cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/tree-with-tags")); + git_reference_free(ref); + + /* Push tagged commit */ + cl_git_pass(git_remote_push(_remote, &refspecs_tagged_commit, &opts)); + cl_git_pass(git_reference_name_to_id(&commit_tag_id, _repo, "refs/tags/tagged-commit")); + + /* Push tagged blob */ + cl_git_pass(git_remote_push(_remote, &refspecs_tagged_blob, &opts)); + cl_git_pass(git_reference_name_to_id(&blob_tag_id, _repo, "refs/tags/tagged-blob")); +} From 1e4576dfd74006cdaf0411ba8a8064f5d563d500 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 22:16:13 +0100 Subject: [PATCH 595/816] push: handle tags to blobs --- src/libgit2/push.c | 27 ++++++++++++++------------- tests/libgit2/network/remote/tag.c | 5 +++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/libgit2/push.c b/src/libgit2/push.c index db5b5a63d3a..882092039f9 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -283,6 +283,7 @@ static int queue_objects(git_push *push) git_vector_foreach(&push->specs, i, spec) { git_object_t type; + git_oid id; size_t size; if (git_oid_is_zero(&spec->loid)) @@ -304,20 +305,20 @@ static int queue_objects(git_push *push) if ((error = enqueue_tag(&target, push, &spec->loid)) < 0) goto on_error; - if (git_object_type(target) == GIT_OBJECT_COMMIT) { - if ((error = git_revwalk_push(rw, git_object_id(target))) < 0) { - git_object_free(target); - goto on_error; - } - } else { - if ((error = git_packbuilder_insert( - push->pb, git_object_id(target), NULL)) < 0) { - git_object_free(target); - goto on_error; - } - } + type = git_object_type(target); + git_oid_cpy(&id, git_object_id(target)); + git_object_free(target); - } else if ((error = git_revwalk_push(rw, &spec->loid)) < 0) + } else { + git_oid_cpy(&id, &spec->loid); + } + + if (type == GIT_OBJECT_COMMIT) + error = git_revwalk_push(rw, &id); + else + error = git_packbuilder_insert(push->pb, &id, NULL); + + if (error < 0) goto on_error; if (!spec->refspec.force) { diff --git a/tests/libgit2/network/remote/tag.c b/tests/libgit2/network/remote/tag.c index 267cc7fed3c..7a166a94f13 100644 --- a/tests/libgit2/network/remote/tag.c +++ b/tests/libgit2/network/remote/tag.c @@ -33,7 +33,7 @@ void test_network_remote_tag__cleanup(void) * Create one commit, one tree, one blob. * Create two tags: one for the commit, one for the blob. */ -void create_commit_with_tags(git_reference **out, git_oid *out_commit_tag_id, git_oid *out_blob_tag_id, git_repository *repo) +static void create_commit_with_tags(git_reference **out, git_oid *out_commit_tag_id, git_oid *out_blob_tag_id, git_repository *repo) { git_treebuilder *treebuilder; git_oid blob_id, tree_id, commit_id; @@ -53,11 +53,12 @@ void create_commit_with_tags(git_reference **out, git_oid *out_commit_tag_id, gi cl_git_pass(git_object_lookup(&target, repo, &commit_id, GIT_OBJECT_COMMIT)); cl_git_pass(git_tag_create_lightweight(out_commit_tag_id, repo, "tagged-commit", target, true)); + git_object_free(target); cl_git_pass(git_object_lookup(&target, repo, &blob_id, GIT_OBJECT_BLOB)); cl_git_pass(git_tag_create_lightweight(out_blob_tag_id, repo, "tagged-blob", target, true)); - git_object_free(target); + git_treebuilder_free(treebuilder); git_signature_free(sig); } From 3b500a92ad0e0f989b84923cb142b641e46c0d8f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 2 Oct 2024 13:06:52 +0100 Subject: [PATCH 596/816] ci: update to windows-2022 for sha256 builds --- .github/workflows/experimental.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml index 2ab745f18ac..60baeb3367a 100644 --- a/.github/workflows/experimental.yml +++ b/.github/workflows/experimental.yml @@ -48,10 +48,10 @@ jobs: SKIP_NEGOTIATE_TESTS: true - name: "Windows (SHA256, amd64, Visual Studio)" id: windows-sha256 - os: windows-2019 + os: windows-2022 env: ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_GENERATOR: Visual Studio 17 2022 CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true From 419948ef23c92cdfd27dcbc3b865bfee7df55bb6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 21 Sep 2024 13:16:16 +0100 Subject: [PATCH 597/816] attrcache: make the attribute cache opaque This minor refactoring helps remove some of the coupling that pieces have to the attribute cache. --- src/libgit2/attr.c | 23 ++++++++++++++++++----- src/libgit2/attrcache.c | 24 ++++++++++++++++++++++++ src/libgit2/attrcache.h | 13 +++++-------- src/libgit2/ignore.c | 10 +++++++--- 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/libgit2/attr.c b/src/libgit2/attr.c index 4cbb7d987f9..d0eacd45adb 100644 --- a/src/libgit2/attr.c +++ b/src/libgit2/attr.c @@ -384,6 +384,8 @@ static int attr_setup( git_attr_file_source index_source = { GIT_ATTR_FILE_SOURCE_INDEX, NULL, GIT_ATTR_FILE, NULL }; git_attr_file_source head_source = { GIT_ATTR_FILE_SOURCE_HEAD, NULL, GIT_ATTR_FILE, NULL }; git_attr_file_source commit_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE, NULL }; + git_attr_cache *attrcache; + const char *attr_cfg_file = NULL; git_index *idx = NULL; const char *workdir; int error = 0; @@ -407,8 +409,10 @@ static int attr_setup( error = 0; } - if ((error = preload_attr_file(repo, attr_session, NULL, - git_repository_attr_cache(repo)->cfg_attr_file)) < 0) + if ((attrcache = git_repository_attr_cache(repo)) != NULL) + attr_cfg_file = git_attr_cache_attributesfile(attrcache); + + if ((error = preload_attr_file(repo, attr_session, NULL, attr_cfg_file)) < 0) goto out; if ((error = git_repository__item_path(&info, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || @@ -464,6 +468,7 @@ int git_attr_add_macro( { int error; git_attr_rule *macro = NULL; + git_attr_cache *attrcache; git_pool *pool; GIT_ASSERT_ARG(repo); @@ -475,7 +480,8 @@ int git_attr_add_macro( macro = git__calloc(1, sizeof(git_attr_rule)); GIT_ERROR_CHECK_ALLOC(macro); - pool = &git_repository_attr_cache(repo)->pool; + attrcache = git_repository_attr_cache(repo); + pool = git_attr_cache_pool(attrcache); macro->match.pattern = git_pool_strdup(pool, name); GIT_ERROR_CHECK_ALLOC(macro->match.pattern); @@ -631,6 +637,8 @@ static int collect_attr_files( int error = 0; git_str dir = GIT_STR_INIT, attrfile = GIT_STR_INIT; const char *workdir = git_repository_workdir(repo); + git_attr_cache *attrcache; + const char *attr_cfg_file = NULL; attr_walk_up_info info = { NULL }; GIT_ASSERT(!git_fs_path_is_absolute(path)); @@ -679,8 +687,13 @@ static int collect_attr_files( if (error < 0) goto cleanup; - if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) { - error = push_attr_file(repo, attr_session, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file); + if ((attrcache = git_repository_attr_cache(repo)) != NULL) + attr_cfg_file = git_attr_cache_attributesfile(attrcache); + + + if (attr_cfg_file) { + error = push_attr_file(repo, attr_session, files, NULL, attr_cfg_file); + if (error < 0) goto cleanup; } diff --git a/src/libgit2/attrcache.c b/src/libgit2/attrcache.c index 405944ed156..1d906bbfa09 100644 --- a/src/libgit2/attrcache.c +++ b/src/libgit2/attrcache.c @@ -14,6 +14,30 @@ #include "ignore.h" #include "path.h" +struct git_attr_cache { + char *cfg_attr_file; /* cached value of core.attributesfile */ + char *cfg_excl_file; /* cached value of core.excludesfile */ + git_strmap *files; /* hash path to git_attr_cache_entry records */ + git_strmap *macros; /* hash name to vector */ + git_mutex lock; + git_pool pool; +}; + +const char *git_attr_cache_attributesfile(git_attr_cache *cache) +{ + return cache->cfg_attr_file; +} + +const char *git_attr_cache_excludesfile(git_attr_cache *cache) +{ + return cache->cfg_excl_file; +} + +git_pool *git_attr_cache_pool(git_attr_cache *cache) +{ + return &cache->pool; +} + GIT_INLINE(int) attr_cache_lock(git_attr_cache *cache) { GIT_UNUSED(cache); /* avoid warning if threading is off */ diff --git a/src/libgit2/attrcache.h b/src/libgit2/attrcache.h index b13e0e8f0a8..a2710b4585b 100644 --- a/src/libgit2/attrcache.h +++ b/src/libgit2/attrcache.h @@ -15,17 +15,14 @@ #define GIT_ATTR_CONFIG "core.attributesfile" #define GIT_IGNORE_CONFIG "core.excludesfile" -typedef struct { - char *cfg_attr_file; /* cached value of core.attributesfile */ - char *cfg_excl_file; /* cached value of core.excludesfile */ - git_strmap *files; /* hash path to git_attr_cache_entry records */ - git_strmap *macros; /* hash name to vector */ - git_mutex lock; - git_pool pool; -} git_attr_cache; +typedef struct git_attr_cache git_attr_cache; extern int git_attr_cache__init(git_repository *repo); +extern const char *git_attr_cache_attributesfile(git_attr_cache *ac); +extern const char *git_attr_cache_excludesfile(git_attr_cache *ac); +extern git_pool *git_attr_cache_pool(git_attr_cache *ac); + /* get file - loading and reload as needed */ extern int git_attr_cache__get( git_attr_file **file, diff --git a/src/libgit2/ignore.c b/src/libgit2/ignore.c index 7856d2c385f..13a67343f6a 100644 --- a/src/libgit2/ignore.c +++ b/src/libgit2/ignore.c @@ -296,6 +296,8 @@ int git_ignore__for_path( { int error = 0; const char *workdir = git_repository_workdir(repo); + git_attr_cache *attrcache; + const char *excludes_file = NULL; git_str infopath = GIT_STR_INIT; GIT_ASSERT_ARG(repo); @@ -358,10 +360,12 @@ int git_ignore__for_path( } /* load core.excludesfile */ - if (git_repository_attr_cache(repo)->cfg_excl_file != NULL) + attrcache = git_repository_attr_cache(repo); + excludes_file = git_attr_cache_excludesfile(attrcache); + + if (excludes_file != NULL) error = push_ignore_file( - ignores, &ignores->ign_global, NULL, - git_repository_attr_cache(repo)->cfg_excl_file); + ignores, &ignores->ign_global, NULL, excludes_file); cleanup: git_str_dispose(&infopath); From 53bc5a128ef5dfa204435c0f7380f34a9fcfda2e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 20:31:39 +0100 Subject: [PATCH 598/816] pool: introduce is_initialized helper method Let callers understand whether a pool has been initialized or not. --- src/util/pool.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/util/pool.h b/src/util/pool.h index 0238431b0a0..75a28c3babc 100644 --- a/src/util/pool.h +++ b/src/util/pool.h @@ -83,6 +83,11 @@ typedef struct { */ extern int git_pool_init(git_pool *pool, size_t item_size); +GIT_INLINE(bool) git_pool_is_initialized(git_pool *pool) +{ + return (pool->item_size > 0); +} + /** * Free all items in pool */ From 539059f6e347adc6a7fdb3f5dd8a3f08819b207c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:37:07 +0100 Subject: [PATCH 599/816] hashmap: introduce git_hashmap / git_hashset Introduce `git_hashmap` and `git_hashset` functionality that is a port of `khash.h` to be more idiomatically libgit2. This gives us many of the benefits of khash that we had abstracted away: 1. Typesafety on the values, since we define the structs and functions 2. Ability to create hashes on the stack 3. Ability to new up hashmaps (or sets) without the libgit2 abstraction wrappers that we had been adding This uses the macros to define hashes (either the structure, or the functions, or both) which is very much in the spirit of khash, but the results are much more idiomatically libgit2. --- src/util/cc-compat.h | 2 + src/util/hashmap.h | 419 +++++++++++++++++++++++++++++++++++++++++ src/util/hashmap_str.h | 43 +++++ tests/util/hashmap.c | 227 ++++++++++++++++++++++ 4 files changed, 691 insertions(+) create mode 100644 src/util/hashmap.h create mode 100644 src/util/hashmap_str.h create mode 100644 tests/util/hashmap.c diff --git a/src/util/cc-compat.h b/src/util/cc-compat.h index ede6e9aa9a1..ae81970eae8 100644 --- a/src/util/cc-compat.h +++ b/src/util/cc-compat.h @@ -44,9 +44,11 @@ _unused = (x); \ } while (0) # define GIT_UNUSED_ARG __attribute__((unused)) +# define GIT_UNUSED_FUNCTION __attribute__((unused)) #else # define GIT_UNUSED(x) ((void)(x)) # define GIT_UNUSED_ARG +# define GIT_UNUSED_FUNCTION #endif /* Define the printf format specifier to use for size_t output */ diff --git a/src/util/hashmap.h b/src/util/hashmap.h new file mode 100644 index 00000000000..b5fd9bce187 --- /dev/null +++ b/src/util/hashmap.h @@ -0,0 +1,419 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_hashmap_h__ +#define INCLUDE_hashmap_h__ + +/* + * This is a variation on khash.h from khlib 2013-05-02 (0.2.8) + * + * The MIT License + * + * Copyright (c) 2008, 2009, 2011 by Attractive Chaos + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#define GIT_HASHMAP_INIT {0} +#define GIT_HASHSET_INIT {0} + +#define GIT_HASHMAP_EMPTY +#define GIT_HASHMAP_INLINE GIT_INLINE(GIT_HASHMAP_EMPTY) + +#define GIT_HASHMAP_IS_EMPTY(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) +#define GIT_HASHMAP_IS_DELETE(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) +#define GIT_HASHMAP_IS_EITHER(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) +#define GIT_HASHMAP_SET_EMPTY_FALSE(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) +#define GIT_HASHMAP_SET_DELETE_TRUE(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) +#define GIT_HASHMAP_SET_DELETE_FALSE(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) +#define GIT_HASHMAP_SET_BOTH_FALSE(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) + +#define GIT_HASHMAP_FLAGSIZE(m) ((m) < 16? 1 : (m)>>4) +#define GIT_HASHMAP_ROUNDUP(x) (--(x), (x)|=(x)>>1, \ + (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) + +#define GIT_HASHSET_VAL_T void * + +typedef uint32_t git_hashmap_iter_t; +#define GIT_HASHMAP_ITER_INIT 0 + +#define GIT_HASHMAP_STRUCT_MEMBERS(key_t, val_t) \ + uint32_t n_buckets, \ + size, \ + n_occupied, \ + upper_bound; \ + uint32_t *flags; \ + key_t *keys; \ + val_t *vals; + +#define GIT_HASHMAP_STRUCT(name, key_t, val_t) \ + typedef struct { \ + GIT_HASHMAP_STRUCT_MEMBERS(key_t, val_t) \ + } name; +#define GIT_HASHSET_STRUCT(name, key_t) \ + GIT_HASHMAP_STRUCT(name, key_t, void *) + + +#define GIT_HASHMAP__COMMON_PROTOTYPES(name, key_t, val_t) \ + extern uint32_t name##_size(name *h); \ + extern bool name##_contains(name *h, key_t key); \ + extern int name##_remove(name *h, key_t key); \ + extern void name##_clear(name *h); \ + extern void name##_dispose(name *h); + +#define GIT_HASHMAP_PROTOTYPES(name, key_t, val_t) \ + GIT_HASHMAP__COMMON_PROTOTYPES(name, key_t, val_t) \ + extern int name##_get(val_t *out, name *h, key_t key); \ + extern int name##_put(name *h, key_t key, val_t val); \ + extern int name##_iterate(git_hashmap_iter_t *iter, key_t *key, val_t *val, name *h); \ + extern int name##_foreach(name *h, int (*cb)(key_t, val_t)); + +#define GIT_HASHSET_PROTOTYPES(name, key_t) \ + GIT_HASHMAP__COMMON_PROTOTYPES(name, key_t, GIT_HASHSET_VAL_T) \ + extern int name##_add(name *h, key_t key); \ + extern int name##_iterate(git_hashmap_iter_t *iter, key_t *key, name *h); \ + extern int name##_foreach(name *h, int (*cb)(key_t)); \ + + +#define GIT_HASHMAP__COMMON_FUNCTIONS(name, is_map, scope, key_t, val_t, __hash_fn, __equal_fn) \ + GIT_UNUSED_FUNCTION scope uint32_t name##_size(name *h) \ + { \ + return h->size; \ + } \ + GIT_INLINE(int) name##__idx(uint32_t *out, name *h, key_t key) \ + { \ + if (h->n_buckets) { \ + uint32_t k, i, last, mask, step = 0; \ + mask = h->n_buckets - 1; \ + k = __hash_fn(key); \ + i = k & mask; \ + last = i; \ + while (!GIT_HASHMAP_IS_EMPTY(h->flags, i) && \ + (GIT_HASHMAP_IS_DELETE(h->flags, i) || !__equal_fn(h->keys[i], key))) { \ + i = (i + (++step)) & mask; \ + if (i == last) \ + return GIT_ENOTFOUND; \ + } \ + if (GIT_HASHMAP_IS_EITHER(h->flags, i)) \ + return GIT_ENOTFOUND; \ + *out = i; \ + return 0; \ + } \ + return GIT_ENOTFOUND; \ + } \ + GIT_UNUSED_FUNCTION scope bool name##_contains(name *h, key_t key) \ + { \ + uint32_t idx; \ + return name##__idx(&idx, h, key) == 0; \ + } \ + GIT_INLINE(int) name##__remove_at_idx(name *h, uint32_t idx) \ + { \ + if (idx < h->n_buckets && !GIT_HASHMAP_IS_EITHER(h->flags, idx)) { \ + GIT_HASHMAP_SET_DELETE_TRUE(h->flags, idx); \ + --h->size; \ + return 0; \ + } \ + return GIT_ENOTFOUND; \ + } \ + GIT_UNUSED_FUNCTION scope int name##_remove(name *h, key_t key) \ + { \ + uint32_t idx; \ + int error; \ + if ((error = name##__idx(&idx, h, key)) == 0) \ + error = name##__remove_at_idx(h, idx); \ + return error; \ + } \ + GIT_INLINE(int) name##__resize(name *h, uint32_t new_n_buckets) \ + { \ + /* This function uses 0.25*n_buckets bytes of working \ + * space instead of [sizeof(key_t+val_t)+.25]*n_buckets. \ + */ \ + double git_hashmap__upper_bound = 0.77; \ + uint32_t *new_flags = 0; \ + uint32_t j = 1; \ + { \ + GIT_HASHMAP_ROUNDUP(new_n_buckets); \ + if (new_n_buckets < 4) \ + new_n_buckets = 4; \ + if (h->size >= (uint32_t)(new_n_buckets * git_hashmap__upper_bound + 0.5)) { \ + /* Requested size is too small */ \ + j = 0; \ + } else { \ + /* Shrink or expand; rehash */ \ + new_flags = git__reallocarray(NULL, GIT_HASHMAP_FLAGSIZE(new_n_buckets), sizeof(uint32_t)); \ + if (!new_flags) \ + return -1; \ + memset(new_flags, 0xaa, GIT_HASHMAP_FLAGSIZE(new_n_buckets) * sizeof(uint32_t)); \ + if (h->n_buckets < new_n_buckets) { \ + /* Expand */ \ + key_t *new_keys = git__reallocarray(h->keys, new_n_buckets, sizeof(key_t)); \ + if (!new_keys) { \ + git__free(new_flags); \ + return -1; \ + } \ + h->keys = new_keys; \ + if (is_map) { \ + val_t *new_vals = git__reallocarray(h->vals, new_n_buckets, sizeof(val_t)); \ + if (!new_vals) { \ + git__free(new_flags); \ + return -1; \ + } \ + h->vals = new_vals; \ + } \ + } \ + } \ + } \ + if (j) { \ + /* Rehashing is needed */ \ + for (j = 0; j != h->n_buckets; ++j) { \ + if (GIT_HASHMAP_IS_EITHER(h->flags, j) == 0) { \ + key_t key = h->keys[j]; \ + val_t val; \ + uint32_t new_mask; \ + new_mask = new_n_buckets - 1; \ + if (is_map) \ + val = h->vals[j]; \ + GIT_HASHMAP_SET_DELETE_TRUE(h->flags, j); \ + while (1) { \ + /* Kick-out process; sort of like in Cuckoo hashing */ \ + uint32_t k, i, step = 0; \ + k = __hash_fn(key); \ + i = k & new_mask; \ + while (!GIT_HASHMAP_IS_EMPTY(new_flags, i)) \ + i = (i + (++step)) & new_mask; \ + GIT_HASHMAP_SET_EMPTY_FALSE(new_flags, i); \ + if (i < h->n_buckets && GIT_HASHMAP_IS_EITHER(h->flags, i) == 0) { \ + /* Kick out the existing element */ \ + { \ + key_t tmp = h->keys[i]; \ + h->keys[i] = key; \ + key = tmp; \ + } \ + if (is_map) { \ + val_t tmp = h->vals[i]; \ + h->vals[i] = val; \ + val = tmp; \ + } \ + /* Mark it as deleted in the old hash table */ \ + GIT_HASHMAP_SET_DELETE_TRUE(h->flags, i); \ + } else { \ + /* Write the element and jump out of the loop */ \ + h->keys[i] = key; \ + if (is_map) \ + h->vals[i] = val; \ + break; \ + } \ + } \ + } \ + } \ + if (h->n_buckets > new_n_buckets) { \ + /* Shrink the hash table */ \ + h->keys = git__reallocarray(h->keys, new_n_buckets, sizeof(key_t)); \ + if (is_map) \ + h->vals = git__reallocarray(h->vals, new_n_buckets, sizeof(val_t)); \ + } \ + /* free the working space */ \ + git__free(h->flags); \ + h->flags = new_flags; \ + h->n_buckets = new_n_buckets; \ + h->n_occupied = h->size; \ + h->upper_bound = (uint32_t)(h->n_buckets * git_hashmap__upper_bound + 0.5); \ + } \ + return 0; \ + } \ + GIT_INLINE(int) name##__put_idx(uint32_t *idx, bool *key_exists, name *h, key_t key) \ + { \ + uint32_t x; \ + if (h->n_occupied >= h->upper_bound) { \ + /* Update the hash table */ \ + if (h->n_buckets > (h->size<<1)) { \ + /* Clear "deleted" elements */ \ + if (name##__resize(h, h->n_buckets - 1) < 0) \ + return -1; \ + } else if (name##__resize(h, h->n_buckets + 1) < 0) { \ + return -1; \ + } \ + } \ + /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ + { \ + uint32_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ + x = site = h->n_buckets; \ + k = __hash_fn(key); \ + i = k & mask; \ + if (GIT_HASHMAP_IS_EMPTY(h->flags, i)) { \ + /* for speed up */ \ + x = i; \ + } else { \ + last = i; \ + while (!GIT_HASHMAP_IS_EMPTY(h->flags, i) && (GIT_HASHMAP_IS_DELETE(h->flags, i) || !__equal_fn(h->keys[i], key))) { \ + if (GIT_HASHMAP_IS_DELETE(h->flags, i)) \ + site = i; \ + i = (i + (++step)) & mask; \ + if (i == last) { \ + x = site; \ + break; \ + } \ + } \ + if (x == h->n_buckets) { \ + if (GIT_HASHMAP_IS_EMPTY(h->flags, i) && site != h->n_buckets) \ + x = site; \ + else \ + x = i; \ + } \ + } \ + } \ + if (GIT_HASHMAP_IS_EMPTY(h->flags, x)) { \ + /* not present at all */ \ + h->keys[x] = key; \ + GIT_HASHMAP_SET_BOTH_FALSE(h->flags, x); \ + ++h->size; \ + ++h->n_occupied; \ + *key_exists = 1; \ + } else if (GIT_HASHMAP_IS_DELETE(h->flags, x)) { \ + /* deleted */ \ + h->keys[x] = key; \ + GIT_HASHMAP_SET_BOTH_FALSE(h->flags, x); \ + ++h->size; \ + *key_exists = 1; \ + } else { \ + /* Don't touch h->keys[x] if present and not deleted */ \ + *key_exists = 0; \ + } \ + *idx = x; \ + return 0; \ + } \ + GIT_UNUSED_FUNCTION scope void name##_clear(name *h) \ + { \ + if (h && h->flags) { \ + memset(h->flags, 0xaa, GIT_HASHMAP_FLAGSIZE(h->n_buckets) * sizeof(uint32_t)); \ + h->size = h->n_occupied = 0; \ + } \ + } \ + GIT_UNUSED_FUNCTION scope void name##_dispose(name *h) \ + { \ + git__free(h->flags); \ + git__free(h->keys); \ + git__free(h->vals); \ + memset(h, 0, sizeof(name)); \ + } + +#define GIT_HASHMAP_FUNCTIONS(name, scope, key_t, val_t, __hash_fn, __equal_fn) \ + GIT_HASHMAP__COMMON_FUNCTIONS(name, true, scope, key_t, val_t, __hash_fn, __equal_fn) \ + \ + GIT_UNUSED_FUNCTION scope int name##_get(val_t *out, name *h, key_t key) \ + { \ + uint32_t idx; \ + int error; \ + if ((error = name##__idx(&idx, h, key)) == 0) \ + *out = (h)->vals[idx]; \ + return error; \ + } \ + GIT_UNUSED_FUNCTION scope int name##_put(name *h, key_t key, val_t val) \ + { \ + uint32_t idx; \ + bool key_exists; \ + int error = name##__put_idx(&idx, &key_exists, h, key); \ + if (error) \ + return error; \ + if (!key_exists) \ + (h)->keys[idx] = key; \ + (h)->vals[idx] = val; \ + return 0; \ + } \ + GIT_UNUSED_FUNCTION scope int name##_iterate(git_hashmap_iter_t *iter, key_t *key, val_t *val, name *h) \ + { \ + for (; *iter < h->n_buckets; (*iter)++) { \ + if (GIT_HASHMAP_IS_EITHER(h->flags, *iter)) \ + continue; \ + if (key) \ + *key = h->keys[*iter]; \ + if (val) \ + *val = h->vals[*iter]; \ + (*iter)++; \ + return 0; \ + } \ + return GIT_ITEROVER; \ + } \ + GIT_UNUSED_FUNCTION scope int name##_foreach(name *h, int (*cb)(key_t, val_t)) \ + { \ + uint32_t idx = 0; \ + key_t key; \ + val_t val; \ + int ret; \ + while ((ret = name##_iterate(&idx, &key, &val, h)) == 0) { \ + if ((ret = cb(key, val)) != 0) \ + return ret; \ + } \ + return ret == GIT_ITEROVER ? 0 : ret; \ + } + +#define GIT_HASHSET_FUNCTIONS(name, scope, key_t, __hash_fn, __equal_fn) \ + GIT_HASHMAP__COMMON_FUNCTIONS(name, false, scope, key_t, void *, __hash_fn, __equal_fn) \ + \ + GIT_UNUSED_FUNCTION scope int name##_add(name *h, key_t key) \ + { \ + uint32_t idx; \ + bool key_exists; \ + int error = name##__put_idx(&idx, &key_exists, h, key); \ + if (error) \ + return error; \ + if (!key_exists) \ + (h)->keys[idx] = key; \ + return 0; \ + } \ + GIT_UNUSED_FUNCTION scope int name##_iterate(git_hashmap_iter_t *iter, key_t *key, name *h) \ + { \ + for (; *iter < h->n_buckets; (*iter)++) { \ + if (GIT_HASHMAP_IS_EITHER(h->flags, *iter)) \ + continue; \ + *key = h->keys[*iter]; \ + return 0; \ + } \ + return GIT_ITEROVER; \ + } \ + GIT_UNUSED_FUNCTION scope int name##_foreach(name *h, int (*cb)(key_t)) \ + { \ + git_hashmap_iter_t iter = 0; \ + key_t key; \ + int ret; \ + while ((ret = name##_iterate(&iter, &key, h)) == 0) { \ + if ((ret = cb(key)) != 0) \ + return ret; \ + } \ + return ret == GIT_ITEROVER ? 0 : ret; \ + } + + +#define GIT_HASHSET_SETUP(name, key_t, __hash_fn, __equal_fn) \ + GIT_HASHSET_STRUCT(name, key_t) \ + GIT_HASHSET_FUNCTIONS(name, GIT_HASHMAP_INLINE, key_t, __hash_fn, __equal_fn) +#define GIT_HASHMAP_SETUP(name, key_t, val_t, __hash_fn, __equal_fn) \ + GIT_HASHMAP_STRUCT(name, key_t, val_t) \ + GIT_HASHMAP_FUNCTIONS(name, GIT_HASHMAP_INLINE, key_t, val_t, __hash_fn, __equal_fn) + +#endif diff --git a/src/util/hashmap_str.h b/src/util/hashmap_str.h new file mode 100644 index 00000000000..099aac5a879 --- /dev/null +++ b/src/util/hashmap_str.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_hashmap_str_h__ +#define INCLUDE_hashmap_str_h__ + +#include "hashmap.h" + +GIT_INLINE(uint32_t) git_hashmap_str_hash(const char *s) +{ + uint32_t h = (uint32_t)*s; + + if (h) { + for (++s; *s; ++s) + h = (h << 5) - h + (uint32_t)*s; + } + + return h; +} + +GIT_INLINE(bool) git_hashmap_str_equal(const char *one, const char *two) +{ + return strcmp(one, two) == 0; +} + +#define GIT_HASHMAP_STR_STRUCT(name, val_t) \ + GIT_HASHMAP_STRUCT(name, const char *, val_t) +#define GIT_HASHMAP_STR_PROTOTYPES(name, val_t) \ + GIT_HASHMAP_PROTOTYPES(name, const char *, val_t) +#define GIT_HASHMAP_STR_FUNCTIONS(name, scope, val_t) \ + GIT_HASHMAP_FUNCTIONS(name, scope, const char *, val_t, git_hashmap_str_hash, git_hashmap_str_equal) + +#define GIT_HASHMAP_STR_SETUP(name, val_t) \ + GIT_HASHMAP_STR_STRUCT(name, val_t) \ + GIT_HASHMAP_STR_FUNCTIONS(name, GIT_HASHMAP_INLINE, val_t) + +GIT_HASHSET_SETUP(git_hashset_str, const char *, git_hashmap_str_hash, git_hashmap_str_equal); +GIT_HASHMAP_SETUP(git_hashmap_str, const char *, void *, git_hashmap_str_hash, git_hashmap_str_equal); + +#endif diff --git a/tests/util/hashmap.c b/tests/util/hashmap.c new file mode 100644 index 00000000000..1bd072084b2 --- /dev/null +++ b/tests/util/hashmap.c @@ -0,0 +1,227 @@ +#include "clar_libgit2.h" +#include "hashmap.h" +#include "hashmap_str.h" + +GIT_HASHMAP_STR_SETUP(git_hashmap_test, char *); + +static git_hashmap_test g_table; + +void test_hashmap__initialize(void) +{ + memset(&g_table, 0x0, sizeof(git_hashmap_test)); +} + +void test_hashmap__cleanup(void) +{ + git_hashmap_test_dispose(&g_table); +} + +void test_hashmap__0(void) +{ + cl_assert(git_hashmap_test_size(&g_table) == 0); +} + +static void insert_strings(git_hashmap_test *table, size_t count) +{ + size_t i, j, over; + char *str; + + for (i = 0; i < count; ++i) { + str = git__malloc(10); + for (j = 0; j < 10; ++j) + str[j] = 'a' + (i % 26); + str[9] = '\0'; + + /* if > 26, then encode larger value in first letters */ + for (j = 0, over = i / 26; over > 0; j++, over = over / 26) + str[j] = 'A' + (over % 26); + + cl_git_pass(git_hashmap_test_put(table, str, str)); + } + + cl_assert_equal_i(git_hashmap_test_size(table), count); +} + +void test_hashmap__inserted_strings_can_be_retrieved(void) +{ + char *str; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + size_t idx = 0; + + insert_strings(&g_table, 20); + + cl_assert(git_hashmap_test_contains(&g_table, "aaaaaaaaa")); + cl_assert(git_hashmap_test_contains(&g_table, "ggggggggg")); + cl_assert(!git_hashmap_test_contains(&g_table, "aaaaaaaab")); + cl_assert(!git_hashmap_test_contains(&g_table, "abcdefghi")); + + while (git_hashmap_test_iterate(&iter, NULL, &str, &g_table) == 0) { + idx++; + git__free(str); + } + + cl_assert_equal_sz(20, idx); +} + +void test_hashmap__deleted_entry_cannot_be_retrieved(void) +{ + const char *key; + char *str; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + size_t idx = 0; + + insert_strings(&g_table, 20); + + cl_assert(git_hashmap_test_contains(&g_table, "bbbbbbbbb")); + cl_git_pass(git_hashmap_test_get(&str, &g_table, "bbbbbbbbb")); + cl_assert_equal_s(str, "bbbbbbbbb"); + cl_git_pass(git_hashmap_test_remove(&g_table, "bbbbbbbbb")); + git__free(str); + + cl_assert(!git_hashmap_test_contains(&g_table, "bbbbbbbbb")); + + while (git_hashmap_test_iterate(&iter, &key, &str, &g_table) == 0) { + idx++; + git__free(str); + } + + cl_assert_equal_sz(idx, 19); +} + +void test_hashmap__inserting_many_keys_succeeds(void) +{ + char *str; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + size_t idx = 0; + + insert_strings(&g_table, 10000); + + while (git_hashmap_test_iterate(&iter, NULL, &str, &g_table) == 0) { + idx++; + git__free(str); + } + + cl_assert_equal_sz(idx, 10000); +} + +void test_hashmap__get_succeeds_with_existing_entries(void) +{ + const char *keys[] = { "foo", "bar", "gobble" }; + char *values[] = { "oof", "rab", "elbbog" }; + char *str; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(keys); i++) + cl_git_pass(git_hashmap_test_put(&g_table, keys[i], values[i])); + + cl_git_pass(git_hashmap_test_get(&str, &g_table, "foo")); + cl_assert_equal_s(str, "oof"); + + cl_git_pass(git_hashmap_test_get(&str, &g_table, "bar")); + cl_assert_equal_s(str, "rab"); + + cl_git_pass(git_hashmap_test_get(&str, &g_table, "gobble")); + cl_assert_equal_s(str, "elbbog"); +} + +void test_hashmap__get_returns_notfound_on_nonexisting_key(void) +{ + const char *keys[] = { "foo", "bar", "gobble" }; + char *values[] = { "oof", "rab", "elbbog" }; + char *str; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(keys); i++) + cl_git_pass(git_hashmap_test_put(&g_table, keys[i], values[i])); + + cl_git_fail_with(GIT_ENOTFOUND, git_hashmap_test_get(&str, &g_table, "other")); +} + +void test_hashmap__put_persists_key(void) +{ + char *str; + + cl_git_pass(git_hashmap_test_put(&g_table, "foo", "oof")); + + cl_git_pass(git_hashmap_test_get(&str, &g_table, "foo")); + cl_assert_equal_s(str, "oof"); +} + +void test_hashmap__put_persists_multpile_keys(void) +{ + char *str; + + cl_git_pass(git_hashmap_test_put(&g_table, "foo", "oof")); + cl_git_pass(git_hashmap_test_put(&g_table, "bar", "rab")); + + cl_git_pass(git_hashmap_test_get(&str, &g_table, "foo")); + cl_assert_equal_s(str, "oof"); + + cl_git_pass(git_hashmap_test_get(&str, &g_table, "bar")); + cl_assert_equal_s(str, "rab"); +} + +void test_hashmap__put_updates_existing_key(void) +{ + char *str; + + cl_git_pass(git_hashmap_test_put(&g_table, "foo", "oof")); + cl_git_pass(git_hashmap_test_put(&g_table, "bar", "rab")); + cl_git_pass(git_hashmap_test_put(&g_table, "gobble", "elbbog")); + cl_assert_equal_i(3, git_hashmap_test_size(&g_table)); + + cl_git_pass(git_hashmap_test_put(&g_table, "foo", "other")); + cl_assert_equal_i(git_hashmap_test_size(&g_table), 3); + + cl_git_pass(git_hashmap_test_get(&str, &g_table, "foo")); + cl_assert_equal_s(str, "other"); +} + +void test_hashmap__iteration(void) +{ + struct { + char *key; + char *value; + int seen; + } entries[] = { + { "foo", "oof" }, + { "bar", "rab" }, + { "gobble", "elbbog" }, + }; + const char *key; + char *value; + uint32_t i, n; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + + for (i = 0; i < ARRAY_SIZE(entries); i++) + cl_git_pass(git_hashmap_test_put(&g_table, entries[i].key, entries[i].value)); + + i = 0, n = 0; + while (git_hashmap_test_iterate(&iter, &key, &value, &g_table) == 0) { + size_t j; + + for (j = 0; j < ARRAY_SIZE(entries); j++) { + if (strcmp(entries[j].key, key)) + continue; + + cl_assert_equal_i(entries[j].seen, 0); + cl_assert_equal_s(entries[j].value, value); + entries[j].seen++; + break; + } + + n++; + } + + for (i = 0; i < ARRAY_SIZE(entries); i++) + cl_assert_equal_i(entries[i].seen, 1); + + cl_assert_equal_i(n, ARRAY_SIZE(entries)); +} + +void test_hashmap__iterating_empty_map_stops_immediately(void) +{ + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + + cl_git_fail_with(GIT_ITEROVER, git_hashmap_test_iterate(&iter, NULL, NULL, &g_table)); +} From 0e110d2e9c0573c66320aef2653d20c751b7ed60 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:44:04 +0100 Subject: [PATCH 600/816] apply: use new hashset for strings --- src/libgit2/apply.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/libgit2/apply.c b/src/libgit2/apply.c index 202d2d2b8f0..c5c99c3ecbb 100644 --- a/src/libgit2/apply.c +++ b/src/libgit2/apply.c @@ -20,6 +20,7 @@ #include "reader.h" #include "index.h" #include "repository.h" +#include "hashmap_str.h" #include "apply.h" typedef struct { @@ -452,7 +453,7 @@ static int apply_one( git_reader *postimage_reader, git_index *postimage, git_diff *diff, - git_strmap *removed_paths, + git_hashset_str *removed_paths, size_t i, const git_apply_options *opts) { @@ -489,7 +490,7 @@ static int apply_one( */ if (delta->status != GIT_DELTA_RENAMED && delta->status != GIT_DELTA_ADDED) { - if (git_strmap_exists(removed_paths, delta->old_file.path)) { + if (git_hashset_str_contains(removed_paths, delta->old_file.path)) { error = apply_err("path '%s' has been renamed or deleted", delta->old_file.path); goto done; } @@ -573,11 +574,11 @@ static int apply_one( if (delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_DELETED) - error = git_strmap_set(removed_paths, delta->old_file.path, (char *) delta->old_file.path); + error = git_hashset_str_add(removed_paths, delta->old_file.path); if (delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_ADDED) - git_strmap_delete(removed_paths, delta->new_file.path); + git_hashset_str_remove(removed_paths, delta->new_file.path); done: git_str_dispose(&pre_contents); @@ -597,20 +598,17 @@ static int apply_deltas( git_diff *diff, const git_apply_options *opts) { - git_strmap *removed_paths; + git_hashset_str removed_paths = GIT_HASHSET_INIT; size_t i; int error = 0; - if (git_strmap_new(&removed_paths) < 0) - return -1; - for (i = 0; i < git_diff_num_deltas(diff); i++) { - if ((error = apply_one(repo, pre_reader, preimage, post_reader, postimage, diff, removed_paths, i, opts)) < 0) + if ((error = apply_one(repo, pre_reader, preimage, post_reader, postimage, diff, &removed_paths, i, opts)) < 0) goto done; } done: - git_strmap_free(removed_paths); + git_hashset_str_dispose(&removed_paths); return error; } From 7890eb1707acd66824973799d8a02959e1747073 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:45:15 +0100 Subject: [PATCH 601/816] attr: use a hashset instead of a strmap --- src/libgit2/attr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libgit2/attr.c b/src/libgit2/attr.c index d0eacd45adb..8d096d7d85c 100644 --- a/src/libgit2/attr.c +++ b/src/libgit2/attr.c @@ -13,6 +13,7 @@ #include "attr_file.h" #include "ignore.h" #include "git2/oid.h" +#include "hashmap_str.h" #include const char *git_attr__true = "[internal]__TRUE__"; @@ -254,7 +255,7 @@ int git_attr_foreach_ext( git_attr_file *file; git_attr_rule *rule; git_attr_assignment *assign; - git_strmap *seen = NULL; + git_hashset_str seen = GIT_HASHSET_INIT; git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN; GIT_ASSERT_ARG(repo); @@ -267,8 +268,7 @@ int git_attr_foreach_ext( if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0) return -1; - if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0 || - (error = git_strmap_new(&seen)) < 0) + if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0) goto cleanup; git_vector_foreach(&files, i, file) { @@ -277,10 +277,10 @@ int git_attr_foreach_ext( git_vector_foreach(&rule->assigns, k, assign) { /* skip if higher priority assignment was already seen */ - if (git_strmap_exists(seen, assign->name)) + if (git_hashset_str_contains(&seen, assign->name)) continue; - if ((error = git_strmap_set(seen, assign->name, assign)) < 0) + if ((error = git_hashset_str_add(&seen, assign->name)) < 0) goto cleanup; error = callback(assign->name, assign->value, payload); @@ -293,7 +293,7 @@ int git_attr_foreach_ext( } cleanup: - git_strmap_free(seen); + git_hashset_str_dispose(&seen); release_attr_files(&files); git_attr_path__free(&path); From 29f141d84bd49f019eddc37fa8df0df41ee1a366 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 20:48:49 +0100 Subject: [PATCH 602/816] attr_cache: move from strmap to hashset_str --- src/libgit2/attrcache.c | 82 +++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/src/libgit2/attrcache.c b/src/libgit2/attrcache.c index 1d906bbfa09..2a822147a65 100644 --- a/src/libgit2/attrcache.c +++ b/src/libgit2/attrcache.c @@ -13,12 +13,20 @@ #include "sysdir.h" #include "ignore.h" #include "path.h" +#include "hashmap_str.h" + +GIT_HASHMAP_STR_SETUP(git_attr_cache_filemap, git_attr_file_entry *); +GIT_HASHMAP_STR_SETUP(git_attr_cache_macromap, git_attr_rule *); struct git_attr_cache { char *cfg_attr_file; /* cached value of core.attributesfile */ char *cfg_excl_file; /* cached value of core.excludesfile */ - git_strmap *files; /* hash path to git_attr_cache_entry records */ - git_strmap *macros; /* hash name to vector */ + + /* hash path to git_attr_file_entry records */ + git_attr_cache_filemap files; + /* hash name to git_attr_rule */ + git_attr_cache_macromap macros; + git_mutex lock; git_pool pool; }; @@ -58,7 +66,12 @@ GIT_INLINE(void) attr_cache_unlock(git_attr_cache *cache) GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry( git_attr_cache *cache, const char *path) { - return git_strmap_get(cache->files, path); + git_attr_file_entry *result; + + if (git_attr_cache_filemap_get(&result, &cache->files, path) == 0) + return result; + + return NULL; } int git_attr_cache__alloc_file_entry( @@ -116,7 +129,7 @@ static int attr_cache_make_entry( git_repository_workdir(repo), path, &cache->pool)) < 0) return error; - if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0) + if ((error = git_attr_cache_filemap_put(&cache->files, entry->path, entry)) < 0) return error; *out = entry; @@ -295,12 +308,11 @@ bool git_attr_cache__is_cached( { git_attr_cache *cache = git_repository_attr_cache(repo); git_attr_file_entry *entry; - git_strmap *files; - if (!cache || !(files = cache->files)) + if (!cache) return false; - if ((entry = git_strmap_get(files, filename)) == NULL) + if (git_attr_cache_filemap_get(&entry, &cache->files, filename) != 0) return false; return entry && (entry->file[source_type] != NULL); @@ -342,6 +354,9 @@ static int attr_cache__lookup_path( static void attr_cache__free(git_attr_cache *cache) { + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + git_attr_rule *rule; + git_attr_file_entry *entry; bool unlock; if (!cache) @@ -349,30 +364,24 @@ static void attr_cache__free(git_attr_cache *cache) unlock = (attr_cache_lock(cache) == 0); - if (cache->files != NULL) { - git_attr_file_entry *entry; + while (git_attr_cache_filemap_iterate(&iter, NULL, &entry, &cache->files) == 0) { git_attr_file *file; - int i; - - git_strmap_foreach_value(cache->files, entry, { - for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; ++i) { - if ((file = git_atomic_swap(entry->file[i], NULL)) != NULL) { - GIT_REFCOUNT_OWN(file, NULL); - git_attr_file__free(file); - } + size_t i; + + for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; i++) { + if ((file = git_atomic_swap(entry->file[i], NULL)) != NULL) { + GIT_REFCOUNT_OWN(file, NULL); + git_attr_file__free(file); } - }); - git_strmap_free(cache->files); + } } - if (cache->macros != NULL) { - git_attr_rule *rule; + iter = GIT_HASHMAP_ITER_INIT; + while (git_attr_cache_macromap_iterate(&iter, NULL, &rule, &cache->macros) == 0) + git_attr_rule__free(rule); - git_strmap_foreach_value(cache->macros, rule, { - git_attr_rule__free(rule); - }); - git_strmap_free(cache->macros); - } + git_attr_cache_filemap_dispose(&cache->files); + git_attr_cache_macromap_dispose(&cache->macros); git_pool_clear(&cache->pool); @@ -425,9 +434,7 @@ int git_attr_cache__init(git_repository *repo) /* allocate hashtable for attribute and ignore file contents, * hashtable for attribute macros, and string pool */ - if ((ret = git_strmap_new(&cache->files)) < 0 || - (ret = git_strmap_new(&cache->macros)) < 0 || - (ret = git_pool_init(&cache->pool, 1)) < 0) + if ((ret = git_pool_init(&cache->pool, 1)) < 0) goto cancel; if (git_atomic_compare_and_swap(&repo->attrcache, NULL, cache) != NULL) @@ -481,11 +488,11 @@ int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro) goto out; locked = true; - if ((preexisting = git_strmap_get(cache->macros, macro->match.pattern)) != NULL) - git_attr_rule__free(preexisting); + if (git_attr_cache_macromap_get(&preexisting, &cache->macros, macro->match.pattern) == 0) + git_attr_rule__free(preexisting); - if ((error = git_strmap_set(cache->macros, macro->match.pattern, macro)) < 0) - goto out; + if ((error = git_attr_cache_macromap_put(&cache->macros, macro->match.pattern, macro)) < 0) + goto out; out: if (locked) @@ -496,7 +503,12 @@ int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro) git_attr_rule *git_attr_cache__lookup_macro( git_repository *repo, const char *name) { - git_strmap *macros = git_repository_attr_cache(repo)->macros; + git_attr_cache *cache = git_repository_attr_cache(repo); + git_attr_rule *rule; + + if (!cache || + git_attr_cache_macromap_get(&rule, &cache->macros, name) != 0) + return NULL; - return git_strmap_get(macros, name); + return rule; } From ee29ac7f030ae64ec06810746e9e45ece2bbd6ac Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:57:30 +0100 Subject: [PATCH 603/816] checkout: use a hashset_str instead of a strmap --- src/libgit2/checkout.c | 16 ++++++++-------- src/libgit2/submodule.h | 1 + src/util/futils.c | 11 ++++++----- src/util/futils.h | 15 ++++++++++++--- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/libgit2/checkout.c b/src/libgit2/checkout.c index cd5cf21ca56..4628f33b2c6 100644 --- a/src/libgit2/checkout.c +++ b/src/libgit2/checkout.c @@ -30,8 +30,8 @@ #include "fs_path.h" #include "attr.h" #include "pool.h" -#include "strmap.h" #include "path.h" +#include "hashmap_str.h" /* See docs/checkout-internals.md for more information */ @@ -72,7 +72,7 @@ typedef struct { size_t total_steps; size_t completed_steps; git_checkout_perfdata perfdata; - git_strmap *mkdir_map; + git_hashset_str mkdir_pathcache; git_attr_session attr_session; } checkout_data; @@ -1419,8 +1419,10 @@ static int checkout_mkdir( struct git_futils_mkdir_options mkdir_opts = {0}; int error; - mkdir_opts.dir_map = data->mkdir_map; - mkdir_opts.pool = &data->pool; + if (git_pool_is_initialized(&data->pool)) { + mkdir_opts.cache_pool = &data->pool; + mkdir_opts.cache_pathset = &data->mkdir_pathcache; + } error = git_futils_mkdir_relative( path, base, mode, flags, &mkdir_opts); @@ -2331,8 +2333,7 @@ static void checkout_data_clear(checkout_data *data) git_index_free(data->index); data->index = NULL; - git_strmap_free(data->mkdir_map); - data->mkdir_map = NULL; + git_hashset_str_dispose(&data->mkdir_pathcache); git_attr_session__free(&data->attr_session); } @@ -2513,8 +2514,7 @@ static int checkout_data_init( (error = git_vector_init(&data->remove_conflicts, 0, NULL)) < 0 || (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 || (error = git_str_puts(&data->target_path, data->opts.target_directory)) < 0 || - (error = git_fs_path_to_dir(&data->target_path)) < 0 || - (error = git_strmap_new(&data->mkdir_map)) < 0) + (error = git_fs_path_to_dir(&data->target_path)) < 0) goto cleanup; data->target_len = git_str_len(&data->target_path); diff --git a/src/libgit2/submodule.h b/src/libgit2/submodule.h index 40b7b70f777..11c9996aa6a 100644 --- a/src/libgit2/submodule.h +++ b/src/libgit2/submodule.h @@ -12,6 +12,7 @@ #include "git2/submodule.h" #include "git2/repository.h" #include "futils.h" +#include "strmap.h" /* Notes: * diff --git a/src/util/futils.c b/src/util/futils.c index 7b5a24b305f..eb32cbb1205 100644 --- a/src/util/futils.c +++ b/src/util/futils.c @@ -8,9 +8,9 @@ #include "futils.h" #include "runtime.h" -#include "strmap.h" #include "hash.h" #include "rand.h" +#include "hashmap_str.h" #include @@ -653,7 +653,8 @@ int git_futils_mkdir_relative( *tail = '\0'; st.st_mode = 0; - if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) + if (opts->cache_pathset && + git_hashset_str_contains(opts->cache_pathset, make_path.ptr)) continue; /* See what's going on with this path component */ @@ -688,17 +689,17 @@ int git_futils_mkdir_relative( make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0) goto done; - if (opts->dir_map && opts->pool) { + if (opts->cache_pathset && opts->cache_pool) { char *cache_path; size_t alloc_size; GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1); - cache_path = git_pool_malloc(opts->pool, alloc_size); + cache_path = git_pool_malloc(opts->cache_pool, alloc_size); GIT_ERROR_CHECK_ALLOC(cache_path); memcpy(cache_path, make_path.ptr, make_path.size + 1); - if ((error = git_strmap_set(opts->dir_map, cache_path, cache_path)) < 0) + if ((error = git_hashset_str_add(opts->cache_pathset, cache_path)) < 0) goto done; } } diff --git a/src/util/futils.h b/src/util/futils.h index 53bcc551890..7ae869be6ec 100644 --- a/src/util/futils.h +++ b/src/util/futils.h @@ -13,8 +13,8 @@ #include "posix.h" #include "fs_path.h" #include "pool.h" -#include "strmap.h" #include "hash.h" +#include "hashmap_str.h" /** * Filebuffer methods @@ -109,8 +109,17 @@ struct git_futils_mkdir_perfdata struct git_futils_mkdir_options { - git_strmap *dir_map; - git_pool *pool; + /* + * Callers can optionally pass an allocation pool and a + * hashset of strings; mkdir will populate these with the + * path(s) it creates; this can be useful for repeated calls + * to mkdir. This will reduce I/O by avoiding testing for the + * existence of intermediate directories that it knows already + * exist (because it created them). + */ + git_pool *cache_pool; + git_hashset_str *cache_pathset; + struct git_futils_mkdir_perfdata perfdata; }; From 1f0c38fbad7c083a8c589d03b1331fc0a8d9be82 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:57:45 +0100 Subject: [PATCH 604/816] config_list: use a hashset_str instead of a strmap --- src/libgit2/config_list.c | 45 ++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/libgit2/config_list.c b/src/libgit2/config_list.c index c6042149c78..0e6559795c2 100644 --- a/src/libgit2/config_list.c +++ b/src/libgit2/config_list.c @@ -6,6 +6,7 @@ */ #include "config_list.h" +#include "hashmap_str.h" typedef struct config_entry_list { struct config_entry_list *next; @@ -24,14 +25,17 @@ typedef struct config_list_iterator { config_entry_list *head; } config_list_iterator; +GIT_HASHMAP_STR_SETUP(git_config_list_pathmap, char *); +GIT_HASHMAP_STR_SETUP(git_config_list_headmap, config_entry_map_head *); + struct git_config_list { git_refcount rc; /* Interned strings - paths to config files or backend types */ - git_strmap *strings; + git_config_list_pathmap strings; /* Config entries */ - git_strmap *map; + git_config_list_headmap map; config_entry_list *entries; }; @@ -43,15 +47,6 @@ int git_config_list_new(git_config_list **out) GIT_ERROR_CHECK_ALLOC(config_list); GIT_REFCOUNT_INC(config_list); - if (git_strmap_new(&config_list->strings) < 0 || - git_strmap_new(&config_list->map) < 0) { - git_strmap_free(config_list->strings); - git_strmap_free(config_list->map); - git__free(config_list); - - return -1; - } - *out = config_list; return 0; } @@ -128,17 +123,19 @@ static void config_list_free(git_config_list *config_list) config_entry_list *entry_list = NULL, *next; config_entry_map_head *head; char *str; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; - git_strmap_foreach_value(config_list->strings, str, { + while (git_config_list_pathmap_iterate(&iter, NULL, &str, &config_list->strings) == 0) git__free(str); - }); - git_strmap_free(config_list->strings); - git_strmap_foreach_value(config_list->map, head, { + git_config_list_pathmap_dispose(&config_list->strings); + + iter = GIT_HASHMAP_ITER_INIT; + while (git_config_list_headmap_iterate(&iter, NULL, &head, &config_list->map) == 0) { git__free((char *) head->entry->base.entry.name); git__free(head); - }); - git_strmap_free(config_list->map); + } + git_config_list_headmap_dispose(&config_list->map); entry_list = config_list->entries; while (entry_list != NULL) { @@ -163,7 +160,7 @@ int git_config_list_append(git_config_list *config_list, git_config_list_entry * config_entry_list *list_head; config_entry_map_head *map_head; - if ((map_head = git_strmap_get(config_list->map, entry->base.entry.name)) != NULL) { + if (git_config_list_headmap_get(&map_head, &config_list->map, entry->base.entry.name) == 0) { map_head->multivar = true; /* * This is a micro-optimization for configuration files @@ -175,7 +172,7 @@ int git_config_list_append(git_config_list *config_list, git_config_list_entry * entry->base.entry.name = map_head->entry->base.entry.name; } else { map_head = git__calloc(1, sizeof(*map_head)); - if ((git_strmap_set(config_list->map, entry->base.entry.name, map_head)) < 0) + if ((git_config_list_headmap_put(&config_list->map, entry->base.entry.name, map_head)) < 0) return -1; } map_head->entry = entry; @@ -197,7 +194,7 @@ int git_config_list_get(git_config_list_entry **out, git_config_list *config_lis { config_entry_map_head *entry; - if ((entry = git_strmap_get(config_list->map, key)) == NULL) + if (git_config_list_headmap_get(&entry, &config_list->map, key) != 0) return GIT_ENOTFOUND; *out = entry->entry; @@ -208,7 +205,7 @@ int git_config_list_get_unique(git_config_list_entry **out, git_config_list *con { config_entry_map_head *entry; - if ((entry = git_strmap_get(config_list->map, key)) == NULL) + if (git_config_list_headmap_get(&entry, &config_list->map, key) != 0) return GIT_ENOTFOUND; if (entry->multivar) { @@ -275,13 +272,13 @@ const char *git_config_list_add_string( git_config_list *config_list, const char *str) { - const char *s; + char *s; - if ((s = git_strmap_get(config_list->strings, str)) != NULL) + if (git_config_list_pathmap_get(&s, &config_list->strings, str) == 0) return s; if ((s = git__strdup(str)) == NULL || - git_strmap_set(config_list->strings, s, (void *)s) < 0) + git_config_list_pathmap_put(&config_list->strings, s, s) < 0) return NULL; return s; From 8dc52d05add7002a65196662ee7736da7b356c0a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 22:59:25 +0100 Subject: [PATCH 605/816] sortedcache: use a hashset_str instead of a strmap --- src/util/sortedcache.c | 23 ++++++++++++----------- src/util/sortedcache.h | 6 +++--- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/util/sortedcache.c b/src/util/sortedcache.c index 6e421aa2e81..05b94347267 100644 --- a/src/util/sortedcache.c +++ b/src/util/sortedcache.c @@ -6,6 +6,7 @@ */ #include "sortedcache.h" +#include "hashmap.h" int git_sortedcache_new( git_sortedcache **out, @@ -26,8 +27,7 @@ int git_sortedcache_new( GIT_ERROR_CHECK_ALLOC(sc); if (git_pool_init(&sc->pool, 1) < 0 || - git_vector_init(&sc->items, 4, item_cmp) < 0 || - git_strmap_new(&sc->map) < 0) + git_vector_init(&sc->items, 4, item_cmp) < 0) goto fail; if (git_rwlock_init(&sc->lock)) { @@ -46,7 +46,6 @@ int git_sortedcache_new( return 0; fail: - git_strmap_free(sc->map); git_vector_dispose(&sc->items); git_pool_clear(&sc->pool); git__free(sc); @@ -65,7 +64,7 @@ const char *git_sortedcache_path(git_sortedcache *sc) static void sortedcache_clear(git_sortedcache *sc) { - git_strmap_clear(sc->map); + git_hashmap_str_clear(&sc->map); if (sc->free_item) { size_t i; @@ -89,7 +88,7 @@ static void sortedcache_free(git_sortedcache *sc) sortedcache_clear(sc); git_vector_dispose(&sc->items); - git_strmap_free(sc->map); + git_hashmap_str_dispose(&sc->map); git_sortedcache_wunlock(sc); @@ -274,7 +273,7 @@ int git_sortedcache_upsert(void **out, git_sortedcache *sc, const char *key) char *item_key; void *item; - if ((item = git_strmap_get(sc->map, key)) != NULL) + if (git_hashmap_str_get(&item, &sc->map, key) == 0) goto done; keylen = strlen(key); @@ -294,11 +293,11 @@ int git_sortedcache_upsert(void **out, git_sortedcache *sc, const char *key) item_key = ((char *)item) + sc->item_path_offset; memcpy(item_key, key, keylen); - if ((error = git_strmap_set(sc->map, item_key, item)) < 0) + if ((error = git_hashmap_str_put(&sc->map, item_key, item)) < 0) goto done; if ((error = git_vector_insert(&sc->items, item)) < 0) - git_strmap_delete(sc->map, item_key); + git_hashmap_str_remove(&sc->map, item_key); done: if (out) @@ -307,9 +306,11 @@ int git_sortedcache_upsert(void **out, git_sortedcache *sc, const char *key) } /* lookup item by key */ -void *git_sortedcache_lookup(const git_sortedcache *sc, const char *key) +void *git_sortedcache_lookup(git_sortedcache *sc, const char *key) { - return git_strmap_get(sc->map, key); + void *value; + + return git_hashmap_str_get(&value, &sc->map, key) == 0 ? value : NULL; } /* find out how many items are in the cache */ @@ -370,7 +371,7 @@ int git_sortedcache_remove(git_sortedcache *sc, size_t pos) (void)git_vector_remove(&sc->items, pos); - git_strmap_delete(sc->map, item + sc->item_path_offset); + git_hashmap_str_remove(&sc->map, item + sc->item_path_offset); if (sc->free_item) sc->free_item(sc->free_item_payload, item); diff --git a/src/util/sortedcache.h b/src/util/sortedcache.h index 3eee4659f58..d4383e96517 100644 --- a/src/util/sortedcache.h +++ b/src/util/sortedcache.h @@ -14,7 +14,7 @@ #include "vector.h" #include "thread.h" #include "pool.h" -#include "strmap.h" +#include "hashmap_str.h" #include @@ -36,7 +36,7 @@ typedef struct { void *free_item_payload; git_pool pool; git_vector items; - git_strmap *map; + git_hashmap_str map; git_futils_filestamp stamp; char path[GIT_FLEX_ARRAY]; } git_sortedcache; @@ -163,7 +163,7 @@ GIT_WARN_UNUSED_RESULT int git_sortedcache_rlock(git_sortedcache *sc); void git_sortedcache_runlock(git_sortedcache *sc); /* Lookup item by key - returns NULL if not found */ -void *git_sortedcache_lookup(const git_sortedcache *sc, const char *key); +void *git_sortedcache_lookup(git_sortedcache *sc, const char *key); /* Get how many items are in the cache * From be8e75a0e1c6164352b8bb5851f70eb6b9405543 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 23:00:28 +0100 Subject: [PATCH 606/816] diff_driver: use a hashmap_str instead of a strmap --- src/libgit2/diff_driver.c | 31 ++++++++++++------------------- src/libgit2/diff_driver.h | 4 ++-- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/libgit2/diff_driver.c b/src/libgit2/diff_driver.c index 5f25fdb442b..7055575e766 100644 --- a/src/libgit2/diff_driver.c +++ b/src/libgit2/diff_driver.c @@ -11,11 +11,11 @@ #include "common.h" #include "diff.h" -#include "strmap.h" #include "map.h" #include "config.h" #include "regexp.h" #include "repository.h" +#include "userdiff.h" typedef enum { DIFF_DRIVER_AUTO = 0, @@ -43,10 +43,10 @@ struct git_diff_driver { char name[GIT_FLEX_ARRAY]; }; -#include "userdiff.h" +GIT_HASHMAP_STR_SETUP(git_diff_driver_map, git_diff_driver *); struct git_diff_driver_registry { - git_strmap *drivers; + git_diff_driver_map map; }; #define FORCE_DIFFABLE (GIT_DIFF_FORCE_TEXT | GIT_DIFF_FORCE_BINARY) @@ -57,28 +57,21 @@ static git_diff_driver diff_driver_text = { DIFF_DRIVER_TEXT, GIT_DIFF_FORCE git_diff_driver_registry *git_diff_driver_registry_new(void) { - git_diff_driver_registry *reg = - git__calloc(1, sizeof(git_diff_driver_registry)); - if (!reg) - return NULL; - - if (git_strmap_new(®->drivers) < 0) { - git_diff_driver_registry_free(reg); - return NULL; - } - - return reg; + return git__calloc(1, sizeof(git_diff_driver_registry)); } void git_diff_driver_registry_free(git_diff_driver_registry *reg) { git_diff_driver *drv; + git_hashmap_iter_t iter = 0; if (!reg) return; - git_strmap_foreach_value(reg->drivers, drv, git_diff_driver_free(drv)); - git_strmap_free(reg->drivers); + while (git_diff_driver_map_iterate(&iter, NULL, &drv, ®->map) == 0) + git_diff_driver_free(drv); + + git_diff_driver_map_dispose(®->map); git__free(reg); } @@ -215,7 +208,7 @@ static int git_diff_driver_builtin( (error = git_regexp_compile(&drv->word_pattern, ddef->words, ddef->flags)) < 0) goto done; - if ((error = git_strmap_set(reg->drivers, drv->name, drv)) < 0) + if ((error = git_diff_driver_map_put(®->map, drv->name, drv)) < 0) goto done; done: @@ -242,7 +235,7 @@ static int git_diff_driver_load( if ((reg = git_repository_driver_registry(repo)) == NULL) return -1; - if ((drv = git_strmap_get(reg->drivers, driver_name)) != NULL) { + if (git_diff_driver_map_get(&drv, ®->map, driver_name) == 0) { *out = drv; return 0; } @@ -331,7 +324,7 @@ static int git_diff_driver_load( goto done; /* store driver in registry */ - if ((error = git_strmap_set(reg->drivers, drv->name, drv)) < 0) + if ((error = git_diff_driver_map_put(®->map, drv->name, drv)) < 0) goto done; *out = drv; diff --git a/src/libgit2/diff_driver.h b/src/libgit2/diff_driver.h index 03711e89e8b..ca0a7ae1e84 100644 --- a/src/libgit2/diff_driver.h +++ b/src/libgit2/diff_driver.h @@ -11,14 +11,14 @@ #include "attr_file.h" #include "str.h" +#include "hashmap.h" +typedef struct git_diff_driver git_diff_driver; typedef struct git_diff_driver_registry git_diff_driver_registry; git_diff_driver_registry *git_diff_driver_registry_new(void); void git_diff_driver_registry_free(git_diff_driver_registry *); -typedef struct git_diff_driver git_diff_driver; - int git_diff_driver_lookup(git_diff_driver **, git_repository *, git_attr_session *attrsession, const char *); void git_diff_driver_free(git_diff_driver *); From c9c5eba32dc7d4fde9e8d4ac2b92201721cf8e7a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 23:19:38 +0100 Subject: [PATCH 607/816] submodule: use a hashmap for submodule map --- src/libgit2/diff_generate.c | 4 +- src/libgit2/repository.h | 2 +- src/libgit2/submodule.c | 159 +++++++++++++++++++++++------------- src/libgit2/submodule.h | 14 ++-- 4 files changed, 110 insertions(+), 69 deletions(-) diff --git a/src/libgit2/diff_generate.c b/src/libgit2/diff_generate.c index 6eeb3b544aa..654145e34a6 100644 --- a/src/libgit2/diff_generate.c +++ b/src/libgit2/diff_generate.c @@ -729,7 +729,7 @@ typedef struct { git_iterator *new_iter; const git_index_entry *oitem; const git_index_entry *nitem; - git_strmap *submodule_cache; + git_submodule_cache *submodule_cache; bool submodule_cache_initialized; } diff_in_progress; @@ -745,7 +745,7 @@ static int maybe_modified_submodule( git_submodule *sub; unsigned int sm_status = 0; git_submodule_ignore_t ign = diff->base.opts.ignore_submodules; - git_strmap *submodule_cache = NULL; + git_submodule_cache *submodule_cache = NULL; *status = GIT_DELTA_UNMODIFIED; diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index f45a3591981..704e0ad2e10 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -165,7 +165,7 @@ struct git_repository { git_atomic32 attr_session_key; intptr_t configmap_cache[GIT_CONFIGMAP_CACHE_MAX]; - git_strmap *submodule_cache; + git_submodule_cache *submodule_cache; }; GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) diff --git a/src/libgit2/submodule.c b/src/libgit2/submodule.c index 005085e99f2..a3bfc787274 100644 --- a/src/libgit2/submodule.c +++ b/src/libgit2/submodule.c @@ -169,22 +169,27 @@ static int is_path_occupied(bool *occupied, git_repository *repo, const char *pa return error; } +GIT_HASHMAP_STR_SETUP(git_submodule_namemap, char *); + /** * Release the name map returned by 'load_submodule_names'. */ -static void free_submodule_names(git_strmap *names) +static void free_submodule_names(git_submodule_namemap *names) { + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; const char *key; char *value; if (names == NULL) return; - git_strmap_foreach(names, key, value, { - git__free((char *) key); + while (git_submodule_namemap_iterate(&iter, &key, &value, names) == 0) { + git__free((char *)key); git__free(value); - }); - git_strmap_free(names); + } + + git_submodule_namemap_dispose(names); + git__free(names); return; } @@ -194,19 +199,22 @@ static void free_submodule_names(git_strmap *names) * TODO: for some use-cases, this might need case-folding on a * case-insensitive filesystem */ -static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg) +static int load_submodule_names(git_submodule_namemap **out, git_repository *repo, git_config *cfg) { const char *key = "^submodule\\..*\\.path$"; + char *value; git_config_iterator *iter = NULL; git_config_entry *entry; git_str buf = GIT_STR_INIT; - git_strmap *names; + git_submodule_namemap *names; int isvalid, error; *out = NULL; - if ((error = git_strmap_new(&names)) < 0) + if ((names = git__calloc(1, sizeof(git_submodule_namemap))) == NULL) { + error = -1; goto out; + } if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0) goto out; @@ -216,7 +224,7 @@ static int load_submodule_names(git_strmap **out, git_repository *repo, git_conf fdot = strchr(entry->name, '.'); ldot = strrchr(entry->name, '.'); - if (git_strmap_exists(names, entry->value)) { + if (git_submodule_namemap_contains(names, entry->value)) { git_error_set(GIT_ERROR_SUBMODULE, "duplicated submodule path '%s'", entry->value); error = -1; @@ -233,7 +241,12 @@ static int load_submodule_names(git_strmap **out, git_repository *repo, git_conf if (!isvalid) continue; - if ((error = git_strmap_set(names, git__strdup(entry->value), git_str_detach(&buf))) < 0) { + if ((value = git__strdup(entry->value)) == NULL) { + error = -1; + goto out; + } + + if ((error = git_submodule_namemap_put(names, value, git_str_detach(&buf))) < 0) { git_error_set(GIT_ERROR_NOMEMORY, "error inserting submodule into hash table"); error = -1; goto out; @@ -252,31 +265,43 @@ static int load_submodule_names(git_strmap **out, git_repository *repo, git_conf return error; } -int git_submodule_cache_init(git_strmap **out, git_repository *repo) +GIT_HASHMAP_STR_FUNCTIONS(git_submodule_cache, GIT_HASHMAP_INLINE, git_submodule *); + +int git_submodule__map(git_submodule_cache *cache, git_repository *repo); + +int git_submodule_cache_init(git_submodule_cache **out, git_repository *repo) { + git_submodule_cache *cache = NULL; int error = 0; - git_strmap *cache = NULL; + GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(repo); - if ((error = git_strmap_new(&cache)) < 0) - return error; - if ((error = git_submodule__map(repo, cache)) < 0) { + + if ((cache = git__calloc(1, sizeof(git_submodule_cache))) == NULL) + return -1; + + if ((error = git_submodule__map(cache, repo)) < 0) { git_submodule_cache_free(cache); return error; } + *out = cache; return error; } -int git_submodule_cache_free(git_strmap *cache) +int git_submodule_cache_free(git_submodule_cache *cache) { git_submodule *sm = NULL; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + if (cache == NULL) return 0; - git_strmap_foreach_value(cache, sm, { + + while (git_submodule_cache_iterate(&iter, NULL, &sm, cache) == 0) git_submodule_free(sm); - }); - git_strmap_free(cache); + + git_submodule_cache_dispose(cache); + git__free(cache); return 0; } @@ -292,7 +317,7 @@ int git_submodule__lookup_with_cache( git_submodule **out, /* NULL if user only wants to test existence */ git_repository *repo, const char *name, /* trailing slash is allowed */ - git_strmap *cache) + git_submodule_cache *cache) { int error; unsigned int location; @@ -307,7 +332,7 @@ int git_submodule__lookup_with_cache( } if (cache != NULL) { - if ((sm = git_strmap_get(cache, name)) != NULL) { + if (git_submodule_cache_get(&sm, cache, name) == 0) { if (out) { *out = sm; GIT_REFCOUNT_INC(*out); @@ -434,19 +459,23 @@ static void submodule_free_dup(void *sm) git_submodule_free(sm); } -static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name) +static int submodule_get_or_create( + git_submodule **out, + git_repository *repo, + git_submodule_cache *cache, + const char *name) { git_submodule *sm = NULL; int error; - if ((sm = git_strmap_get(map, name)) != NULL) + if (git_submodule_cache_get(&sm, cache, name) == 0) goto done; /* if the submodule doesn't exist yet in the map, create it */ if ((error = submodule_alloc(&sm, repo, name)) < 0) return error; - if ((error = git_strmap_set(map, sm->name, sm)) < 0) { + if ((error = git_submodule_cache_put(cache, sm->name, sm)) < 0) { git_submodule_free(sm); return error; } @@ -457,12 +486,15 @@ static int submodule_get_or_create(git_submodule **out, git_repository *repo, gi return 0; } -static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg) +static int submodules_from_index( + git_submodule_cache *cache, + git_index *idx, + git_config *cfg) { int error; git_iterator *i = NULL; const git_index_entry *entry; - git_strmap *names; + git_submodule_namemap *names; if ((error = load_submodule_names(&names, git_index_owner(idx), cfg))) goto done; @@ -473,7 +505,7 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf while (!(error = git_iterator_advance(&entry, i))) { git_submodule *sm; - if ((sm = git_strmap_get(map, entry->path)) != NULL) { + if (git_submodule_cache_get(&sm, cache, entry->path) == 0) { if (S_ISGITLINK(entry->mode)) submodule_update_from_index_entry(sm, entry); else @@ -481,10 +513,10 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf } else if (S_ISGITLINK(entry->mode)) { const char *name; - if ((name = git_strmap_get(names, entry->path)) == NULL) + if (git_submodule_namemap_get((char **)&name, names, entry->path) != 0) name = entry->path; - if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) { + if (!submodule_get_or_create(&sm, git_index_owner(idx), cache, name)) { submodule_update_from_index_entry(sm, entry); git_submodule_free(sm); } @@ -501,12 +533,15 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf return error; } -static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg) +static int submodules_from_head( + git_submodule_cache *cache, + git_tree *head, + git_config *cfg) { int error; git_iterator *i = NULL; const git_index_entry *entry; - git_strmap *names; + git_submodule_namemap *names; if ((error = load_submodule_names(&names, git_tree_owner(head), cfg))) goto done; @@ -517,7 +552,7 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg while (!(error = git_iterator_advance(&entry, i))) { git_submodule *sm; - if ((sm = git_strmap_get(map, entry->path)) != NULL) { + if (git_submodule_cache_get(&sm, cache, entry->path) == 0) { if (S_ISGITLINK(entry->mode)) submodule_update_from_head_data(sm, entry->mode, &entry->id); else @@ -525,10 +560,10 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg } else if (S_ISGITLINK(entry->mode)) { const char *name; - if ((name = git_strmap_get(names, entry->path)) == NULL) + if (git_submodule_namemap_get((char **)&name, names, entry->path) != 0) name = entry->path; - if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) { + if (!submodule_get_or_create(&sm, git_tree_owner(head), cache, name)) { submodule_update_from_head_data( sm, entry->mode, &entry->id); git_submodule_free(sm); @@ -549,11 +584,11 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg /* If have_sm is true, sm is populated, otherwise map an repo are. */ typedef struct { git_config *mods; - git_strmap *map; + git_submodule_cache *cache; git_repository *repo; } lfc_data; -int git_submodule__map(git_repository *repo, git_strmap *map) +int git_submodule__map(git_submodule_cache *cache, git_repository *repo) { int error = 0; git_index *idx = NULL; @@ -563,8 +598,8 @@ int git_submodule__map(git_repository *repo, git_strmap *map) git_config *mods = NULL; bool has_workdir; + GIT_ASSERT_ARG(cache); GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(map); /* get sources that we will need to check */ if (git_repository_index(&idx, repo) < 0) @@ -581,7 +616,7 @@ int git_submodule__map(git_repository *repo, git_strmap *map) /* add submodule information from .gitmodules */ if (has_workdir) { lfc_data data = { 0 }; - data.map = map; + data.cache = cache; data.repo = repo; if ((error = gitmodules_snapshot(&mods, repo)) < 0) { @@ -597,19 +632,22 @@ int git_submodule__map(git_repository *repo, git_strmap *map) } /* add back submodule information from index */ if (mods && idx) { - if ((error = submodules_from_index(map, idx, mods)) < 0) + if ((error = submodules_from_index(cache, idx, mods)) < 0) goto cleanup; } /* add submodule information from HEAD */ if (mods && head) { - if ((error = submodules_from_head(map, head, mods)) < 0) + if ((error = submodules_from_head(cache, head, mods)) < 0) goto cleanup; } /* shallow scan submodules in work tree as needed */ if (has_workdir) { - git_strmap_foreach_value(map, sm, { - submodule_load_from_wd_lite(sm); - }); + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; + + while (git_submodule_cache_iterate(&iter, NULL, &sm, cache) == 0) { + if ((error = submodule_load_from_wd_lite(sm)) < 0) + goto cleanup; + } } cleanup: @@ -627,8 +665,9 @@ int git_submodule_foreach( void *payload) { git_vector snapshot = GIT_VECTOR_INIT; - git_strmap *submodules; + git_submodule_cache *submodules; git_submodule *sm; + git_hashmap_iter_t iter; int error; size_t i; @@ -637,20 +676,22 @@ int git_submodule_foreach( return -1; } - if ((error = git_strmap_new(&submodules)) < 0) - return error; + if ((submodules = git__calloc(1, sizeof(git_submodule_cache))) == NULL) + return -1; - if ((error = git_submodule__map(repo, submodules)) < 0) + if ((error = git_submodule__map(submodules, repo)) < 0) goto done; - if (!(error = git_vector_init( - &snapshot, git_strmap_size(submodules), submodule_cmp))) { - - git_strmap_foreach_value(submodules, sm, { + if (!(error = git_vector_init(&snapshot, + git_submodule_cache_size(submodules), + submodule_cmp))) { + for (iter = GIT_HASHMAP_ITER_INIT; + git_submodule_cache_iterate(&iter, NULL, &sm, submodules) == 0; ) { if ((error = git_vector_insert(&snapshot, sm)) < 0) break; + GIT_REFCOUNT_INC(sm); - }); + } } if (error < 0) @@ -670,10 +711,12 @@ int git_submodule_foreach( git_submodule_free(sm); git_vector_dispose(&snapshot); - git_strmap_foreach_value(submodules, sm, { + for (iter = GIT_HASHMAP_ITER_INIT; + git_submodule_cache_iterate(&iter, NULL, &sm, submodules) == 0; ) git_submodule_free(sm); - }); - git_strmap_free(submodules); + + git_submodule_cache_dispose(submodules); + git__free(submodules); return error; } @@ -2049,7 +2092,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) { lfc_data *data = payload; const char *namestart, *property; - git_strmap *map = data->map; + git_submodule_cache *cache = data->cache; git_str name = GIT_STR_INIT; git_submodule *sm; int error, isvalid; @@ -2080,7 +2123,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) * a new submodule, load the config and insert it. If it's * already inserted, we've already loaded it, so we skip. */ - if (git_strmap_exists(map, name.ptr)) { + if (git_submodule_cache_contains(cache, name.ptr)) { error = 0; goto done; } @@ -2093,7 +2136,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) goto done; } - if ((error = git_strmap_set(map, sm->name, sm)) < 0) + if ((error = git_submodule_cache_put(cache, sm->name, sm)) < 0) goto done; error = 0; diff --git a/src/libgit2/submodule.h b/src/libgit2/submodule.h index 11c9996aa6a..2690d8dd9fe 100644 --- a/src/libgit2/submodule.h +++ b/src/libgit2/submodule.h @@ -12,7 +12,7 @@ #include "git2/submodule.h" #include "git2/repository.h" #include "futils.h" -#include "strmap.h" +#include "hashmap.h" /* Notes: * @@ -117,15 +117,17 @@ enum { #define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \ ((S) & ~(0xFFFFFFFFu << 20)) +GIT_HASHMAP_STR_STRUCT(git_submodule_cache, git_submodule *); + /* Initialize an external submodule cache for the provided repo. */ -extern int git_submodule_cache_init(git_strmap **out, git_repository *repo); +extern int git_submodule_cache_init(git_submodule_cache **out, git_repository *repo); /* Release the resources of the submodule cache. */ -extern int git_submodule_cache_free(git_strmap *cache); +extern int git_submodule_cache_free(git_submodule_cache *cache); /* Submodule lookup with an explicit cache */ extern int git_submodule__lookup_with_cache( - git_submodule **out, git_repository *repo, const char *path, git_strmap *cache); + git_submodule **out, git_repository *repo, const char *path, git_submodule_cache *cache); /* Internal status fn returns status and optionally the various OIDs */ extern int git_submodule__status( @@ -146,10 +148,6 @@ extern int git_submodule_parse_ignore( extern int git_submodule_parse_update( git_submodule_update_t *out, const char *value); -extern int git_submodule__map( - git_repository *repo, - git_strmap *map); - /** * Check whether a submodule's name is valid. * From e39a4f79dddd0b6920ffb8c2771026895ca57ac3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 23:40:48 +0100 Subject: [PATCH 608/816] mwindow: use hashmaps --- src/libgit2/mwindow.c | 79 ++++++++++++++++------------------ src/libgit2/mwindow.h | 4 ++ tests/libgit2/pack/filelimit.c | 6 +-- tests/libgit2/pack/sharing.c | 19 +++----- 4 files changed, 50 insertions(+), 58 deletions(-) diff --git a/src/libgit2/mwindow.c b/src/libgit2/mwindow.c index 2c50e068aaf..7e4054df664 100644 --- a/src/libgit2/mwindow.c +++ b/src/libgit2/mwindow.c @@ -11,7 +11,6 @@ #include "futils.h" #include "map.h" #include "runtime.h" -#include "strmap.h" #include "pack.h" #define DEFAULT_WINDOW_SIZE \ @@ -29,33 +28,27 @@ size_t git_mwindow__window_size = DEFAULT_WINDOW_SIZE; size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT; size_t git_mwindow__file_limit = DEFAULT_FILE_LIMIT; -/* Mutex to control access to `git_mwindow__mem_ctl` and `git__pack_cache`. */ -git_mutex git__mwindow_mutex; +/* Mutex to control access to `git_mwindow__mem_ctl` and `git_mwindow__pack_cache`. */ +git_mutex git_mwindow__mutex; -/* Whenever you want to read or modify this, grab `git__mwindow_mutex` */ +/* Whenever you want to read or modify this, grab `git_mwindow__mutex` */ git_mwindow_ctl git_mwindow__mem_ctl; /* Global list of mwindow files, to open packs once across repos */ -git_strmap *git__pack_cache = NULL; +GIT_HASHMAP_STR_FUNCTIONS(git_mwindow_packmap, , struct git_pack_file *); +git_mwindow_packmap git_mwindow__pack_cache; static void git_mwindow_global_shutdown(void) { - git_strmap *tmp = git__pack_cache; - - git_mutex_free(&git__mwindow_mutex); - - git__pack_cache = NULL; - git_strmap_free(tmp); + git_mutex_free(&git_mwindow__mutex); + git_mwindow_packmap_dispose(&git_mwindow__pack_cache); } int git_mwindow_global_init(void) { int error; - GIT_ASSERT(!git__pack_cache); - - if ((error = git_mutex_init(&git__mwindow_mutex)) < 0 || - (error = git_strmap_new(&git__pack_cache)) < 0) + if ((error = git_mutex_init(&git_mwindow__mutex)) < 0) return error; return git_runtime_shutdown_register(git_mwindow_global_shutdown); @@ -73,31 +66,34 @@ int git_mwindow_get_pack( if ((error = git_packfile__name(&packname, path)) < 0) return error; - if (git_mutex_lock(&git__mwindow_mutex) < 0) { + if (git_mutex_lock(&git_mwindow__mutex) < 0) { git_error_set(GIT_ERROR_OS, "failed to lock mwindow mutex"); return -1; } - pack = git_strmap_get(git__pack_cache, packname); + error = git_mwindow_packmap_get(&pack, &git_mwindow__pack_cache, packname); git__free(packname); - if (pack != NULL) { + if (error == 0) { git_atomic32_inc(&pack->refcount); - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); *out = pack; return 0; + } else if (error != GIT_ENOTFOUND) { + return error; } /* If we didn't find it, we need to create it */ if ((error = git_packfile_alloc(&pack, path, oid_type)) < 0) { - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); return error; } git_atomic32_inc(&pack->refcount); - error = git_strmap_set(git__pack_cache, pack->pack_name, pack); - git_mutex_unlock(&git__mwindow_mutex); + error = git_mwindow_packmap_put(&git_mwindow__pack_cache, pack->pack_name, pack); + git_mutex_unlock(&git_mwindow__mutex); + if (error < 0) { git_packfile_free(pack, false); return error; @@ -112,21 +108,18 @@ int git_mwindow_put_pack(struct git_pack_file *pack) int count, error; struct git_pack_file *pack_to_delete = NULL; - if ((error = git_mutex_lock(&git__mwindow_mutex)) < 0) + if ((error = git_mutex_lock(&git_mwindow__mutex)) < 0) return error; - /* put before get would be a corrupted state */ - GIT_ASSERT(git__pack_cache); - /* if we cannot find it, the state is corrupted */ - GIT_ASSERT(git_strmap_exists(git__pack_cache, pack->pack_name)); + GIT_ASSERT(git_mwindow_packmap_contains(&git_mwindow__pack_cache, pack->pack_name)); count = git_atomic32_dec(&pack->refcount); if (count == 0) { - git_strmap_delete(git__pack_cache, pack->pack_name); + git_mwindow_packmap_remove(&git_mwindow__pack_cache, pack->pack_name); pack_to_delete = pack; } - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); git_packfile_free(pack_to_delete, false); return 0; @@ -134,7 +127,7 @@ int git_mwindow_put_pack(struct git_pack_file *pack) /* * Free all the windows in a sequence, typically because we're done - * with the file. Needs to hold the git__mwindow_mutex. + * with the file. Needs to hold the git_mwindow__mutex. */ static int git_mwindow_free_all_locked(git_mwindow_file *mwf) { @@ -176,14 +169,14 @@ int git_mwindow_free_all(git_mwindow_file *mwf) { int error; - if (git_mutex_lock(&git__mwindow_mutex)) { + if (git_mutex_lock(&git_mwindow__mutex)) { git_error_set(GIT_ERROR_THREAD, "unable to lock mwindow mutex"); return -1; } error = git_mwindow_free_all_locked(mwf); - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); return error; } @@ -405,7 +398,7 @@ unsigned char *git_mwindow_open( git_mwindow_ctl *ctl = &git_mwindow__mem_ctl; git_mwindow *w = *cursor; - if (git_mutex_lock(&git__mwindow_mutex)) { + if (git_mutex_lock(&git_mwindow__mutex)) { git_error_set(GIT_ERROR_THREAD, "unable to lock mwindow mutex"); return NULL; } @@ -427,7 +420,7 @@ unsigned char *git_mwindow_open( if (!w) { w = new_window_locked(mwf->fd, mwf->size, offset); if (w == NULL) { - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); return NULL; } w->next = mwf->windows; @@ -447,7 +440,7 @@ unsigned char *git_mwindow_open( if (left) *left = (unsigned int)(w->window_map.len - offset); - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); return (unsigned char *) w->window_map.data + offset; } @@ -459,14 +452,14 @@ int git_mwindow_file_register(git_mwindow_file *mwf) size_t i; git_mwindow_file *closed_file = NULL; - if (git_mutex_lock(&git__mwindow_mutex)) { + if (git_mutex_lock(&git_mwindow__mutex)) { git_error_set(GIT_ERROR_THREAD, "unable to lock mwindow mutex"); return -1; } if (ctl->windowfiles.length == 0 && (error = git_vector_init(&ctl->windowfiles, 8, NULL)) < 0) { - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); goto cleanup; } @@ -486,7 +479,7 @@ int git_mwindow_file_register(git_mwindow_file *mwf) } error = git_vector_insert(&ctl->windowfiles, mwf); - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); if (error < 0) goto cleanup; @@ -515,30 +508,30 @@ void git_mwindow_file_deregister(git_mwindow_file *mwf) git_mwindow_file *cur; size_t i; - if (git_mutex_lock(&git__mwindow_mutex)) + if (git_mutex_lock(&git_mwindow__mutex)) return; git_vector_foreach(&ctl->windowfiles, i, cur) { if (cur == mwf) { git_vector_remove(&ctl->windowfiles, i); - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); return; } } - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); } void git_mwindow_close(git_mwindow **window) { git_mwindow *w = *window; if (w) { - if (git_mutex_lock(&git__mwindow_mutex)) { + if (git_mutex_lock(&git_mwindow__mutex)) { git_error_set(GIT_ERROR_THREAD, "unable to lock mwindow mutex"); return; } w->inuse_cnt--; - git_mutex_unlock(&git__mwindow_mutex); + git_mutex_unlock(&git_mwindow__mutex); *window = NULL; } } diff --git a/src/libgit2/mwindow.h b/src/libgit2/mwindow.h index 8e6df2613b7..43352c4196b 100644 --- a/src/libgit2/mwindow.h +++ b/src/libgit2/mwindow.h @@ -12,6 +12,10 @@ #include "map.h" #include "vector.h" +#include "hashmap_str.h" + +GIT_HASHMAP_STR_STRUCT(git_mwindow_packmap, struct git_pack_file *); +GIT_HASHMAP_STR_PROTOTYPES(git_mwindow_packmap, struct git_pack_file *); typedef struct git_mwindow { struct git_mwindow *next; diff --git a/tests/libgit2/pack/filelimit.c b/tests/libgit2/pack/filelimit.c index fa08485fb92..148c8012c5c 100644 --- a/tests/libgit2/pack/filelimit.c +++ b/tests/libgit2/pack/filelimit.c @@ -8,7 +8,7 @@ static size_t expected_open_mwindow_files = 0; static size_t original_mwindow_file_limit = 0; -extern git_mutex git__mwindow_mutex; +extern git_mutex git_mwindow__mutex; extern git_mwindow_ctl git_mwindow__mem_ctl; void test_pack_filelimit__initialize_tiny(void) @@ -120,13 +120,13 @@ void test_pack_filelimit__open_repo_with_multiple_packfiles(void) ++i; cl_assert_equal_i(commit_count, i); - cl_git_pass(git_mutex_lock(&git__mwindow_mutex)); + cl_git_pass(git_mutex_lock(&git_mwindow__mutex)); /* * Adding an assert while holding a lock will cause the whole process to * deadlock. Copy the value and do the assert after releasing the lock. */ open_windows = ctl->open_windows; - cl_git_pass(git_mutex_unlock(&git__mwindow_mutex)); + cl_git_pass(git_mutex_unlock(&git_mwindow__mutex)); cl_assert_equal_i(expected_open_mwindow_files, open_windows); diff --git a/tests/libgit2/pack/sharing.c b/tests/libgit2/pack/sharing.c index 2e2042d2bc9..dd7aee8ba1e 100644 --- a/tests/libgit2/pack/sharing.c +++ b/tests/libgit2/pack/sharing.c @@ -1,19 +1,18 @@ #include "clar_libgit2.h" #include -#include "strmap.h" #include "mwindow.h" #include "pack.h" +#include "hashmap.h" -extern git_strmap *git__pack_cache; +extern git_mwindow_packmap git_mwindow__pack_cache; void test_pack_sharing__open_two_repos(void) { git_repository *repo1, *repo2; git_object *obj1, *obj2; git_oid id; - size_t pos; - void *data; - int error; + struct git_pack_file *pack; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; cl_git_pass(git_repository_open(&repo1, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_open(&repo2, cl_fixture("testrepo.git"))); @@ -23,14 +22,10 @@ void test_pack_sharing__open_two_repos(void) cl_git_pass(git_object_lookup(&obj1, repo1, &id, GIT_OBJECT_ANY)); cl_git_pass(git_object_lookup(&obj2, repo2, &id, GIT_OBJECT_ANY)); - pos = 0; - while ((error = git_strmap_iterate(&data, git__pack_cache, &pos, NULL)) == 0) { - struct git_pack_file *pack = (struct git_pack_file *) data; - + while (git_mwindow_packmap_iterate(&iter, NULL, &pack, &git_mwindow__pack_cache) == 0) cl_assert_equal_i(2, pack->refcount.val); - } - cl_assert_equal_i(3, git_strmap_size(git__pack_cache)); + cl_assert_equal_i(3, git_mwindow_packmap_size(&git_mwindow__pack_cache)); git_object_free(obj1); git_object_free(obj2); @@ -38,5 +33,5 @@ void test_pack_sharing__open_two_repos(void) git_repository_free(repo2); /* we don't want to keep the packs open after the repos go away */ - cl_assert_equal_i(0, git_strmap_size(git__pack_cache)); + cl_assert_equal_i(0, git_mwindow_packmap_size(&git_mwindow__pack_cache)); } From 58c15588e1dfb7ca2148bf4fef9b40ee4bbb22f6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 23:42:34 +0100 Subject: [PATCH 609/816] transaction: use hashmap --- src/libgit2/transaction.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/libgit2/transaction.c b/src/libgit2/transaction.c index 963416196b4..1965498c0da 100644 --- a/src/libgit2/transaction.c +++ b/src/libgit2/transaction.c @@ -8,7 +8,6 @@ #include "transaction.h" #include "repository.h" -#include "strmap.h" #include "refdb.h" #include "pool.h" #include "reflog.h" @@ -44,6 +43,8 @@ typedef struct { remove :1; } transaction_node; +GIT_HASHMAP_STR_SETUP(git_transaction_nodemap, transaction_node *); + struct git_transaction { transaction_t type; git_repository *repo; @@ -51,7 +52,7 @@ struct git_transaction { git_config *cfg; void *cfg_data; - git_strmap *locks; + git_transaction_nodemap locks; git_pool pool; }; @@ -94,11 +95,6 @@ int git_transaction_new(git_transaction **out, git_repository *repo) goto on_error; } - if ((error = git_strmap_new(&tx->locks)) < 0) { - error = -1; - goto on_error; - } - if ((error = git_repository_refdb(&tx->db, repo)) < 0) goto on_error; @@ -130,7 +126,7 @@ int git_transaction_lock_ref(git_transaction *tx, const char *refname) if ((error = git_refdb_lock(&node->payload, tx->db, refname)) < 0) return error; - if ((error = git_strmap_set(tx->locks, node->name, node)) < 0) + if ((error = git_transaction_nodemap_put(&tx->locks, node->name, node)) < 0) goto cleanup; return 0; @@ -144,8 +140,11 @@ int git_transaction_lock_ref(git_transaction *tx, const char *refname) static int find_locked(transaction_node **out, git_transaction *tx, const char *refname) { transaction_node *node; + int error; + + error = git_transaction_nodemap_get(&node, &tx->locks, refname); - if ((node = git_strmap_get(tx->locks, refname)) == NULL) { + if (error != 0) { git_error_set(GIT_ERROR_REFERENCE, "the specified reference is not locked"); return GIT_ENOTFOUND; } @@ -334,6 +333,7 @@ static int update_target(git_refdb *db, transaction_node *node) int git_transaction_commit(git_transaction *tx) { transaction_node *node; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; int error = 0; GIT_ASSERT_ARG(tx); @@ -346,7 +346,7 @@ int git_transaction_commit(git_transaction *tx) return error; } - git_strmap_foreach_value(tx->locks, node, { + while (git_transaction_nodemap_iterate(&iter, NULL, &node, &tx->locks) == 0) { if (node->reflog) { if ((error = tx->db->backend->reflog_write(tx->db->backend, node->reflog)) < 0) return error; @@ -362,7 +362,7 @@ int git_transaction_commit(git_transaction *tx) if ((error = update_target(tx->db, node)) < 0) return error; } - }); + } return 0; } @@ -371,6 +371,7 @@ void git_transaction_free(git_transaction *tx) { transaction_node *node; git_pool pool; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; if (!tx) return; @@ -384,15 +385,15 @@ void git_transaction_free(git_transaction *tx) } /* start by unlocking the ones we've left hanging, if any */ - git_strmap_foreach_value(tx->locks, node, { + while (git_transaction_nodemap_iterate(&iter, NULL, &node, &tx->locks) == 0) { if (node->committed) continue; git_refdb_unlock(tx->db, node->payload, false, false, NULL, NULL, NULL); - }); + } git_refdb_free(tx->db); - git_strmap_free(tx->locks); + git_transaction_nodemap_dispose(&tx->locks); /* tx is inside the pool, so we need to extract the data */ memcpy(&pool, &tx->pool, sizeof(git_pool)); From 74c42335f7f3df8920deb28c6f77b8382d7757fa Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Sep 2024 23:50:33 +0100 Subject: [PATCH 610/816] tree: use hashmap --- src/libgit2/tree.c | 54 ++++++++++++++++++++++++++-------------------- src/libgit2/tree.h | 5 +++-- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/libgit2/tree.c b/src/libgit2/tree.c index 3e8d4fa3829..ad9d8af28f5 100644 --- a/src/libgit2/tree.c +++ b/src/libgit2/tree.c @@ -21,6 +21,8 @@ #define TREE_ENTRY_CHECK_NAMELEN(n) \ if (n > UINT16_MAX) { git_error_set(GIT_ERROR_INVALID, "tree entry path too long"); } +GIT_HASHMAP_STR_FUNCTIONS(git_treebuilder_entrymap, GIT_HASHMAP_INLINE, git_tree_entry *); + static bool valid_filemode(const int filemode) { return (filemode == GIT_FILEMODE_TREE @@ -347,7 +349,7 @@ size_t git_treebuilder_entrycount(git_treebuilder *bld) { GIT_ASSERT_ARG_WITH_RETVAL(bld, 0); - return git_strmap_size(bld->map); + return git_treebuilder_entrymap_size(&bld->map); } GIT_INLINE(void) set_error(const char *str, const char *path) @@ -512,10 +514,12 @@ static int git_treebuilder__write_with_buffer( git_tree_entry *entry; git_vector entries = GIT_VECTOR_INIT; size_t oid_size = git_oid_size(bld->repo->oid_type); + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; git_str_clear(buf); - entrycount = git_strmap_size(bld->map); + entrycount = git_treebuilder_entrymap_size(&bld->map); + if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0) goto out; @@ -523,10 +527,10 @@ static int git_treebuilder__write_with_buffer( (error = git_str_grow(buf, entrycount * 72)) < 0) goto out; - git_strmap_foreach_value(bld->map, entry, { + while (git_treebuilder_entrymap_iterate(&iter, NULL, &entry, &bld->map) == 0) { if ((error = git_vector_insert(&entries, entry)) < 0) goto out; - }); + } git_vector_sort(&entries); @@ -570,7 +574,7 @@ static int append_entry( entry->attr = (uint16_t)filemode; - if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { + if ((error = git_treebuilder_entrymap_put(&bld->map, entry->filename, entry)) < 0) { git_tree_entry_free(entry); git_error_set(GIT_ERROR_TREE, "failed to append entry %s to the tree builder", filename); return -1; @@ -753,11 +757,6 @@ int git_treebuilder_new( bld->repo = repo; - if (git_strmap_new(&bld->map) < 0) { - git__free(bld); - return -1; - } - if (source != NULL) { git_tree_entry *entry_src; @@ -796,13 +795,13 @@ int git_treebuilder_insert( if ((error = check_entry(bld->repo, filename, id, filemode)) < 0) return error; - if ((entry = git_strmap_get(bld->map, filename)) != NULL) { + if (git_treebuilder_entrymap_get(&entry, &bld->map, filename) == 0) { git_oid_cpy(&entry->oid, id); } else { entry = alloc_entry(filename, strlen(filename), id); GIT_ERROR_CHECK_ALLOC(entry); - if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { + if (git_treebuilder_entrymap_put(&bld->map, entry->filename, entry) < 0) { git_tree_entry_free(entry); git_error_set(GIT_ERROR_TREE, "failed to insert %s", filename); return -1; @@ -819,10 +818,15 @@ int git_treebuilder_insert( static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename) { + git_tree_entry *entry; + GIT_ASSERT_ARG_WITH_RETVAL(bld, NULL); GIT_ASSERT_ARG_WITH_RETVAL(filename, NULL); - return git_strmap_get(bld->map, filename); + if (git_treebuilder_entrymap_get(&entry, &bld->map, filename) != 0) + return NULL; + + return entry; } const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *filename) @@ -837,7 +841,7 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename) if (entry == NULL) return tree_error("failed to remove entry: file isn't in the tree", filename); - git_strmap_delete(bld->map, filename); + git_treebuilder_entrymap_remove(&bld->map, filename); git_tree_entry_free(entry); return 0; @@ -858,16 +862,17 @@ int git_treebuilder_filter( { const char *filename; git_tree_entry *entry; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; GIT_ASSERT_ARG(bld); GIT_ASSERT_ARG(filter); - git_strmap_foreach(bld->map, filename, entry, { - if (filter(entry, payload)) { - git_strmap_delete(bld->map, filename); - git_tree_entry_free(entry); - } - }); + while (git_treebuilder_entrymap_iterate(&iter, &filename, &entry, &bld->map) == 0) { + if (filter(entry, payload)) { + git_treebuilder_entrymap_remove(&bld->map, filename); + git_tree_entry_free(entry); + } + } return 0; } @@ -875,11 +880,14 @@ int git_treebuilder_filter( int git_treebuilder_clear(git_treebuilder *bld) { git_tree_entry *e; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; GIT_ASSERT_ARG(bld); - git_strmap_foreach_value(bld->map, e, git_tree_entry_free(e)); - git_strmap_clear(bld->map); + while (git_treebuilder_entrymap_iterate(&iter, NULL, &e, &bld->map) == 0) + git_tree_entry_free(e); + + git_treebuilder_entrymap_clear(&bld->map); return 0; } @@ -891,7 +899,7 @@ void git_treebuilder_free(git_treebuilder *bld) git_str_dispose(&bld->write_cache); git_treebuilder_clear(bld); - git_strmap_free(bld->map); + git_treebuilder_entrymap_dispose(&bld->map); git__free(bld); } diff --git a/src/libgit2/tree.h b/src/libgit2/tree.h index 5088450ab9b..8deec60408e 100644 --- a/src/libgit2/tree.h +++ b/src/libgit2/tree.h @@ -13,7 +13,6 @@ #include "repository.h" #include "odb.h" #include "vector.h" -#include "strmap.h" #include "pool.h" struct git_tree_entry { @@ -29,9 +28,11 @@ struct git_tree { git_array_t(git_tree_entry) entries; }; +GIT_HASHMAP_STR_STRUCT(git_treebuilder_entrymap, git_tree_entry *); + struct git_treebuilder { git_repository *repo; - git_strmap *map; + git_treebuilder_entrymap map; git_str write_cache; }; From c1ecf566fd947f79aa11cc21fe578b0e764f749d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 28 Sep 2024 23:03:00 +0100 Subject: [PATCH 611/816] hashmap: update index to use new hashmap --- src/libgit2/idxmap.c | 157 ----------------------------------- src/libgit2/idxmap.h | 177 ---------------------------------------- src/libgit2/index.c | 102 ++++++++--------------- src/libgit2/index.h | 4 +- src/libgit2/index_map.c | 95 +++++++++++++++++++++ src/libgit2/index_map.h | 28 +++++++ 6 files changed, 158 insertions(+), 405 deletions(-) delete mode 100644 src/libgit2/idxmap.c delete mode 100644 src/libgit2/idxmap.h create mode 100644 src/libgit2/index_map.c create mode 100644 src/libgit2/index_map.h diff --git a/src/libgit2/idxmap.c b/src/libgit2/idxmap.c deleted file mode 100644 index bc23608f2df..00000000000 --- a/src/libgit2/idxmap.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "idxmap.h" - -#define kmalloc git__malloc -#define kcalloc git__calloc -#define krealloc git__realloc -#define kreallocarray git__reallocarray -#define kfree git__free -#include "khash.h" - -__KHASH_TYPE(idx, const git_index_entry *, git_index_entry *) -__KHASH_TYPE(idxicase, const git_index_entry *, git_index_entry *) - -/* This is __ac_X31_hash_string but with tolower and it takes the entry's stage into account */ -static kh_inline khint_t idxentry_hash(const git_index_entry *e) -{ - const char *s = e->path; - khint_t h = (khint_t)git__tolower(*s); - if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)git__tolower(*s); - return h + GIT_INDEX_ENTRY_STAGE(e); -} - -#define idxentry_equal(a, b) (GIT_INDEX_ENTRY_STAGE(a) == GIT_INDEX_ENTRY_STAGE(b) && strcmp(a->path, b->path) == 0) -#define idxentry_icase_equal(a, b) (GIT_INDEX_ENTRY_STAGE(a) == GIT_INDEX_ENTRY_STAGE(b) && strcasecmp(a->path, b->path) == 0) - -__KHASH_IMPL(idx, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_equal) -__KHASH_IMPL(idxicase, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_icase_equal) - -int git_idxmap_new(git_idxmap **out) -{ - *out = kh_init(idx); - GIT_ERROR_CHECK_ALLOC(*out); - - return 0; -} - -int git_idxmap_icase_new(git_idxmap_icase **out) -{ - *out = kh_init(idxicase); - GIT_ERROR_CHECK_ALLOC(*out); - - return 0; -} - -void git_idxmap_free(git_idxmap *map) -{ - kh_destroy(idx, map); -} - -void git_idxmap_icase_free(git_idxmap_icase *map) -{ - kh_destroy(idxicase, map); -} - -void git_idxmap_clear(git_idxmap *map) -{ - kh_clear(idx, map); -} - -void git_idxmap_icase_clear(git_idxmap_icase *map) -{ - kh_clear(idxicase, map); -} - -int git_idxmap_resize(git_idxmap *map, size_t size) -{ - if (!git__is_uint32(size) || - kh_resize(idx, map, (khiter_t)size) < 0) { - git_error_set_oom(); - return -1; - } - return 0; -} - -int git_idxmap_icase_resize(git_idxmap_icase *map, size_t size) -{ - if (!git__is_uint32(size) || - kh_resize(idxicase, map, (khiter_t)size) < 0) { - git_error_set_oom(); - return -1; - } - return 0; -} - -void *git_idxmap_get(git_idxmap *map, const git_index_entry *key) -{ - size_t idx = kh_get(idx, map, key); - if (idx == kh_end(map) || !kh_exist(map, idx)) - return NULL; - return kh_val(map, idx); -} - -int git_idxmap_set(git_idxmap *map, const git_index_entry *key, void *value) -{ - size_t idx; - int rval; - - idx = kh_put(idx, map, key, &rval); - if (rval < 0) - return -1; - - if (rval == 0) - kh_key(map, idx) = key; - - kh_val(map, idx) = value; - - return 0; -} - -int git_idxmap_icase_set(git_idxmap_icase *map, const git_index_entry *key, void *value) -{ - size_t idx; - int rval; - - idx = kh_put(idxicase, map, key, &rval); - if (rval < 0) - return -1; - - if (rval == 0) - kh_key(map, idx) = key; - - kh_val(map, idx) = value; - - return 0; -} - -void *git_idxmap_icase_get(git_idxmap_icase *map, const git_index_entry *key) -{ - size_t idx = kh_get(idxicase, map, key); - if (idx == kh_end(map) || !kh_exist(map, idx)) - return NULL; - return kh_val(map, idx); -} - -int git_idxmap_delete(git_idxmap *map, const git_index_entry *key) -{ - khiter_t idx = kh_get(idx, map, key); - if (idx == kh_end(map)) - return GIT_ENOTFOUND; - kh_del(idx, map, idx); - return 0; -} - -int git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key) -{ - khiter_t idx = kh_get(idxicase, map, key); - if (idx == kh_end(map)) - return GIT_ENOTFOUND; - kh_del(idxicase, map, idx); - return 0; -} diff --git a/src/libgit2/idxmap.h b/src/libgit2/idxmap.h deleted file mode 100644 index 76170ef328a..00000000000 --- a/src/libgit2/idxmap.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_idxmap_h__ -#define INCLUDE_idxmap_h__ - -#include "common.h" - -#include "git2/index.h" - -/** A map with `git_index_entry`s as key. */ -typedef struct kh_idx_s git_idxmap; -/** A map with case-insensitive `git_index_entry`s as key */ -typedef struct kh_idxicase_s git_idxmap_icase; - -/** - * Allocate a new index entry map. - * - * @param out Pointer to the map that shall be allocated. - * @return 0 on success, an error code if allocation has failed. - */ -int git_idxmap_new(git_idxmap **out); - -/** - * Allocate a new case-insensitive index entry map. - * - * @param out Pointer to the map that shall be allocated. - * @return 0 on success, an error code if allocation has failed. - */ -int git_idxmap_icase_new(git_idxmap_icase **out); - -/** - * Free memory associated with the map. - * - * Note that this function will _not_ free values added to this - * map. - * - * @param map Pointer to the map that is to be free'd. May be - * `NULL`. - */ -void git_idxmap_free(git_idxmap *map); - -/** - * Free memory associated with the map. - * - * Note that this function will _not_ free values added to this - * map. - * - * @param map Pointer to the map that is to be free'd. May be - * `NULL`. - */ -void git_idxmap_icase_free(git_idxmap_icase *map); - -/** - * Clear all entries from the map. - * - * This function will remove all entries from the associated map. - * Memory associated with it will not be released, though. - * - * @param map Pointer to the map that shall be cleared. May be - * `NULL`. - */ -void git_idxmap_clear(git_idxmap *map); - -/** - * Clear all entries from the map. - * - * This function will remove all entries from the associated map. - * Memory associated with it will not be released, though. - * - * @param map Pointer to the map that shall be cleared. May be - * `NULL`. - */ -void git_idxmap_icase_clear(git_idxmap_icase *map); - -/** - * Resize the map by allocating more memory. - * - * @param map map that shall be resized - * @param size count of entries that the map shall hold - * @return `0` if the map was successfully resized, a negative - * error code otherwise - */ -int git_idxmap_resize(git_idxmap *map, size_t size); - -/** - * Resize the map by allocating more memory. - * - * @param map map that shall be resized - * @param size count of entries that the map shall hold - * @return `0` if the map was successfully resized, a negative - * error code otherwise - */ -int git_idxmap_icase_resize(git_idxmap_icase *map, size_t size); - -/** - * Return value associated with the given key. - * - * @param map map to search key in - * @param key key to search for; the index entry will be searched - * for by its case-sensitive path - * @return value associated with the given key or NULL if the key was not found - */ -void *git_idxmap_get(git_idxmap *map, const git_index_entry *key); - -/** - * Return value associated with the given key. - * - * @param map map to search key in - * @param key key to search for; the index entry will be searched - * for by its case-insensitive path - * @return value associated with the given key or NULL if the key was not found - */ -void *git_idxmap_icase_get(git_idxmap_icase *map, const git_index_entry *key); - -/** - * Set the entry for key to value. - * - * If the map has no corresponding entry for the given key, a new - * entry will be created with the given value. If an entry exists - * already, its value will be updated to match the given value. - * - * @param map map to create new entry in - * @param key key to set - * @param value value to associate the key with; may be NULL - * @return zero if the key was successfully set, a negative error - * code otherwise - */ -int git_idxmap_set(git_idxmap *map, const git_index_entry *key, void *value); - -/** - * Set the entry for key to value. - * - * If the map has no corresponding entry for the given key, a new - * entry will be created with the given value. If an entry exists - * already, its value will be updated to match the given value. - * - * @param map map to create new entry in - * @param key key to set - * @param value value to associate the key with; may be NULL - * @return zero if the key was successfully set, a negative error - * code otherwise - */ -int git_idxmap_icase_set(git_idxmap_icase *map, const git_index_entry *key, void *value); - -/** - * Delete an entry from the map. - * - * Delete the given key and its value from the map. If no such - * key exists, this will do nothing. - * - * @param map map to delete key in - * @param key key to delete - * @return `0` if the key has been deleted, GIT_ENOTFOUND if no - * such key was found, a negative code in case of an - * error - */ -int git_idxmap_delete(git_idxmap *map, const git_index_entry *key); - -/** - * Delete an entry from the map. - * - * Delete the given key and its value from the map. If no such - * key exists, this will do nothing. - * - * @param map map to delete key in - * @param key key to delete - * @return `0` if the key has been deleted, GIT_ENOTFOUND if no - * such key was found, a negative code in case of an - * error - */ -int git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key); - -#endif diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 632720dc6c3..29d10ef7213 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -17,10 +17,10 @@ #include "pathspec.h" #include "ignore.h" #include "blob.h" -#include "idxmap.h" #include "diff.h" #include "varint.h" #include "path.h" +#include "index_map.h" #include "git2/odb.h" #include "git2/oid.h" @@ -133,30 +133,6 @@ static int write_index(unsigned char checksum[GIT_HASH_MAX_SIZE], size_t *checks static void index_entry_free(git_index_entry *entry); static void index_entry_reuc_free(git_index_reuc_entry *reuc); -GIT_INLINE(int) index_map_set(git_idxmap *map, git_index_entry *e, bool ignore_case) -{ - if (ignore_case) - return git_idxmap_icase_set((git_idxmap_icase *) map, e, e); - else - return git_idxmap_set(map, e, e); -} - -GIT_INLINE(int) index_map_delete(git_idxmap *map, git_index_entry *e, bool ignore_case) -{ - if (ignore_case) - return git_idxmap_icase_delete((git_idxmap_icase *) map, e); - else - return git_idxmap_delete(map, e); -} - -GIT_INLINE(int) index_map_resize(git_idxmap *map, size_t count, bool ignore_case) -{ - if (ignore_case) - return git_idxmap_icase_resize((git_idxmap_icase *) map, count); - else - return git_idxmap_resize(map, count); -} - int git_index_entry_srch(const void *key, const void *array_member) { const struct entry_srch_key *srch_key = key; @@ -388,6 +364,7 @@ GIT_INLINE(int) index_find( void git_index__set_ignore_case(git_index *index, bool ignore_case) { index->ignore_case = ignore_case; + index->entries_map.ignore_case = ignore_case; if (ignore_case) { index->entries_cmp_path = git__strcasecmp_cb; @@ -438,7 +415,6 @@ int git_index__open( } if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 || - git_idxmap_new(&index->entries_map) < 0 || git_vector_init(&index->names, 8, conflict_name_cmp) < 0 || git_vector_init(&index->reuc, 8, reuc_cmp) < 0 || git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0) @@ -502,7 +478,7 @@ static void index_free(git_index *index) return; git_index_clear(index); - git_idxmap_free(index->entries_map); + git_index_entrymap_dispose(&index->entries_map); git_vector_dispose(&index->entries); git_vector_dispose(&index->names); git_vector_dispose(&index->reuc); @@ -547,7 +523,7 @@ static int index_remove_entry(git_index *index, size_t pos) if (entry != NULL) { git_tree_cache_invalidate_path(index->tree, entry->path); - index_map_delete(index->entries_map, entry, index->ignore_case); + git_index_entrymap_remove(&index->entries_map, entry); } error = git_vector_remove(&index->entries, pos); @@ -575,7 +551,8 @@ int git_index_clear(git_index *index) index->tree = NULL; git_pool_clear(&index->tree_pool); - git_idxmap_clear(index->entries_map); + git_index_entrymap_clear(&index->entries_map); + while (!error && index->entries.length > 0) error = index_remove_entry(index, index->entries.length - 1); @@ -906,14 +883,9 @@ const git_index_entry *git_index_get_bypath( key.path = path; GIT_INDEX_ENTRY_STAGE_SET(&key, stage); - if (index->ignore_case) - value = git_idxmap_icase_get((git_idxmap_icase *) index->entries_map, &key); - else - value = git_idxmap_get(index->entries_map, &key); - - if (!value) { - git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path); - return NULL; + if (git_index_entrymap_get(&value, &index->entries_map, &key) != 0) { + git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path); + return NULL; } return value; @@ -1455,7 +1427,7 @@ static int index_insert( * check for dups, this is actually cheaper in the long run.) */ if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0 || - (error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) + (error = git_index_entrymap_put(&index->entries_map, entry)) < 0) goto out; } @@ -1684,8 +1656,7 @@ int git_index__fill(git_index *index, const git_vector *source_entries) return 0; if (git_vector_size_hint(&index->entries, source_entries->length) < 0 || - index_map_resize(index->entries_map, (size_t)(source_entries->length * 1.3), - index->ignore_case) < 0) + git_index_entrymap_resize(&index->entries_map, (size_t)(source_entries->length * 1.3)) < 0) return -1; git_vector_foreach(source_entries, i, source_entry) { @@ -1698,10 +1669,8 @@ int git_index__fill(git_index *index, const git_vector *source_entries) entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE; entry->mode = git_index__create_mode(entry->mode); - if ((error = git_vector_insert(&index->entries, entry)) < 0) - break; - - if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) + if ((error = git_vector_insert(&index->entries, entry)) < 0 || + (error = git_index_entrymap_put(&index->entries_map, entry)) < 0) break; index->dirty = 1; @@ -1744,7 +1713,7 @@ int git_index_remove(git_index *index, const char *path, int stage) remove_key.path = path; GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage); - index_map_delete(index->entries_map, &remove_key, index->ignore_case); + git_index_entrymap_remove(&index->entries_map, &remove_key); if (index_find(&position, index, path, 0, stage) < 0) { git_error_set( @@ -2797,7 +2766,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) GIT_ASSERT(!index->entries.length); - if ((error = index_map_resize(index->entries_map, header.entry_count, index->ignore_case)) < 0) + if ((error = git_index_entrymap_resize(&index->entries_map, header.entry_count)) < 0) return error; /* Parse all the entries */ @@ -2815,7 +2784,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) goto done; } - if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) { + if ((error = git_index_entrymap_put(&index->entries_map, entry)) < 0) { index_entry_free(entry); goto done; } @@ -3367,14 +3336,11 @@ int git_index_read_tree(git_index *index, const git_tree *tree) { int error = 0; git_vector entries = GIT_VECTOR_INIT; - git_idxmap *entries_map; + git_index_entrymap entries_map = GIT_INDEX_ENTRYMAP_INIT; read_tree_data data; size_t i; git_index_entry *e; - if (git_idxmap_new(&entries_map) < 0) - return -1; - git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */ data.index = index; @@ -3390,11 +3356,11 @@ int git_index_read_tree(git_index *index, const git_tree *tree) if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0) goto cleanup; - if ((error = index_map_resize(entries_map, entries.length, index->ignore_case)) < 0) + if ((error = git_index_entrymap_resize(&entries_map, entries.length)) < 0) goto cleanup; git_vector_foreach(&entries, i, e) { - if ((error = index_map_set(entries_map, e, index->ignore_case)) < 0) { + if ((error = git_index_entrymap_put(&entries_map, e)) < 0) { git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map"); return error; } @@ -3404,18 +3370,18 @@ int git_index_read_tree(git_index *index, const git_tree *tree) git_vector_sort(&entries); - if ((error = git_index_clear(index)) < 0) { - /* well, this isn't good */; - } else { - git_vector_swap(&entries, &index->entries); - entries_map = git_atomic_swap(index->entries_map, entries_map); - } + if ((error = git_index_clear(index)) < 0) + goto cleanup; + + git_vector_swap(&entries, &index->entries); + git_index_entrymap_swap(&entries_map, &index->entries_map); index->dirty = 1; cleanup: git_vector_dispose(&entries); - git_idxmap_free(entries_map); + git_index_entrymap_dispose(&entries_map); + if (error < 0) return error; @@ -3431,7 +3397,7 @@ static int git_index_read_iterator( { git_vector new_entries = GIT_VECTOR_INIT, remove_entries = GIT_VECTOR_INIT; - git_idxmap *new_entries_map = NULL; + git_index_entrymap new_entries_map = GIT_INDEX_ENTRYMAP_INIT; git_iterator *index_iterator = NULL; git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; const git_index_entry *old_entry, *new_entry; @@ -3442,12 +3408,11 @@ static int git_index_read_iterator( GIT_ASSERT((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE)); if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 || - (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 || - (error = git_idxmap_new(&new_entries_map)) < 0) + (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0) goto done; - if (new_length_hint && (error = index_map_resize(new_entries_map, new_length_hint, - index->ignore_case)) < 0) + if (new_length_hint && + (error = git_index_entrymap_resize(&new_entries_map, new_length_hint)) < 0) goto done; opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE | @@ -3512,8 +3477,7 @@ static int git_index_read_iterator( if (add_entry) { if ((error = git_vector_insert(&new_entries, add_entry)) == 0) - error = index_map_set(new_entries_map, add_entry, - index->ignore_case); + error = git_index_entrymap_put(&new_entries_map, add_entry); } if (remove_entry && error >= 0) @@ -3542,7 +3506,7 @@ static int git_index_read_iterator( goto done; git_vector_swap(&new_entries, &index->entries); - new_entries_map = git_atomic_swap(index->entries_map, new_entries_map); + git_index_entrymap_swap(&index->entries_map, &new_entries_map); git_vector_foreach(&remove_entries, i, entry) { if (index->tree) @@ -3557,7 +3521,7 @@ static int git_index_read_iterator( error = 0; done: - git_idxmap_free(new_entries_map); + git_index_entrymap_dispose(&new_entries_map); git_vector_dispose(&new_entries); git_vector_dispose(&remove_entries); git_iterator_free(index_iterator); diff --git a/src/libgit2/index.h b/src/libgit2/index.h index 53c29977df7..601e98f1ce2 100644 --- a/src/libgit2/index.h +++ b/src/libgit2/index.h @@ -12,8 +12,8 @@ #include "futils.h" #include "filebuf.h" #include "vector.h" -#include "idxmap.h" #include "tree-cache.h" +#include "index_map.h" #include "git2/odb.h" #include "git2/index.h" @@ -30,7 +30,7 @@ struct git_index { unsigned char checksum[GIT_HASH_MAX_SIZE]; git_vector entries; - git_idxmap *entries_map; + git_index_entrymap entries_map; git_vector deleted; /* deleted entries if readers > 0 */ git_atomic32 readers; /* number of active iterators */ diff --git a/src/libgit2/index_map.c b/src/libgit2/index_map.c new file mode 100644 index 00000000000..4c50ca7ab63 --- /dev/null +++ b/src/libgit2/index_map.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "hashmap.h" +#include "index_map.h" + +typedef git_index_entrymap git_index_entrymap_default; +typedef git_index_entrymap git_index_entrymap_icase; + +/* This is __ac_X31_hash_string but with tolower and it takes the entry's stage into account */ +GIT_INLINE(uint32_t) git_index_entrymap_hash(const git_index_entry *e) +{ + const char *s = e->path; + uint32_t h = (uint32_t)git__tolower(*s); + if (h) { + for (++s ; *s; ++s) + h = (h << 5) - h + (uint32_t)git__tolower(*s); + } + return h + GIT_INDEX_ENTRY_STAGE(e); +} + +#define git_index_entrymap_equal_default(a, b) (GIT_INDEX_ENTRY_STAGE(a) == GIT_INDEX_ENTRY_STAGE(b) && strcmp(a->path, b->path) == 0) +#define git_index_entrymap_equal_icase(a, b) (GIT_INDEX_ENTRY_STAGE(a) == GIT_INDEX_ENTRY_STAGE(b) && strcasecmp(a->path, b->path) == 0) + +GIT_HASHMAP_FUNCTIONS(git_index_entrymap_default, GIT_HASHMAP_INLINE, git_index_entry *, git_index_entry *, git_index_entrymap_hash, git_index_entrymap_equal_default) +GIT_HASHMAP_FUNCTIONS(git_index_entrymap_icase, GIT_HASHMAP_INLINE, git_index_entry *, git_index_entry *, git_index_entrymap_hash, git_index_entrymap_equal_icase) + +int git_index_entrymap_put(git_index_entrymap *map, git_index_entry *e) +{ + if (map->ignore_case) + return git_index_entrymap_icase_put((git_index_entrymap_icase *)map, e, e); + else + return git_index_entrymap_default_put((git_index_entrymap_default *)map, e, e); +} + +int git_index_entrymap_get(git_index_entry **out, git_index_entrymap *map, git_index_entry *e) +{ + if (map->ignore_case) + return git_index_entrymap_icase_get(out, (git_index_entrymap_icase *)map, e); + else + return git_index_entrymap_default_get(out, (git_index_entrymap_default *)map, e); +} + +int git_index_entrymap_remove(git_index_entrymap *map, git_index_entry *e) +{ + if (map->ignore_case) + return git_index_entrymap_icase_remove((git_index_entrymap_icase *)map, e); + else + return git_index_entrymap_default_remove((git_index_entrymap_default *)map, e); +} + +int git_index_entrymap_resize(git_index_entrymap *map, size_t count) +{ + if (count > UINT32_MAX) { + git_error_set(GIT_ERROR_INDEX, "index map is out of bounds"); + return -1; + } + + if (map->ignore_case) + return git_index_entrymap_icase__resize((git_index_entrymap_icase *)map, (uint32_t)count); + else + return git_index_entrymap_default__resize((git_index_entrymap_default *)map, (uint32_t)count); +} + +void git_index_entrymap_swap(git_index_entrymap *a, git_index_entrymap *b) +{ + git_index_entrymap t; + + if (a != b) { + memcpy(&t, a, sizeof(t)); + memcpy(a, b, sizeof(t)); + memcpy(b, &t, sizeof(t)); + } +} + +void git_index_entrymap_clear(git_index_entrymap *map) +{ + if (map->ignore_case) + git_index_entrymap_icase_clear((git_index_entrymap_icase *)map); + else + git_index_entrymap_default_clear((git_index_entrymap_default *)map); +} + +void git_index_entrymap_dispose(git_index_entrymap *map) +{ + if (map->ignore_case) + git_index_entrymap_icase_dispose((git_index_entrymap_icase *)map); + else + git_index_entrymap_default_dispose((git_index_entrymap_default *)map); +} diff --git a/src/libgit2/index_map.h b/src/libgit2/index_map.h new file mode 100644 index 00000000000..177a3f196c6 --- /dev/null +++ b/src/libgit2/index_map.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_index_map_h__ +#define INCLUDE_index_map_h__ + +#include "common.h" +#include "hashmap.h" + +typedef struct { + unsigned int ignore_case; + GIT_HASHMAP_STRUCT_MEMBERS(git_index_entry *, git_index_entry *) +} git_index_entrymap; + +#define GIT_INDEX_ENTRYMAP_INIT { 0 } + +extern int git_index_entrymap_get(git_index_entry **out, git_index_entrymap *map, git_index_entry *e); +extern int git_index_entrymap_put(git_index_entrymap *map, git_index_entry *e); +extern int git_index_entrymap_remove(git_index_entrymap *map, git_index_entry *e); +extern int git_index_entrymap_resize(git_index_entrymap *map, size_t count); +extern void git_index_entrymap_swap(git_index_entrymap *a, git_index_entrymap *b); +extern void git_index_entrymap_clear(git_index_entrymap *map); +extern void git_index_entrymap_dispose(git_index_entrymap *map); + +#endif From b4be7d0dcdf2e5d02531ac80e05876d26d878638 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 15:34:52 +0100 Subject: [PATCH 612/816] oid: introduce oid hash functions Provide functions for `git_oid` to provide a 32 bit or 64 bit hash value, useful for a hashmap. --- src/libgit2/oid.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h index f25a899a681..d6a681caf58 100644 --- a/src/libgit2/oid.h +++ b/src/libgit2/oid.h @@ -256,6 +256,22 @@ GIT_INLINE(void) git_oid_clear(git_oid *out, git_oid_t type) #endif } +/* A 32 bit representation suitable for a hashmap key */ +GIT_INLINE(uint32_t) git_oid_hash32(const git_oid *oid) +{ + uint32_t hash; + memcpy(&hash, oid->id, sizeof(uint32_t)); + return hash; +} + +/* A 64 bit representation suitable for a hashmap key */ +GIT_INLINE(uint64_t) git_oid_hash64(const git_oid *oid) +{ + uint64_t hash; + memcpy(&hash, oid->id, sizeof(uint64_t)); + return hash; +} + /* SHA256 support */ int git_oid__fromstr(git_oid *out, const char *str, git_oid_t type); From 7fb641b93a09a7c834e220f497212180e266b1ad Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 15:35:17 +0100 Subject: [PATCH 613/816] cache: use a well-typed hashmap for oid mapped cache --- src/libgit2/cache.c | 39 ++++++++++++++++++++++----------------- src/libgit2/cache.h | 16 +++++++--------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/libgit2/cache.c b/src/libgit2/cache.c index 2f68e357cbd..b544fa331b3 100644 --- a/src/libgit2/cache.c +++ b/src/libgit2/cache.c @@ -14,6 +14,9 @@ #include "odb.h" #include "object.h" #include "git2/oid.h" +#include "hashmap.h" + +GIT_HASHMAP_FUNCTIONS(git_cache_oidmap, GIT_HASHMAP_INLINE, const git_oid *, git_cached_obj *, git_oid_hash32, git_oid_equal); bool git_cache__enabled = true; ssize_t git_cache__max_storage = (256 * 1024 * 1024); @@ -45,9 +48,6 @@ int git_cache_init(git_cache *cache) { memset(cache, 0, sizeof(*cache)); - if ((git_oidmap_new(&cache->map)) < 0) - return -1; - if (git_rwlock_init(&cache->lock)) { git_error_set(GIT_ERROR_OS, "failed to initialize cache rwlock"); return -1; @@ -60,15 +60,15 @@ int git_cache_init(git_cache *cache) static void clear_cache(git_cache *cache) { git_cached_obj *evict = NULL; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; if (git_cache_size(cache) == 0) return; - git_oidmap_foreach_value(cache->map, evict, { + while (git_cache_oidmap_iterate(&iter, NULL, &evict, &cache->map) == 0) git_cached_obj_decref(evict); - }); - git_oidmap_clear(cache->map); + git_cache_oidmap_clear(&cache->map); git_atomic_ssize_add(&git_cache__current_storage, -cache->used_memory); cache->used_memory = 0; } @@ -83,10 +83,15 @@ void git_cache_clear(git_cache *cache) git_rwlock_wrunlock(&cache->lock); } +size_t git_cache_size(git_cache *cache) +{ + return git_cache_oidmap_size(&cache->map); +} + void git_cache_dispose(git_cache *cache) { git_cache_clear(cache); - git_oidmap_free(cache->map); + git_cache_oidmap_dispose(&cache->map); git_rwlock_free(&cache->lock); git__memzero(cache, sizeof(*cache)); } @@ -94,8 +99,9 @@ void git_cache_dispose(git_cache *cache) /* Called with lock */ static void cache_evict_entries(git_cache *cache) { - size_t evict_count = git_cache_size(cache) / 2048, i; + size_t evict_count = git_cache_size(cache) / 2048; ssize_t evicted_memory = 0; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; if (evict_count < 8) evict_count = 8; @@ -106,17 +112,16 @@ static void cache_evict_entries(git_cache *cache) return; } - i = 0; while (evict_count > 0) { - git_cached_obj *evict; const git_oid *key; + git_cached_obj *evict; - if (git_oidmap_iterate((void **) &evict, cache->map, &i, &key) == GIT_ITEROVER) + if (git_cache_oidmap_iterate(&iter, &key, &evict, &cache->map) != 0) break; evict_count--; evicted_memory += evict->size; - git_oidmap_delete(cache->map, key); + git_cache_oidmap_remove(&cache->map, key); git_cached_obj_decref(evict); } @@ -132,12 +137,12 @@ static bool cache_should_store(git_object_t object_type, size_t object_size) static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags) { - git_cached_obj *entry; + git_cached_obj *entry = NULL; if (!git_cache__enabled || git_rwlock_rdlock(&cache->lock) < 0) return NULL; - if ((entry = git_oidmap_get(cache->map, oid)) != NULL) { + if (git_cache_oidmap_get(&entry, &cache->map, oid) == 0) { if (flags && entry->flags != flags) { entry = NULL; } else { @@ -172,8 +177,8 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) cache_evict_entries(cache); /* not found */ - if ((stored_entry = git_oidmap_get(cache->map, &entry->oid)) == NULL) { - if (git_oidmap_set(cache->map, &entry->oid, entry) == 0) { + if (git_cache_oidmap_get(&stored_entry, &cache->map, &entry->oid) != 0) { + if (git_cache_oidmap_put(&cache->map, &entry->oid, entry) == 0) { git_cached_obj_incref(entry); cache->used_memory += entry->size; git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size); @@ -187,7 +192,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) entry = stored_entry; } else if (stored_entry->flags == GIT_CACHE_STORE_RAW && entry->flags == GIT_CACHE_STORE_PARSED) { - if (git_oidmap_set(cache->map, &entry->oid, entry) == 0) { + if (git_cache_oidmap_put(&cache->map, &entry->oid, entry) == 0) { git_cached_obj_decref(stored_entry); git_cached_obj_incref(entry); } else { diff --git a/src/libgit2/cache.h b/src/libgit2/cache.h index 42c4fa80d7f..d6bf2851efc 100644 --- a/src/libgit2/cache.h +++ b/src/libgit2/cache.h @@ -14,7 +14,7 @@ #include "git2/odb.h" #include "thread.h" -#include "oidmap.h" +#include "hashmap.h" enum { GIT_CACHE_STORE_ANY = 0, @@ -30,10 +30,12 @@ typedef struct { git_atomic32 refcount; } git_cached_obj; +GIT_HASHMAP_STRUCT(git_cache_oidmap, const git_oid *, git_cached_obj *); + typedef struct { - git_oidmap *map; - git_rwlock lock; - ssize_t used_memory; + git_cache_oidmap map; + git_rwlock lock; + ssize_t used_memory; } git_cache; extern bool git_cache__enabled; @@ -45,6 +47,7 @@ int git_cache_set_max_object_size(git_object_t type, size_t size); int git_cache_init(git_cache *cache); void git_cache_dispose(git_cache *cache); void git_cache_clear(git_cache *cache); +size_t git_cache_size(git_cache *cache); void *git_cache_store_raw(git_cache *cache, git_odb_object *entry); void *git_cache_store_parsed(git_cache *cache, git_object *entry); @@ -53,11 +56,6 @@ git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid); git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid); void *git_cache_get_any(git_cache *cache, const git_oid *oid); -GIT_INLINE(size_t) git_cache_size(git_cache *cache) -{ - return (size_t)git_oidmap_size(cache->map); -} - GIT_INLINE(void) git_cached_obj_incref(void *_obj) { git_cached_obj *obj = _obj; From f9ad579ebc751ac1e1ccb129b42370a051891125 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 15:40:43 +0100 Subject: [PATCH 614/816] commit_graph: use a well-typed oid hashmap --- src/libgit2/commit_graph.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index 47803be4ac6..948a921b327 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -13,7 +13,6 @@ #include "futils.h" #include "hash.h" #include "oidarray.h" -#include "oidmap.h" #include "pack.h" #include "repository.h" #include "revwalk.h" @@ -25,6 +24,7 @@ #define COMMIT_GRAPH_SIGNATURE 0x43475048 /* "CGPH" */ #define COMMIT_GRAPH_VERSION 1 #define COMMIT_GRAPH_OBJECT_ID_VERSION 1 + struct git_commit_graph_header { uint32_t signature; uint8_t version; @@ -839,6 +839,8 @@ enum generation_number_commit_state { GENERATION_NUMBER_COMMIT_STATE_VISITED = 3 }; +GIT_HASHMAP_SETUP(git_commit_graph_oidmap, const git_oid *, struct packed_commit *, git_oid_hash32, git_oid_equal); + static int compute_generation_numbers(git_vector *commits) { git_array_t(size_t) index_stack = GIT_ARRAY_INIT; @@ -846,17 +848,14 @@ static int compute_generation_numbers(git_vector *commits) size_t *parent_idx; enum generation_number_commit_state *commit_states = NULL; struct packed_commit *child_packed_commit; - git_oidmap *packed_commit_map = NULL; + git_commit_graph_oidmap packed_commit_map = GIT_HASHMAP_INIT; int error = 0; /* First populate the parent indices fields */ - error = git_oidmap_new(&packed_commit_map); - if (error < 0) - goto cleanup; git_vector_foreach (commits, i, child_packed_commit) { child_packed_commit->index = i; - error = git_oidmap_set( - packed_commit_map, &child_packed_commit->sha1, child_packed_commit); + error = git_commit_graph_oidmap_put(&packed_commit_map, + &child_packed_commit->sha1, child_packed_commit); if (error < 0) goto cleanup; } @@ -874,8 +873,7 @@ static int compute_generation_numbers(git_vector *commits) goto cleanup; } git_array_foreach (child_packed_commit->parents, parent_i, parent_id) { - parent_packed_commit = git_oidmap_get(packed_commit_map, parent_id); - if (!parent_packed_commit) { + if (git_commit_graph_oidmap_get(&parent_packed_commit, &packed_commit_map, parent_id) != 0) { git_error_set(GIT_ERROR_ODB, "parent commit %s not found in commit graph", git_oid_tostr_s(parent_id)); @@ -975,7 +973,7 @@ static int compute_generation_numbers(git_vector *commits) } cleanup: - git_oidmap_free(packed_commit_map); + git_commit_graph_oidmap_dispose(&packed_commit_map); git__free(commit_states); git_array_clear(index_stack); From 90f17858007aadb05e2cf23f1dea28934bffdee9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 16:28:21 +0100 Subject: [PATCH 615/816] describe: use a typed oid hashmap --- src/libgit2/describe.c | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/libgit2/describe.c b/src/libgit2/describe.c index 7fed8e859a2..5964ff87389 100644 --- a/src/libgit2/describe.c +++ b/src/libgit2/describe.c @@ -14,7 +14,6 @@ #include "buf.h" #include "commit.h" #include "commit_list.h" -#include "oidmap.h" #include "refs.h" #include "repository.h" #include "revwalk.h" @@ -22,6 +21,7 @@ #include "tag.h" #include "vector.h" #include "wildmatch.h" +#include "hashmap.h" /* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */ @@ -32,20 +32,22 @@ struct commit_name { git_oid sha1; char *path; - /* Khash workaround. They original key has to still be reachable */ + /* The original key for the hashmap */ git_oid peeled; }; -static void *oidmap_value_bykey(git_oidmap *map, const git_oid *key) -{ - return git_oidmap_get(map, key); -} +GIT_HASHMAP_SETUP(git_describe_oidmap, const git_oid *, struct commit_name *, git_oid_hash32, git_oid_equal); static struct commit_name *find_commit_name( - git_oidmap *names, + git_describe_oidmap *names, const git_oid *peeled) { - return (struct commit_name *)(oidmap_value_bykey(names, peeled)); + struct commit_name *result; + + if (git_describe_oidmap_get(&result, names, peeled) == 0) + return result; + + return NULL; } static int replace_name( @@ -92,7 +94,7 @@ static int replace_name( static int add_to_known_names( git_repository *repo, - git_oidmap *names, + git_describe_oidmap *names, const char *path, const git_oid *peeled, unsigned int prio, @@ -121,7 +123,7 @@ static int add_to_known_names( e->path = git__strdup(path); git_oid_cpy(&e->peeled, peeled); - if (!found && git_oidmap_set(names, &e->peeled, e) < 0) + if (!found && git_describe_oidmap_put(names, &e->peeled, e) < 0) return -1; } else @@ -174,7 +176,7 @@ struct get_name_data { git_describe_options *opts; git_repository *repo; - git_oidmap *names; + git_describe_oidmap names; git_describe_result *result; }; @@ -240,7 +242,7 @@ static int get_name(const char *refname, void *payload) else prio = 0; - add_to_known_names(data->repo, data->names, + add_to_known_names(data->repo, &data->names, all ? refname + strlen(GIT_REFS_DIR) : refname + strlen(GIT_REFS_TAGS_DIR), &peeled, prio, &sha1); return 0; @@ -451,7 +453,7 @@ static int describe( git_oid_cpy(&data->result->commit_id, git_commit_id(commit)); - n = find_commit_name(data->names, git_commit_id(commit)); + n = find_commit_name(&data->names, git_commit_id(commit)); if (n && (tags || all || n->prio == 2)) { /* * Exact match to an existing ref. @@ -492,7 +494,7 @@ static int describe( git_commit_list_node *c = (git_commit_list_node *)git_pqueue_pop(&list); seen_commits++; - n = find_commit_name(data->names, &c->oid); + n = find_commit_name(&data->names, &c->oid); if (n) { if (!tags && !all && n->prio < 2) { @@ -653,11 +655,12 @@ int git_describe_commit( git_object *committish, git_describe_options *opts) { - struct get_name_data data; + struct get_name_data data = {0}; struct commit_name *name; git_commit *commit; - int error = -1; git_describe_options normalized; + git_hashmap_iter_t iter = GIT_HASHMAP_INIT; + int error = -1; GIT_ASSERT_ARG(result); GIT_ASSERT_ARG(committish); @@ -677,9 +680,6 @@ int git_describe_commit( "git_describe_options"); data.opts = &normalized; - if ((error = git_oidmap_new(&data.names)) < 0) - return error; - /** TODO: contains to be implemented */ if ((error = git_object_peel((git_object **)(&commit), committish, GIT_OBJECT_COMMIT)) < 0) @@ -690,7 +690,7 @@ int git_describe_commit( get_name, &data)) < 0) goto cleanup; - if (git_oidmap_size(data.names) == 0 && !normalized.show_commit_oid_as_fallback) { + if (git_describe_oidmap_size(&data.names) == 0 && !normalized.show_commit_oid_as_fallback) { git_error_set(GIT_ERROR_DESCRIBE, "cannot describe - " "no reference found, cannot describe anything."); error = -1; @@ -703,13 +703,13 @@ int git_describe_commit( cleanup: git_commit_free(commit); - git_oidmap_foreach_value(data.names, name, { + while (git_describe_oidmap_iterate(&iter, NULL, &name, &data.names) == 0) { git_tag_free(name->tag); git__free(name->path); git__free(name); - }); + } - git_oidmap_free(data.names); + git_describe_oidmap_dispose(&data.names); if (error < 0) git_describe_result_free(data.result); From 9a7d920f73d97eab20127e47a280d48d5654c419 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 16:28:35 +0100 Subject: [PATCH 616/816] grafts: use a typed oid hashmap --- src/libgit2/grafts.c | 38 ++++++++++++++++++-------------------- src/libgit2/grafts.h | 1 - 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 1d9373a56f6..9ead540e1e9 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -11,10 +11,13 @@ #include "oid.h" #include "oidarray.h" #include "parse.h" +#include "hashmap.h" + +GIT_HASHMAP_SETUP(git_grafts_oidmap, const git_oid *, git_commit_graft *, git_oid_hash32, git_oid_equal); struct git_grafts { /* Map of `git_commit_graft`s */ - git_oidmap *commits; + git_grafts_oidmap commits; /* Type of object IDs */ git_oid_t oid_type; @@ -33,11 +36,6 @@ int git_grafts_new(git_grafts **out, git_oid_t oid_type) grafts = git__calloc(1, sizeof(*grafts)); GIT_ERROR_CHECK_ALLOC(grafts); - if ((git_oidmap_new(&grafts->commits)) < 0) { - git__free(grafts); - return -1; - } - grafts->oid_type = oid_type; *out = grafts; @@ -88,23 +86,24 @@ void git_grafts_free(git_grafts *grafts) return; git__free(grafts->path); git_grafts_clear(grafts); - git_oidmap_free(grafts->commits); + git_grafts_oidmap_dispose(&grafts->commits); git__free(grafts); } void git_grafts_clear(git_grafts *grafts) { + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; git_commit_graft *graft; if (!grafts) return; - git_oidmap_foreach_value(grafts->commits, graft, { + while (git_grafts_oidmap_iterate(&iter, NULL, &graft, &grafts->commits) == 0) { git__free(graft->parents.ptr); git__free(graft); - }); + } - git_oidmap_clear(grafts->commits); + git_grafts_oidmap_clear(&grafts->commits); } int git_grafts_refresh(git_grafts *grafts) @@ -205,7 +204,7 @@ int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t paren if ((error = git_grafts_remove(grafts, &graft->oid)) < 0 && error != GIT_ENOTFOUND) goto cleanup; - if ((error = git_oidmap_set(grafts->commits, &graft->oid, graft)) < 0) + if ((error = git_grafts_oidmap_put(&grafts->commits, &graft->oid, graft)) < 0) goto cleanup; return 0; @@ -223,10 +222,10 @@ int git_grafts_remove(git_grafts *grafts, const git_oid *oid) GIT_ASSERT_ARG(grafts && oid); - if ((graft = git_oidmap_get(grafts->commits, oid)) == NULL) + if (git_grafts_oidmap_get(&graft, &grafts->commits, oid) != 0) return GIT_ENOTFOUND; - if ((error = git_oidmap_delete(grafts->commits, oid)) < 0) + if ((error = git_grafts_oidmap_remove(&grafts->commits, oid)) < 0) return error; git__free(graft->parents.ptr); @@ -238,23 +237,22 @@ int git_grafts_remove(git_grafts *grafts, const git_oid *oid) int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid) { GIT_ASSERT_ARG(out && grafts && oid); - if ((*out = git_oidmap_get(grafts->commits, oid)) == NULL) - return GIT_ENOTFOUND; - return 0; + return git_grafts_oidmap_get(out, &grafts->commits, oid); } int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts) { + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; git_array_oid_t array = GIT_ARRAY_INIT; const git_oid *oid; - size_t existing, i = 0; + size_t existing; GIT_ASSERT_ARG(out && grafts); - if ((existing = git_oidmap_size(grafts->commits)) > 0) + if ((existing = git_grafts_oidmap_size(&grafts->commits)) > 0) git_array_init_to_size(array, existing); - while (git_oidmap_iterate(NULL, grafts->commits, &i, &oid) == 0) { + while (git_grafts_oidmap_iterate(&iter, &oid, NULL, &grafts->commits) == 0) { git_oid *cpy = git_array_alloc(array); GIT_ERROR_CHECK_ALLOC(cpy); git_oid_cpy(cpy, oid); @@ -268,5 +266,5 @@ int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts) size_t git_grafts_size(git_grafts *grafts) { - return git_oidmap_size(grafts->commits); + return git_grafts_oidmap_size(&grafts->commits); } diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h index 394867fd6cc..ab59f56b07c 100644 --- a/src/libgit2/grafts.h +++ b/src/libgit2/grafts.h @@ -9,7 +9,6 @@ #include "common.h" #include "oidarray.h" -#include "oidmap.h" /** graft commit */ typedef struct { From c7294317ca95343ad61ec7341c014d00124f6a68 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 18:15:48 +0100 Subject: [PATCH 617/816] merge: use type safe oid-keyed hashmaps --- src/libgit2/merge.c | 47 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 8f3fc460216..17cbc16117f 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -32,7 +32,6 @@ #include "commit.h" #include "oidarray.h" #include "merge_driver.h" -#include "oidmap.h" #include "array.h" #include "git2/types.h" @@ -1144,24 +1143,28 @@ typedef struct { size_t first_entry; } deletes_by_oid_queue; -static void deletes_by_oid_free(git_oidmap *map) { +GIT_HASHMAP_SETUP(git_merge_deletes_oidmap, const git_oid *, deletes_by_oid_queue *, git_oid_hash32, git_oid_equal); + +static void deletes_by_oid_dispose(git_merge_deletes_oidmap *map) +{ + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; deletes_by_oid_queue *queue; if (!map) return; - git_oidmap_foreach_value(map, queue, { + while (git_merge_deletes_oidmap_iterate(&iter, NULL, &queue, map) == 0) git_array_clear(queue->arr); - }); - git_oidmap_free(map); + + git_merge_deletes_oidmap_dispose(map); } -static int deletes_by_oid_enqueue(git_oidmap *map, git_pool *pool, const git_oid *id, size_t idx) +static int deletes_by_oid_enqueue(git_merge_deletes_oidmap *map, git_pool *pool, const git_oid *id, size_t idx) { deletes_by_oid_queue *queue; size_t *array_entry; - if ((queue = git_oidmap_get(map, id)) == NULL) { + if (git_merge_deletes_oidmap_get(&queue, map, id) != 0) { queue = git_pool_malloc(pool, sizeof(deletes_by_oid_queue)); GIT_ERROR_CHECK_ALLOC(queue); @@ -1169,7 +1172,7 @@ static int deletes_by_oid_enqueue(git_oidmap *map, git_pool *pool, const git_oid queue->next_pos = 0; queue->first_entry = idx; - if (git_oidmap_set(map, id, queue) < 0) + if (git_merge_deletes_oidmap_put(map, id, queue) < 0) return -1; } else { array_entry = git_array_alloc(queue->arr); @@ -1180,13 +1183,14 @@ static int deletes_by_oid_enqueue(git_oidmap *map, git_pool *pool, const git_oid return 0; } -static int deletes_by_oid_dequeue(size_t *idx, git_oidmap *map, const git_oid *id) +static int deletes_by_oid_dequeue(size_t *idx, git_merge_deletes_oidmap *map, const git_oid *id) { deletes_by_oid_queue *queue; size_t *array_entry; + int error; - if ((queue = git_oidmap_get(map, id)) == NULL) - return GIT_ENOTFOUND; + if ((error = git_merge_deletes_oidmap_get(&queue, map, id)) != 0) + return error; if (queue->next_pos == 0) { *idx = queue->first_entry; @@ -1209,15 +1213,10 @@ static int merge_diff_mark_similarity_exact( { size_t i, j; git_merge_diff *conflict_src, *conflict_tgt; - git_oidmap *ours_deletes_by_oid = NULL, *theirs_deletes_by_oid = NULL; + git_merge_deletes_oidmap ours_deletes_by_oid = GIT_HASHMAP_INIT, + theirs_deletes_by_oid = GIT_HASHMAP_INIT; int error = 0; - if (git_oidmap_new(&ours_deletes_by_oid) < 0 || - git_oidmap_new(&theirs_deletes_by_oid) < 0) { - error = -1; - goto done; - } - /* Build a map of object ids to conflicts */ git_vector_foreach(&diff_list->conflicts, i, conflict_src) { /* Items can be the source of a rename iff they have an item in the @@ -1233,13 +1232,13 @@ static int merge_diff_mark_similarity_exact( continue; if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { - error = deletes_by_oid_enqueue(ours_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); + error = deletes_by_oid_enqueue(&ours_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); if (error < 0) goto done; } if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { - error = deletes_by_oid_enqueue(theirs_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); + error = deletes_by_oid_enqueue(&theirs_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); if (error < 0) goto done; } @@ -1250,7 +1249,7 @@ static int merge_diff_mark_similarity_exact( continue; if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry)) { - if (deletes_by_oid_dequeue(&i, ours_deletes_by_oid, &conflict_tgt->our_entry.id) == 0) { + if (deletes_by_oid_dequeue(&i, &ours_deletes_by_oid, &conflict_tgt->our_entry.id) == 0) { similarity_ours[i].similarity = 100; similarity_ours[i].other_idx = j; @@ -1260,7 +1259,7 @@ static int merge_diff_mark_similarity_exact( } if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry)) { - if (deletes_by_oid_dequeue(&i, theirs_deletes_by_oid, &conflict_tgt->their_entry.id) == 0) { + if (deletes_by_oid_dequeue(&i, &theirs_deletes_by_oid, &conflict_tgt->their_entry.id) == 0) { similarity_theirs[i].similarity = 100; similarity_theirs[i].other_idx = j; @@ -1271,8 +1270,8 @@ static int merge_diff_mark_similarity_exact( } done: - deletes_by_oid_free(ours_deletes_by_oid); - deletes_by_oid_free(theirs_deletes_by_oid); + deletes_by_oid_dispose(&ours_deletes_by_oid); + deletes_by_oid_dispose(&theirs_deletes_by_oid); return error; } From 79290ba49c2f00513a4a05e18d703afa4d08a3ff Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 20:08:17 +0100 Subject: [PATCH 618/816] odb_mempack: use a typed hashmap --- src/libgit2/odb_mempack.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c index fb4391f8dcf..e1ee72cdb55 100644 --- a/src/libgit2/odb_mempack.c +++ b/src/libgit2/odb_mempack.c @@ -12,7 +12,6 @@ #include "hash.h" #include "odb.h" #include "array.h" -#include "oidmap.h" #include "pack-objects.h" #include "git2/odb_backend.h" @@ -29,9 +28,11 @@ struct memobject { char data[GIT_FLEX_ARRAY]; }; +GIT_HASHMAP_SETUP(git_odb_mempack_oidmap, const git_oid *, struct memobject *, git_oid_hash32, git_oid_equal); + struct memory_packer_db { git_odb_backend parent; - git_oidmap *objects; + git_odb_mempack_oidmap objects; git_array_t(struct memobject *) commits; }; @@ -41,7 +42,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void struct memobject *obj = NULL; size_t alloc_len; - if (git_oidmap_exists(db->objects, oid)) + if (git_odb_mempack_oidmap_contains(&db->objects, oid)) return 0; GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, sizeof(struct memobject), len); @@ -53,7 +54,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void obj->len = len; obj->type = type; - if (git_oidmap_set(db->objects, &obj->oid, obj) < 0) + if (git_odb_mempack_oidmap_put(&db->objects, &obj->oid, obj) < 0) return -1; if (type == GIT_OBJECT_COMMIT) { @@ -69,16 +70,17 @@ static int impl__exists(git_odb_backend *backend, const git_oid *oid) { struct memory_packer_db *db = (struct memory_packer_db *)backend; - return git_oidmap_exists(db->objects, oid); + return git_odb_mempack_oidmap_contains(&db->objects, oid); } static int impl__read(void **buffer_p, size_t *len_p, git_object_t *type_p, git_odb_backend *backend, const git_oid *oid) { struct memory_packer_db *db = (struct memory_packer_db *)backend; struct memobject *obj; + int error; - if ((obj = git_oidmap_get(db->objects, oid)) == NULL) - return GIT_ENOTFOUND; + if ((error = git_odb_mempack_oidmap_get(&obj, &db->objects, oid)) != 0) + return error; *len_p = obj->len; *type_p = obj->type; @@ -93,9 +95,10 @@ static int impl__read_header(size_t *len_p, git_object_t *type_p, git_odb_backen { struct memory_packer_db *db = (struct memory_packer_db *)backend; struct memobject *obj; + int error; - if ((obj = git_oidmap_get(db->objects, oid)) == NULL) - return GIT_ENOTFOUND; + if ((error = git_odb_mempack_oidmap_get(&obj, &db->objects, oid)) != 0) + return error; *len_p = obj->len; *type_p = obj->type; @@ -136,11 +139,11 @@ int git_mempack_write_thin_pack(git_odb_backend *backend, git_packbuilder *pb) { struct memory_packer_db *db = (struct memory_packer_db *)backend; const git_oid *oid; - size_t iter = 0; + git_hashmap_iter_t iter = GIT_HASHMAP_INIT; int err; while (true) { - err = git_oidmap_iterate(NULL, db->objects, &iter, &oid); + err = git_odb_mempack_oidmap_iterate(&iter, &oid, NULL, &db->objects); if (err == GIT_ITEROVER) break; @@ -167,14 +170,13 @@ int git_mempack_reset(git_odb_backend *_backend) { struct memory_packer_db *db = (struct memory_packer_db *)_backend; struct memobject *object = NULL; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; - git_oidmap_foreach_value(db->objects, object, { + while (git_odb_mempack_oidmap_iterate(&iter, NULL, &object, &db->objects) == 0) git__free(object); - }); git_array_clear(db->commits); - - git_oidmap_clear(db->objects); + git_odb_mempack_oidmap_clear(&db->objects); return 0; } @@ -184,7 +186,7 @@ static void impl__free(git_odb_backend *_backend) struct memory_packer_db *db = (struct memory_packer_db *)_backend; git_mempack_reset(_backend); - git_oidmap_free(db->objects); + git_odb_mempack_oidmap_dispose(&db->objects); git__free(db); } @@ -197,9 +199,6 @@ int git_mempack_new(git_odb_backend **out) db = git__calloc(1, sizeof(struct memory_packer_db)); GIT_ERROR_CHECK_ALLOC(db); - if (git_oidmap_new(&db->objects) < 0) - return -1; - db->parent.version = GIT_ODB_BACKEND_VERSION; db->parent.read = &impl__read; db->parent.write = &impl__write; From 5d2c56d8a5fd27e60e777307f729828a32130290 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Sep 2024 20:56:41 +0100 Subject: [PATCH 619/816] revwalk: hashmap --- src/libgit2/revwalk.c | 22 ++++++++++++---------- src/libgit2/revwalk.h | 6 +++--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/libgit2/revwalk.c b/src/libgit2/revwalk.c index 4ea6fae8ffb..7dd31f92fd1 100644 --- a/src/libgit2/revwalk.c +++ b/src/libgit2/revwalk.c @@ -15,6 +15,8 @@ #include "merge.h" #include "vector.h" +GIT_HASHMAP_FUNCTIONS(git_revwalk_oidmap, GIT_HASHMAP_INLINE, const git_oid *, git_commit_list_node *, git_oid_hash32, git_oid_equal); + static int get_revision(git_commit_list_node **out, git_revwalk *walk, git_commit_list **list); git_commit_list_node *git_revwalk__commit_lookup( @@ -23,7 +25,7 @@ git_commit_list_node *git_revwalk__commit_lookup( git_commit_list_node *commit; /* lookup and reserve space if not already present */ - if ((commit = git_oidmap_get(walk->commits, oid)) != NULL) + if (git_revwalk_oidmap_get(&commit, &walk->commits, oid) == 0) return commit; commit = git_commit_list_alloc_node(walk); @@ -32,7 +34,7 @@ git_commit_list_node *git_revwalk__commit_lookup( git_oid_cpy(&commit->oid, oid); - if ((git_oidmap_set(walk->commits, &commit->oid, commit)) < 0) + if (git_revwalk_oidmap_put(&walk->commits, &commit->oid, commit) < 0) return NULL; return commit; @@ -623,7 +625,7 @@ static int prepare_walk(git_revwalk *walk) return GIT_ITEROVER; } - /* + /* * This is a bit convoluted, but necessary to maintain the order of * the commits. This is especially important in situations where * git_revwalk__push_glob is called with a git_revwalk__push_options @@ -643,13 +645,13 @@ static int prepare_walk(git_revwalk *walk) git_error_set_oom(); return -1; } - + commit->seen = 1; if (commits_last == NULL) commits = new_list; else commits_last->next = new_list; - + commits_last = new_list; } } @@ -700,8 +702,7 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) git_revwalk *walk = git__calloc(1, sizeof(git_revwalk)); GIT_ERROR_CHECK_ALLOC(walk); - if (git_oidmap_new(&walk->commits) < 0 || - git_pqueue_init(&walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0 || + if (git_pqueue_init(&walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0 || git_pool_init(&walk->commit_pool, COMMIT_ALLOC) < 0) return -1; @@ -727,7 +728,7 @@ void git_revwalk_free(git_revwalk *walk) git_revwalk_reset(walk); git_odb_free(walk->odb); - git_oidmap_free(walk->commits); + git_revwalk_oidmap_dispose(&walk->commits); git_pool_clear(&walk->commit_pool); git_pqueue_free(&walk->iterator_time); git__free(walk); @@ -799,17 +800,18 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk) int git_revwalk_reset(git_revwalk *walk) { git_commit_list_node *commit; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; GIT_ASSERT_ARG(walk); - git_oidmap_foreach_value(walk->commits, commit, { + while (git_revwalk_oidmap_iterate(&iter, NULL, &commit, &walk->commits) == 0) { commit->seen = 0; commit->in_degree = 0; commit->topo_delay = 0; commit->uninteresting = 0; commit->added = 0; commit->flags = 0; - }); + } git_pqueue_clear(&walk->iterator_time); git_commit_list_free(&walk->iterator_topo); diff --git a/src/libgit2/revwalk.h b/src/libgit2/revwalk.h index 94b8a6fb1fd..31c01d2e628 100644 --- a/src/libgit2/revwalk.h +++ b/src/libgit2/revwalk.h @@ -10,19 +10,19 @@ #include "common.h" #include "git2/revwalk.h" -#include "oidmap.h" #include "commit_list.h" #include "pqueue.h" #include "pool.h" #include "vector.h" +#include "hashmap.h" -#include "oidmap.h" +GIT_HASHMAP_STRUCT(git_revwalk_oidmap, const git_oid *, git_commit_list_node *); struct git_revwalk { git_repository *repo; git_odb *odb; - git_oidmap *commits; + git_revwalk_oidmap commits; git_pool commit_pool; git_commit_list *iterator_topo; From 77e359ecc46a6d72108588b49037ec54193e6e43 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 01:05:56 +0100 Subject: [PATCH 620/816] indexer: use typed hashmap --- src/libgit2/indexer.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index d51d373b0f3..99d44de08a8 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -20,14 +20,16 @@ #include "filebuf.h" #include "oid.h" #include "oidarray.h" -#include "oidmap.h" #include "zstream.h" #include "object.h" +#include "hashmap.h" size_t git_indexer__max_objects = UINT32_MAX; #define UINT31_MAX (0x7FFFFFFF) +GIT_HASHMAP_SETUP(git_indexer_oidmap, const git_oid *, git_oid *, git_oid_hash32, git_oid_equal); + struct entry { git_oid oid; uint32_t crc; @@ -63,7 +65,7 @@ struct git_indexer { char objbuf[8*1024]; /* OIDs referenced from pack objects. Used for verification. */ - git_oidmap *expected_oids; + git_indexer_oidmap expected_oids; /* Needed to look up objects which we want to inject to fix a thin pack */ git_odb *odb; @@ -181,8 +183,7 @@ static int indexer_new( checksum_type = indexer_hash_algorithm(idx); if ((error = git_hash_ctx_init(&idx->hash_ctx, checksum_type)) < 0 || - (error = git_hash_ctx_init(&idx->trailer, checksum_type)) < 0 || - (error = git_oidmap_new(&idx->expected_oids)) < 0) + (error = git_hash_ctx_init(&idx->trailer, checksum_type)) < 0) goto cleanup; idx->do_verify = opts.verify; @@ -381,11 +382,11 @@ static int add_expected_oid(git_indexer *idx, const git_oid *oid) */ if ((!idx->odb || !git_odb_exists(idx->odb, oid)) && !git_oidmap_exists(idx->pack->idx_cache, oid) && - !git_oidmap_exists(idx->expected_oids, oid)) { + !git_indexer_oidmap_contains(&idx->expected_oids, oid)) { git_oid *dup = git__malloc(sizeof(*oid)); GIT_ERROR_CHECK_ALLOC(dup); git_oid_cpy(dup, oid); - return git_oidmap_set(idx->expected_oids, dup, dup); + return git_indexer_oidmap_put(&idx->expected_oids, dup, dup); } return 0; @@ -412,8 +413,8 @@ static int check_object_connectivity(git_indexer *idx, const git_rawobj *obj) goto out; } - if ((expected = git_oidmap_get(idx->expected_oids, &object->cached.oid)) != NULL) { - git_oidmap_delete(idx->expected_oids, &object->cached.oid); + if (git_indexer_oidmap_get(&expected, &idx->expected_oids, &object->cached.oid) == 0) { + git_indexer_oidmap_remove(&idx->expected_oids, &object->cached.oid); git__free(expected); } @@ -1301,9 +1302,9 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) * bail out due to an incomplete and thus corrupt * packfile. */ - if (git_oidmap_size(idx->expected_oids) > 0) { + if (git_indexer_oidmap_size(&idx->expected_oids) > 0) { git_error_set(GIT_ERROR_INDEXER, "packfile is missing %"PRIuZ" objects", - git_oidmap_size(idx->expected_oids)); + (size_t)git_indexer_oidmap_size(&idx->expected_oids)); return -1; } @@ -1446,9 +1447,8 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) void git_indexer_free(git_indexer *idx) { - const git_oid *key; - git_oid *value; - size_t iter; + git_oid *id; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; if (idx == NULL) return; @@ -1471,13 +1471,13 @@ void git_indexer_free(git_indexer *idx) git_packfile_free(idx->pack, !idx->pack_committed); - iter = 0; - while (git_oidmap_iterate((void **) &value, idx->expected_oids, &iter, &key) == 0) - git__free(value); + iter = GIT_HASHMAP_ITER_INIT; + while (git_indexer_oidmap_iterate(&iter, NULL, &id, &idx->expected_oids) == 0) + git__free(id); git_hash_ctx_cleanup(&idx->trailer); git_hash_ctx_cleanup(&idx->hash_ctx); git_str_dispose(&idx->entry_data); - git_oidmap_free(idx->expected_oids); + git_indexer_oidmap_dispose(&idx->expected_oids); git__free(idx); } From 9daf45abc3abb99a0e54f4ea3d465bd7ba8fac69 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 01:14:19 +0100 Subject: [PATCH 621/816] pack: use typed hashmap for index cache --- src/libgit2/indexer.c | 26 ++++++++++---------------- src/libgit2/pack.c | 4 +++- src/libgit2/pack.h | 18 +++++++++++------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index 99d44de08a8..accb0812f0b 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -381,7 +381,7 @@ static int add_expected_oid(git_indexer *idx, const git_oid *oid) * not have to expect it. */ if ((!idx->odb || !git_odb_exists(idx->odb, oid)) && - !git_oidmap_exists(idx->pack->idx_cache, oid) && + !git_pack_oidmap_contains(&idx->pack->idx_cache, oid) && !git_indexer_oidmap_contains(&idx->expected_oids, oid)) { git_oid *dup = git__malloc(sizeof(*oid)); GIT_ERROR_CHECK_ALLOC(dup); @@ -519,7 +519,7 @@ static int store_object(git_indexer *idx) git_oid_cpy(&pentry->id, &oid); pentry->offset = entry_start; - if (git_oidmap_exists(idx->pack->idx_cache, &pentry->id)) { + if (git_pack_oidmap_contains(&idx->pack->idx_cache, &pentry->id)) { const char *idstr = git_oid_tostr_s(&pentry->id); if (!idstr) @@ -531,7 +531,7 @@ static int store_object(git_indexer *idx) goto on_error; } - if ((error = git_oidmap_set(idx->pack->idx_cache, &pentry->id, pentry)) < 0) { + if ((error = git_pack_oidmap_put(&idx->pack->idx_cache, &pentry->id, pentry)) < 0) { git__free(pentry); git_error_set_oom(); goto on_error; @@ -560,7 +560,7 @@ static int store_object(git_indexer *idx) GIT_INLINE(bool) has_entry(git_indexer *idx, git_oid *id) { - return git_oidmap_exists(idx->pack->idx_cache, id); + return git_pack_oidmap_contains(&idx->pack->idx_cache, id); } static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, off64_t entry_start) @@ -576,8 +576,8 @@ static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_ent pentry->offset = entry_start; - if (git_oidmap_exists(idx->pack->idx_cache, &pentry->id) || - git_oidmap_set(idx->pack->idx_cache, &pentry->id, pentry) < 0) { + if (git_pack_oidmap_contains(&idx->pack->idx_cache, &pentry->id) || + git_pack_oidmap_put(&idx->pack->idx_cache, &pentry->id, pentry) < 0) { git_error_set(GIT_ERROR_INDEXER, "cannot insert object into pack"); return -1; } @@ -912,9 +912,6 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_inde return -1; } - if (git_oidmap_new(&idx->pack->idx_cache) < 0) - return -1; - idx->pack->has_cache = 1; if (git_vector_init(&idx->objects, total_objects, objects_cmp) < 0) return -1; @@ -1447,6 +1444,7 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) void git_indexer_free(git_indexer *idx) { + struct git_pack_entry *pentry; git_oid *id; git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; @@ -1458,14 +1456,10 @@ void git_indexer_free(git_indexer *idx) git_vector_dispose_deep(&idx->objects); - if (idx->pack->idx_cache) { - struct git_pack_entry *pentry; - git_oidmap_foreach_value(idx->pack->idx_cache, pentry, { - git__free(pentry); - }); + while (git_pack_oidmap_iterate(&iter, NULL, &pentry, &idx->pack->idx_cache) == 0) + git__free(pentry); - git_oidmap_free(idx->pack->idx_cache); - } + git_pack_oidmap_dispose(&idx->pack->idx_cache); git_vector_dispose_deep(&idx->deltas); diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index 642dcb8a004..fe18fe08864 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -41,6 +41,8 @@ static int pack_entry_find_offset( const git_oid *short_oid, size_t len); +GIT_HASHMAP_FUNCTIONS(git_pack_oidmap, , const git_oid *, struct git_pack_entry *, git_oid_hash32, git_oid_equal); + static int packfile_error(const char *message) { git_error_set(GIT_ERROR_ODB, "invalid pack file - %s", message); @@ -1009,7 +1011,7 @@ int get_delta_base( if (p->has_cache) { struct git_pack_entry *entry; - if ((entry = git_oidmap_get(p->idx_cache, &base_oid)) != NULL) { + if (git_pack_oidmap_get(&entry, &p->idx_cache, &base_oid) == 0) { if (entry->offset == 0) return packfile_error("delta offset is zero"); diff --git a/src/libgit2/pack.h b/src/libgit2/pack.h index 1a9eb14b295..f98aec572de 100644 --- a/src/libgit2/pack.h +++ b/src/libgit2/pack.h @@ -83,6 +83,12 @@ typedef git_array_t(struct pack_chain_elem) git_dependency_chain; #define GIT_PACK_CACHE_MEMORY_LIMIT 16 * 1024 * 1024 #define GIT_PACK_CACHE_SIZE_LIMIT 1024 * 1024 /* don't bother caching anything over 1MB */ +struct git_pack_entry { + off64_t offset; + git_oid id; + struct git_pack_file *p; +}; + typedef struct { size_t memory_used; size_t memory_limit; @@ -91,6 +97,9 @@ typedef struct { git_offmap *entries; } git_pack_cache; +GIT_HASHMAP_STRUCT(git_pack_oidmap, const git_oid *, struct git_pack_entry *); +GIT_HASHMAP_PROTOTYPES(git_pack_oidmap, const git_oid *, struct git_pack_entry *); + struct git_pack_file { git_mwindow_file mwf; git_map index_map; @@ -110,7 +119,8 @@ struct git_pack_file { int index_version; git_time_t mtime; - git_oidmap *idx_cache; + + git_pack_oidmap idx_cache; unsigned char **ids; git_pack_cache bases; /* delta base cache */ @@ -139,12 +149,6 @@ int git_pack__lookup_id( const unsigned char *id_prefix, const git_oid_t oid_type); -struct git_pack_entry { - off64_t offset; - git_oid id; - struct git_pack_file *p; -}; - typedef struct git_packfile_stream { off64_t curpos; int done; From 597a67164dcf8f6a6dfd8ae15931ce6102760cf3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 01:35:08 +0100 Subject: [PATCH 622/816] pack: typed hashmap for offsets instead of offmap --- src/libgit2/pack.c | 40 ++++++++++++++++++---------------------- src/libgit2/pack.h | 12 ++++++------ 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index fe18fe08864..0688e6aa927 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -41,6 +41,10 @@ static int pack_entry_find_offset( const git_oid *short_oid, size_t len); +#define off64_hash(key) (uint32_t)((key)>>33^(key)^(key)<<11) +#define off64_equal(a, b) ((a) == (b)) + +GIT_HASHMAP_FUNCTIONS(git_pack_offsetmap, GIT_HASHMAP_INLINE, off64_t, git_pack_cache_entry *, off64_hash, off64_equal); GIT_HASHMAP_FUNCTIONS(git_pack_oidmap, , const git_oid *, struct git_pack_entry *, git_oid_hash32, git_oid_equal); static int packfile_error(const char *message) @@ -77,31 +81,21 @@ static void free_cache_object(void *o) static void cache_free(git_pack_cache *cache) { + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; git_pack_cache_entry *entry; - if (cache->entries) { - git_offmap_foreach_value(cache->entries, entry, { - free_cache_object(entry); - }); + while (git_pack_offsetmap_iterate(&iter, NULL, &entry, &cache->entries) == 0) + free_cache_object(entry); - git_offmap_free(cache->entries); - cache->entries = NULL; - } + git_pack_offsetmap_dispose(&cache->entries); } static int cache_init(git_pack_cache *cache) { - if (git_offmap_new(&cache->entries) < 0) - return -1; - cache->memory_limit = GIT_PACK_CACHE_MEMORY_LIMIT; if (git_mutex_init(&cache->lock)) { git_error_set(GIT_ERROR_OS, "failed to initialize pack cache mutex"); - - git__free(cache->entries); - cache->entries = NULL; - return -1; } @@ -110,15 +104,16 @@ static int cache_init(git_pack_cache *cache) static git_pack_cache_entry *cache_get(git_pack_cache *cache, off64_t offset) { - git_pack_cache_entry *entry; + git_pack_cache_entry *entry = NULL; if (git_mutex_lock(&cache->lock) < 0) return NULL; - if ((entry = git_offmap_get(cache->entries, offset)) != NULL) { + if (git_pack_offsetmap_get(&entry, &cache->entries, offset) == 0) { git_atomic32_inc(&entry->refcount); entry->last_usage = cache->use_ctr++; } + git_mutex_unlock(&cache->lock); return entry; @@ -127,16 +122,17 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, off64_t offset) /* Run with the cache lock held */ static void free_lowest_entry(git_pack_cache *cache) { - off64_t offset; + git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT; git_pack_cache_entry *entry; + off64_t offset; - git_offmap_foreach(cache->entries, offset, entry, { + while (git_pack_offsetmap_iterate(&iter, &offset, &entry, &cache->entries) == 0) { if (entry && git_atomic32_get(&entry->refcount) == 0) { cache->memory_used -= entry->raw.len; - git_offmap_delete(cache->entries, offset); + git_pack_offsetmap_remove(&cache->entries, offset); free_cache_object(entry); } - }); + } } static int cache_add( @@ -159,12 +155,12 @@ static int cache_add( return -1; } /* Add it to the cache if nobody else has */ - exists = git_offmap_exists(cache->entries, offset); + exists = git_pack_offsetmap_contains(&cache->entries, offset); if (!exists) { while (cache->memory_used + base->len > cache->memory_limit) free_lowest_entry(cache); - git_offmap_set(cache->entries, offset, entry); + git_pack_offsetmap_put(&cache->entries, offset, entry); cache->memory_used += entry->raw.len; *cached_out = entry; diff --git a/src/libgit2/pack.h b/src/libgit2/pack.h index f98aec572de..8e0cba15f2c 100644 --- a/src/libgit2/pack.h +++ b/src/libgit2/pack.h @@ -16,8 +16,6 @@ #include "map.h" #include "mwindow.h" #include "odb.h" -#include "offmap.h" -#include "oidmap.h" #include "zstream.h" #include "oid.h" @@ -89,17 +87,19 @@ struct git_pack_entry { struct git_pack_file *p; }; +GIT_HASHMAP_STRUCT(git_pack_offsetmap, off64_t, git_pack_cache_entry *); + +GIT_HASHMAP_STRUCT(git_pack_oidmap, const git_oid *, struct git_pack_entry *); +GIT_HASHMAP_PROTOTYPES(git_pack_oidmap, const git_oid *, struct git_pack_entry *); + typedef struct { size_t memory_used; size_t memory_limit; size_t use_ctr; git_mutex lock; - git_offmap *entries; + git_pack_offsetmap entries; } git_pack_cache; -GIT_HASHMAP_STRUCT(git_pack_oidmap, const git_oid *, struct git_pack_entry *); -GIT_HASHMAP_PROTOTYPES(git_pack_oidmap, const git_oid *, struct git_pack_entry *); - struct git_pack_file { git_mwindow_file mwf; git_map index_map; From 4e2ce7eb8b2253b0999ef3f6edfbcbbf41fea624 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 01:55:28 +0100 Subject: [PATCH 623/816] packbuilder: use hashmap for pobject map --- src/libgit2/pack-objects.c | 18 +++++++++--------- src/libgit2/pack-objects.h | 7 +++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index 7c331c2d547..ff574b7c862 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -64,6 +64,8 @@ struct walk_object { /* Size of the buffer to feed to zlib */ #define COMPRESS_BUFLEN (1024 * 1024) +GIT_HASHMAP_FUNCTIONS(git_packbuilder_pobjectmap, GIT_HASHMAP_INLINE, const git_oid *, git_pobject *, git_oid_hash32, git_oid_equal); + static unsigned name_hash(const char *name) { unsigned c, hash = 0; @@ -139,8 +141,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) hash_algorithm = git_oid_algorithm(pb->oid_type); GIT_ASSERT(hash_algorithm); - if (git_oidmap_new(&pb->object_ix) < 0 || - git_oidmap_new(&pb->walk_objects) < 0 || + if (git_oidmap_new(&pb->walk_objects) < 0 || git_pool_init(&pb->object_pool, sizeof(struct walk_object)) < 0) goto on_error; @@ -192,10 +193,10 @@ static int rehash(git_packbuilder *pb) git_pobject *po; size_t i; - git_oidmap_clear(pb->object_ix); + git_packbuilder_pobjectmap_clear(&pb->object_ix); for (i = 0, po = pb->object_list; i < pb->nr_objects; i++, po++) { - if (git_oidmap_set(pb->object_ix, &po->id, po) < 0) + if (git_packbuilder_pobjectmap_put(&pb->object_ix, &po->id, po) < 0) return -1; } @@ -214,7 +215,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, /* If the object already exists in the hash table, then we don't * have any work to do */ - if (git_oidmap_exists(pb->object_ix, oid)) + if (git_packbuilder_pobjectmap_contains(&pb->object_ix, oid)) return 0; if (pb->nr_objects >= pb->nr_alloc) { @@ -246,7 +247,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, git_oid_cpy(&po->id, oid); po->hash = name_hash(name); - if (git_oidmap_set(pb->object_ix, &po->id, po) < 0) { + if (git_packbuilder_pobjectmap_put(&pb->object_ix, &po->id, po) < 0) { git_error_set_oom(); return -1; } @@ -515,7 +516,7 @@ static int cb_tag_foreach(const char *name, git_oid *oid, void *data) GIT_UNUSED(name); - if ((po = git_oidmap_get(pb->object_ix, oid)) == NULL) + if (git_packbuilder_pobjectmap_get(&po, &pb->object_ix, oid) != 0) return 0; po->tagged = 1; @@ -1843,8 +1844,7 @@ void git_packbuilder_free(git_packbuilder *pb) if (pb->odb) git_odb_free(pb->odb); - if (pb->object_ix) - git_oidmap_free(pb->object_ix); + git_packbuilder_pobjectmap_dispose(&pb->object_ix); if (pb->object_list) git__free(pb->object_list); diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h index 380a28ebe1f..efaf613e5b5 100644 --- a/src/libgit2/pack-objects.h +++ b/src/libgit2/pack-objects.h @@ -12,10 +12,11 @@ #include "str.h" #include "hash.h" -#include "oidmap.h" #include "zstream.h" #include "pool.h" #include "indexer.h" +#include "oidmap.h" +#include "hashmap.h" #include "git2/oid.h" #include "git2/pack.h" @@ -51,6 +52,8 @@ typedef struct git_pobject { filled:1; } git_pobject; +GIT_HASHMAP_STRUCT(git_packbuilder_pobjectmap, const git_oid *, git_pobject *); + struct git_packbuilder { git_repository *repo; /* associated repository */ git_odb *odb; /* associated object database */ @@ -69,7 +72,7 @@ struct git_packbuilder { git_pobject *object_list; - git_oidmap *object_ix; + git_packbuilder_pobjectmap object_ix; git_oidmap *walk_objects; git_pool object_pool; From 8c55bbeb9e1637bc0faf894ac1d4cae99c1929f6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 02:01:12 +0100 Subject: [PATCH 624/816] packbuilder: use hashmap for walk_objects --- src/libgit2/pack-objects.c | 14 +++++++++----- src/libgit2/pack-objects.h | 7 ++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index ff574b7c862..44c591555aa 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -65,6 +65,7 @@ struct walk_object { #define COMPRESS_BUFLEN (1024 * 1024) GIT_HASHMAP_FUNCTIONS(git_packbuilder_pobjectmap, GIT_HASHMAP_INLINE, const git_oid *, git_pobject *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_FUNCTIONS(git_packbuilder_walk_objectmap, GIT_HASHMAP_INLINE, const git_oid *, struct walk_object *, git_oid_hash32, git_oid_equal); static unsigned name_hash(const char *name) { @@ -141,8 +142,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) hash_algorithm = git_oid_algorithm(pb->oid_type); GIT_ASSERT(hash_algorithm); - if (git_oidmap_new(&pb->walk_objects) < 0 || - git_pool_init(&pb->object_pool, sizeof(struct walk_object)) < 0) + if (git_pool_init(&pb->object_pool, sizeof(struct walk_object)) < 0) goto on_error; pb->repo = repo; @@ -1607,12 +1607,16 @@ static int retrieve_object(struct walk_object **out, git_packbuilder *pb, const struct walk_object *obj; int error; - if ((obj = git_oidmap_get(pb->walk_objects, id)) == NULL) { + error = git_packbuilder_walk_objectmap_get(&obj, &pb->walk_objects, id); + + if (error == GIT_ENOTFOUND) { if ((error = lookup_walk_object(&obj, pb, id)) < 0) return error; - if ((error = git_oidmap_set(pb->walk_objects, &obj->id, obj)) < 0) + if ((error = git_packbuilder_walk_objectmap_put(&pb->walk_objects, &obj->id, obj)) < 0) return error; + } else if (error != 0) { + return error; } *out = obj; @@ -1849,7 +1853,7 @@ void git_packbuilder_free(git_packbuilder *pb) if (pb->object_list) git__free(pb->object_list); - git_oidmap_free(pb->walk_objects); + git_packbuilder_walk_objectmap_dispose(&pb->walk_objects); git_pool_clear(&pb->object_pool); git_hash_ctx_cleanup(&pb->ctx); diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h index efaf613e5b5..da726c714ce 100644 --- a/src/libgit2/pack-objects.h +++ b/src/libgit2/pack-objects.h @@ -15,7 +15,6 @@ #include "zstream.h" #include "pool.h" #include "indexer.h" -#include "oidmap.h" #include "hashmap.h" #include "git2/oid.h" @@ -52,7 +51,10 @@ typedef struct git_pobject { filled:1; } git_pobject; +typedef struct walk_object walk_object; + GIT_HASHMAP_STRUCT(git_packbuilder_pobjectmap, const git_oid *, git_pobject *); +GIT_HASHMAP_STRUCT(git_packbuilder_walk_objectmap, const git_oid *, walk_object *); struct git_packbuilder { git_repository *repo; /* associated repository */ @@ -73,8 +75,7 @@ struct git_packbuilder { git_pobject *object_list; git_packbuilder_pobjectmap object_ix; - - git_oidmap *walk_objects; + git_packbuilder_walk_objectmap walk_objects; git_pool object_pool; #ifndef GIT_DEPRECATE_HARD From 8d81bb57d65e9b646ed75005d8ad455f266cc32b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 01:36:49 +0100 Subject: [PATCH 625/816] hashmap: remove now-unused offmap and strmap --- src/libgit2/attrcache.h | 1 - src/libgit2/offmap.c | 101 --------------------- src/libgit2/offmap.h | 133 --------------------------- src/libgit2/refs.h | 1 - src/libgit2/repository.c | 1 - src/util/strmap.c | 100 --------------------- src/util/strmap.h | 131 --------------------------- tests/util/strmap.c | 190 --------------------------------------- 8 files changed, 658 deletions(-) delete mode 100644 src/libgit2/offmap.c delete mode 100644 src/libgit2/offmap.h delete mode 100644 src/util/strmap.c delete mode 100644 src/util/strmap.h delete mode 100644 tests/util/strmap.c diff --git a/src/libgit2/attrcache.h b/src/libgit2/attrcache.h index a2710b4585b..2693278d4b8 100644 --- a/src/libgit2/attrcache.h +++ b/src/libgit2/attrcache.h @@ -10,7 +10,6 @@ #include "common.h" #include "attr_file.h" -#include "strmap.h" #define GIT_ATTR_CONFIG "core.attributesfile" #define GIT_IGNORE_CONFIG "core.excludesfile" diff --git a/src/libgit2/offmap.c b/src/libgit2/offmap.c deleted file mode 100644 index be9eb66d8c0..00000000000 --- a/src/libgit2/offmap.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "offmap.h" - -#define kmalloc git__malloc -#define kcalloc git__calloc -#define krealloc git__realloc -#define kreallocarray git__reallocarray -#define kfree git__free -#include "khash.h" - -__KHASH_TYPE(off, off64_t, void *) - -__KHASH_IMPL(off, static kh_inline, off64_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal) - - -int git_offmap_new(git_offmap **out) -{ - *out = kh_init(off); - GIT_ERROR_CHECK_ALLOC(*out); - - return 0; -} - -void git_offmap_free(git_offmap *map) -{ - kh_destroy(off, map); -} - -void git_offmap_clear(git_offmap *map) -{ - kh_clear(off, map); -} - -size_t git_offmap_size(git_offmap *map) -{ - return kh_size(map); -} - -void *git_offmap_get(git_offmap *map, const off64_t key) -{ - size_t idx = kh_get(off, map, key); - if (idx == kh_end(map) || !kh_exist(map, idx)) - return NULL; - return kh_val(map, idx); -} - -int git_offmap_set(git_offmap *map, const off64_t key, void *value) -{ - size_t idx; - int rval; - - idx = kh_put(off, map, key, &rval); - if (rval < 0) - return -1; - - if (rval == 0) - kh_key(map, idx) = key; - - kh_val(map, idx) = value; - - return 0; -} - -int git_offmap_delete(git_offmap *map, const off64_t key) -{ - khiter_t idx = kh_get(off, map, key); - if (idx == kh_end(map)) - return GIT_ENOTFOUND; - kh_del(off, map, idx); - return 0; -} - -int git_offmap_exists(git_offmap *map, const off64_t key) -{ - return kh_get(off, map, key) != kh_end(map); -} - -int git_offmap_iterate(void **value, git_offmap *map, size_t *iter, off64_t *key) -{ - size_t i = *iter; - - while (i < map->n_buckets && !kh_exist(map, i)) - i++; - - if (i >= map->n_buckets) - return GIT_ITEROVER; - - if (key) - *key = kh_key(map, i); - if (value) - *value = kh_value(map, i); - *iter = ++i; - - return 0; -} diff --git a/src/libgit2/offmap.h b/src/libgit2/offmap.h deleted file mode 100644 index 81c459b0145..00000000000 --- a/src/libgit2/offmap.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2012 the libgit2 contributors - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_offmap_h__ -#define INCLUDE_offmap_h__ - -#include "common.h" - -#include "git2/types.h" - -/** A map with `off64_t`s as key. */ -typedef struct kh_off_s git_offmap; - -/** - * Allocate a new `off64_t` map. - * - * @param out Pointer to the map that shall be allocated. - * @return 0 on success, an error code if allocation has failed. - */ -int git_offmap_new(git_offmap **out); - -/** - * Free memory associated with the map. - * - * Note that this function will _not_ free values added to this - * map. - * - * @param map Pointer to the map that is to be free'd. May be - * `NULL`. - */ -void git_offmap_free(git_offmap *map); - -/** - * Clear all entries from the map. - * - * This function will remove all entries from the associated map. - * Memory associated with it will not be released, though. - * - * @param map Pointer to the map that shall be cleared. May be - * `NULL`. - */ -void git_offmap_clear(git_offmap *map); - -/** - * Return the number of elements in the map. - * - * @parameter map map containing the elements - * @return number of elements in the map - */ -size_t git_offmap_size(git_offmap *map); - -/** - * Return value associated with the given key. - * - * @param map map to search key in - * @param key key to search for - * @return value associated with the given key or NULL if the key was not found - */ -void *git_offmap_get(git_offmap *map, const off64_t key); - -/** - * Set the entry for key to value. - * - * If the map has no corresponding entry for the given key, a new - * entry will be created with the given value. If an entry exists - * already, its value will be updated to match the given value. - * - * @param map map to create new entry in - * @param key key to set - * @param value value to associate the key with; may be NULL - * @return zero if the key was successfully set, a negative error - * code otherwise - */ -int git_offmap_set(git_offmap *map, const off64_t key, void *value); - -/** - * Delete an entry from the map. - * - * Delete the given key and its value from the map. If no such - * key exists, this will do nothing. - * - * @param map map to delete key in - * @param key key to delete - * @return `0` if the key has been deleted, GIT_ENOTFOUND if no - * such key was found, a negative code in case of an - * error - */ -int git_offmap_delete(git_offmap *map, const off64_t key); - -/** - * Check whether a key exists in the given map. - * - * @param map map to query for the key - * @param key key to search for - * @return 0 if the key has not been found, 1 otherwise - */ -int git_offmap_exists(git_offmap *map, const off64_t key); - -/** - * Iterate over entries of the map. - * - * This functions allows to iterate over all key-value entries of - * the map. The current position is stored in the `iter` variable - * and should be initialized to `0` before the first call to this - * function. - * - * @param map map to iterate over - * @param value pointer to the variable where to store the current - * value. May be NULL. - * @param iter iterator storing the current position. Initialize - * with zero previous to the first call. - * @param key pointer to the variable where to store the current - * key. May be NULL. - * @return `0` if the next entry was correctly retrieved. - * GIT_ITEROVER if no entries are left. A negative error - * code otherwise. - */ -int git_offmap_iterate(void **value, git_offmap *map, size_t *iter, off64_t *key); - -#define git_offmap_foreach(h, kvar, vvar, code) { size_t __i = 0; \ - while (git_offmap_iterate((void **) &(vvar), h, &__i, &(kvar)) == 0) { \ - code; \ - } } - -#define git_offmap_foreach_value(h, vvar, code) { size_t __i = 0; \ - while (git_offmap_iterate((void **) &(vvar), h, &__i, NULL) == 0) { \ - code; \ - } } - -#endif diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index 588af82fe40..a06965b60d8 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -12,7 +12,6 @@ #include "git2/oid.h" #include "git2/refs.h" #include "git2/refdb.h" -#include "strmap.h" #include "str.h" #include "oid.h" diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 01fc25519a3..0cc47452b88 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -34,7 +34,6 @@ #include "submodule.h" #include "worktree.h" #include "path.h" -#include "strmap.h" #ifdef GIT_WIN32 # include "win32/w32_util.h" diff --git a/src/util/strmap.c b/src/util/strmap.c deleted file mode 100644 index c6e5b6dc70b..00000000000 --- a/src/util/strmap.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "strmap.h" - -#define kmalloc git__malloc -#define kcalloc git__calloc -#define krealloc git__realloc -#define kreallocarray git__reallocarray -#define kfree git__free -#include "khash.h" - -__KHASH_TYPE(str, const char *, void *) - -__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal) - -int git_strmap_new(git_strmap **out) -{ - *out = kh_init(str); - GIT_ERROR_CHECK_ALLOC(*out); - - return 0; -} - -void git_strmap_free(git_strmap *map) -{ - kh_destroy(str, map); -} - -void git_strmap_clear(git_strmap *map) -{ - kh_clear(str, map); -} - -size_t git_strmap_size(git_strmap *map) -{ - return kh_size(map); -} - -void *git_strmap_get(git_strmap *map, const char *key) -{ - size_t idx = kh_get(str, map, key); - if (idx == kh_end(map) || !kh_exist(map, idx)) - return NULL; - return kh_val(map, idx); -} - -int git_strmap_set(git_strmap *map, const char *key, void *value) -{ - size_t idx; - int rval; - - idx = kh_put(str, map, key, &rval); - if (rval < 0) - return -1; - - if (rval == 0) - kh_key(map, idx) = key; - - kh_val(map, idx) = value; - - return 0; -} - -int git_strmap_delete(git_strmap *map, const char *key) -{ - khiter_t idx = kh_get(str, map, key); - if (idx == kh_end(map)) - return GIT_ENOTFOUND; - kh_del(str, map, idx); - return 0; -} - -int git_strmap_exists(git_strmap *map, const char *key) -{ - return kh_get(str, map, key) != kh_end(map); -} - -int git_strmap_iterate(void **value, git_strmap *map, size_t *iter, const char **key) -{ - size_t i = *iter; - - while (i < map->n_buckets && !kh_exist(map, i)) - i++; - - if (i >= map->n_buckets) - return GIT_ITEROVER; - - if (key) - *key = kh_key(map, i); - if (value) - *value = kh_val(map, i); - *iter = ++i; - - return 0; -} diff --git a/src/util/strmap.h b/src/util/strmap.h deleted file mode 100644 index b64d3dcb55d..00000000000 --- a/src/util/strmap.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_strmap_h__ -#define INCLUDE_strmap_h__ - -#include "git2_util.h" - -/** A map with C strings as key. */ -typedef struct kh_str_s git_strmap; - -/** - * Allocate a new string map. - * - * @param out Pointer to the map that shall be allocated. - * @return 0 on success, an error code if allocation has failed. - */ -int git_strmap_new(git_strmap **out); - -/** - * Free memory associated with the map. - * - * Note that this function will _not_ free keys or values added - * to this map. - * - * @param map Pointer to the map that is to be free'd. May be - * `NULL`. - */ -void git_strmap_free(git_strmap *map); - -/** - * Clear all entries from the map. - * - * This function will remove all entries from the associated map. - * Memory associated with it will not be released, though. - * - * @param map Pointer to the map that shall be cleared. May be - * `NULL`. - */ -void git_strmap_clear(git_strmap *map); - -/** - * Return the number of elements in the map. - * - * @parameter map map containing the elements - * @return number of elements in the map - */ -size_t git_strmap_size(git_strmap *map); - -/** - * Return value associated with the given key. - * - * @param map map to search key in - * @param key key to search for - * @return value associated with the given key or NULL if the key was not found - */ -void *git_strmap_get(git_strmap *map, const char *key); - -/** - * Set the entry for key to value. - * - * If the map has no corresponding entry for the given key, a new - * entry will be created with the given value. If an entry exists - * already, its value will be updated to match the given value. - * - * @param map map to create new entry in - * @param key key to set - * @param value value to associate the key with; may be NULL - * @return zero if the key was successfully set, a negative error - * code otherwise - */ -int git_strmap_set(git_strmap *map, const char *key, void *value); - -/** - * Delete an entry from the map. - * - * Delete the given key and its value from the map. If no such - * key exists, this will do nothing. - * - * @param map map to delete key in - * @param key key to delete - * @return `0` if the key has been deleted, GIT_ENOTFOUND if no - * such key was found, a negative code in case of an - * error - */ -int git_strmap_delete(git_strmap *map, const char *key); - -/** - * Check whether a key exists in the given map. - * - * @param map map to query for the key - * @param key key to search for - * @return 0 if the key has not been found, 1 otherwise - */ -int git_strmap_exists(git_strmap *map, const char *key); - -/** - * Iterate over entries of the map. - * - * This functions allows to iterate over all key-value entries of - * the map. The current position is stored in the `iter` variable - * and should be initialized to `0` before the first call to this - * function. - * - * @param map map to iterate over - * @param value pointer to the variable where to store the current - * value. May be NULL. - * @param iter iterator storing the current position. Initialize - * with zero previous to the first call. - * @param key pointer to the variable where to store the current - * key. May be NULL. - * @return `0` if the next entry was correctly retrieved. - * GIT_ITEROVER if no entries are left. A negative error - * code otherwise. - */ -int git_strmap_iterate(void **value, git_strmap *map, size_t *iter, const char **key); - -#define git_strmap_foreach(h, kvar, vvar, code) { size_t __i = 0; \ - while (git_strmap_iterate((void **) &(vvar), h, &__i, &(kvar)) == 0) { \ - code; \ - } } - -#define git_strmap_foreach_value(h, vvar, code) { size_t __i = 0; \ - while (git_strmap_iterate((void **) &(vvar), h, &__i, NULL) == 0) { \ - code; \ - } } - -#endif diff --git a/tests/util/strmap.c b/tests/util/strmap.c deleted file mode 100644 index c4f5c864704..00000000000 --- a/tests/util/strmap.c +++ /dev/null @@ -1,190 +0,0 @@ -#include "clar_libgit2.h" -#include "strmap.h" - -static git_strmap *g_table; - -void test_strmap__initialize(void) -{ - cl_git_pass(git_strmap_new(&g_table)); - cl_assert(g_table != NULL); -} - -void test_strmap__cleanup(void) -{ - git_strmap_free(g_table); -} - -void test_strmap__0(void) -{ - cl_assert(git_strmap_size(g_table) == 0); -} - -static void insert_strings(git_strmap *table, size_t count) -{ - size_t i, j, over; - char *str; - - for (i = 0; i < count; ++i) { - str = malloc(10); - for (j = 0; j < 10; ++j) - str[j] = 'a' + (i % 26); - str[9] = '\0'; - - /* if > 26, then encode larger value in first letters */ - for (j = 0, over = i / 26; over > 0; j++, over = over / 26) - str[j] = 'A' + (over % 26); - - cl_git_pass(git_strmap_set(table, str, str)); - } - - cl_assert_equal_i(git_strmap_size(table), count); -} - -void test_strmap__inserted_strings_can_be_retrieved(void) -{ - char *str; - int i; - - insert_strings(g_table, 20); - - cl_assert(git_strmap_exists(g_table, "aaaaaaaaa")); - cl_assert(git_strmap_exists(g_table, "ggggggggg")); - cl_assert(!git_strmap_exists(g_table, "aaaaaaaab")); - cl_assert(!git_strmap_exists(g_table, "abcdefghi")); - - i = 0; - git_strmap_foreach_value(g_table, str, { i++; free(str); }); - cl_assert(i == 20); -} - -void test_strmap__deleted_entry_cannot_be_retrieved(void) -{ - char *str; - int i; - - insert_strings(g_table, 20); - - cl_assert(git_strmap_exists(g_table, "bbbbbbbbb")); - str = git_strmap_get(g_table, "bbbbbbbbb"); - cl_assert_equal_s(str, "bbbbbbbbb"); - cl_git_pass(git_strmap_delete(g_table, "bbbbbbbbb")); - free(str); - - cl_assert(!git_strmap_exists(g_table, "bbbbbbbbb")); - - i = 0; - git_strmap_foreach_value(g_table, str, { i++; free(str); }); - cl_assert_equal_i(i, 19); -} - -void test_strmap__inserting_many_keys_succeeds(void) -{ - char *str; - int i; - - insert_strings(g_table, 10000); - - i = 0; - git_strmap_foreach_value(g_table, str, { i++; free(str); }); - cl_assert_equal_i(i, 10000); -} - -void test_strmap__get_succeeds_with_existing_entries(void) -{ - const char *keys[] = { "foo", "bar", "gobble" }; - char *values[] = { "oof", "rab", "elbbog" }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(keys); i++) - cl_git_pass(git_strmap_set(g_table, keys[i], values[i])); - - cl_assert_equal_s(git_strmap_get(g_table, "foo"), "oof"); - cl_assert_equal_s(git_strmap_get(g_table, "bar"), "rab"); - cl_assert_equal_s(git_strmap_get(g_table, "gobble"), "elbbog"); -} - -void test_strmap__get_returns_null_on_nonexisting_key(void) -{ - const char *keys[] = { "foo", "bar", "gobble" }; - char *values[] = { "oof", "rab", "elbbog" }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(keys); i++) - cl_git_pass(git_strmap_set(g_table, keys[i], values[i])); - - cl_assert_equal_p(git_strmap_get(g_table, "other"), NULL); -} - -void test_strmap__set_persists_key(void) -{ - cl_git_pass(git_strmap_set(g_table, "foo", "oof")); - cl_assert_equal_s(git_strmap_get(g_table, "foo"), "oof"); -} - -void test_strmap__set_persists_multpile_keys(void) -{ - cl_git_pass(git_strmap_set(g_table, "foo", "oof")); - cl_git_pass(git_strmap_set(g_table, "bar", "rab")); - cl_assert_equal_s(git_strmap_get(g_table, "foo"), "oof"); - cl_assert_equal_s(git_strmap_get(g_table, "bar"), "rab"); -} - -void test_strmap__set_updates_existing_key(void) -{ - cl_git_pass(git_strmap_set(g_table, "foo", "oof")); - cl_git_pass(git_strmap_set(g_table, "bar", "rab")); - cl_git_pass(git_strmap_set(g_table, "gobble", "elbbog")); - cl_assert_equal_i(git_strmap_size(g_table), 3); - - cl_git_pass(git_strmap_set(g_table, "foo", "other")); - cl_assert_equal_i(git_strmap_size(g_table), 3); - - cl_assert_equal_s(git_strmap_get(g_table, "foo"), "other"); -} - -void test_strmap__iteration(void) -{ - struct { - char *key; - char *value; - int seen; - } entries[] = { - { "foo", "oof" }, - { "bar", "rab" }, - { "gobble", "elbbog" }, - }; - const char *key, *value; - size_t i, n; - - for (i = 0; i < ARRAY_SIZE(entries); i++) - cl_git_pass(git_strmap_set(g_table, entries[i].key, entries[i].value)); - - i = 0, n = 0; - while (git_strmap_iterate((void **) &value, g_table, &i, &key) == 0) { - size_t j; - - for (j = 0; j < ARRAY_SIZE(entries); j++) { - if (strcmp(entries[j].key, key)) - continue; - - cl_assert_equal_i(entries[j].seen, 0); - cl_assert_equal_s(entries[j].value, value); - entries[j].seen++; - break; - } - - n++; - } - - for (i = 0; i < ARRAY_SIZE(entries); i++) - cl_assert_equal_i(entries[i].seen, 1); - - cl_assert_equal_i(n, ARRAY_SIZE(entries)); -} - -void test_strmap__iterating_empty_map_stops_immediately(void) -{ - size_t i = 0; - - cl_git_fail_with(git_strmap_iterate(NULL, g_table, &i, NULL), GIT_ITEROVER); -} From 9c1f4b4f6f87c35cbed9b781095215c773fd195c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 02:02:40 +0100 Subject: [PATCH 626/816] oidmap: remove now-unused oidmap --- src/libgit2/oidmap.c | 107 ----------------------------- src/libgit2/oidmap.h | 128 ----------------------------------- tests/libgit2/core/oidmap.c | 130 ------------------------------------ 3 files changed, 365 deletions(-) delete mode 100644 src/libgit2/oidmap.c delete mode 100644 src/libgit2/oidmap.h delete mode 100644 tests/libgit2/core/oidmap.c diff --git a/src/libgit2/oidmap.c b/src/libgit2/oidmap.c deleted file mode 100644 index eaf9fa051be..00000000000 --- a/src/libgit2/oidmap.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "oidmap.h" - -#define kmalloc git__malloc -#define kcalloc git__calloc -#define krealloc git__realloc -#define kreallocarray git__reallocarray -#define kfree git__free -#include "khash.h" - -__KHASH_TYPE(oid, const git_oid *, void *) - -GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) -{ - khint_t h; - memcpy(&h, oid->id, sizeof(khint_t)); - return h; -} - -__KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) - -int git_oidmap_new(git_oidmap **out) -{ - *out = kh_init(oid); - GIT_ERROR_CHECK_ALLOC(*out); - - return 0; -} - -void git_oidmap_free(git_oidmap *map) -{ - kh_destroy(oid, map); -} - -void git_oidmap_clear(git_oidmap *map) -{ - kh_clear(oid, map); -} - -size_t git_oidmap_size(git_oidmap *map) -{ - return kh_size(map); -} - -void *git_oidmap_get(git_oidmap *map, const git_oid *key) -{ - size_t idx = kh_get(oid, map, key); - if (idx == kh_end(map) || !kh_exist(map, idx)) - return NULL; - return kh_val(map, idx); -} - -int git_oidmap_set(git_oidmap *map, const git_oid *key, void *value) -{ - size_t idx; - int rval; - - idx = kh_put(oid, map, key, &rval); - if (rval < 0) - return -1; - - if (rval == 0) - kh_key(map, idx) = key; - - kh_val(map, idx) = value; - - return 0; -} - -int git_oidmap_delete(git_oidmap *map, const git_oid *key) -{ - khiter_t idx = kh_get(oid, map, key); - if (idx == kh_end(map)) - return GIT_ENOTFOUND; - kh_del(oid, map, idx); - return 0; -} - -int git_oidmap_exists(git_oidmap *map, const git_oid *key) -{ - return kh_get(oid, map, key) != kh_end(map); -} - -int git_oidmap_iterate(void **value, git_oidmap *map, size_t *iter, const git_oid **key) -{ - size_t i = *iter; - - while (i < map->n_buckets && !kh_exist(map, i)) - i++; - - if (i >= map->n_buckets) - return GIT_ITEROVER; - - if (key) - *key = kh_key(map, i); - if (value) - *value = kh_value(map, i); - *iter = ++i; - - return 0; -} diff --git a/src/libgit2/oidmap.h b/src/libgit2/oidmap.h deleted file mode 100644 index b748f727c5e..00000000000 --- a/src/libgit2/oidmap.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_oidmap_h__ -#define INCLUDE_oidmap_h__ - -#include "common.h" - -#include "git2/oid.h" - -/** A map with `git_oid`s as key. */ -typedef struct kh_oid_s git_oidmap; - -/** - * Allocate a new OID map. - * - * @param out Pointer to the map that shall be allocated. - * @return 0 on success, an error code if allocation has failed. - */ -int git_oidmap_new(git_oidmap **out); - -/** - * Free memory associated with the map. - * - * Note that this function will _not_ free values added to this - * map. - * - * @param map Pointer to the map that is to be free'd. May be - * `NULL`. - */ -void git_oidmap_free(git_oidmap *map); - -/** - * Clear all entries from the map. - * - * This function will remove all entries from the associated map. - * Memory associated with it will not be released, though. - * - * @param map Pointer to the map that shall be cleared. May be - * `NULL`. - */ -void git_oidmap_clear(git_oidmap *map); - -/** - * Return the number of elements in the map. - * - * @parameter map map containing the elements - * @return number of elements in the map - */ -size_t git_oidmap_size(git_oidmap *map); - -/** - * Return value associated with the given key. - * - * @param map map to search key in - * @param key key to search for - * @return value associated with the given key or NULL if the key was not found - */ -void *git_oidmap_get(git_oidmap *map, const git_oid *key); - -/** - * Set the entry for key to value. - * - * If the map has no corresponding entry for the given key, a new - * entry will be created with the given value. If an entry exists - * already, its value will be updated to match the given value. - * - * @param map map to create new entry in - * @param key key to set - * @param value value to associate the key with; may be NULL - * @return zero if the key was successfully set, a negative error - * code otherwise - */ -int git_oidmap_set(git_oidmap *map, const git_oid *key, void *value); - -/** - * Delete an entry from the map. - * - * Delete the given key and its value from the map. If no such - * key exists, this will do nothing. - * - * @param map map to delete key in - * @param key key to delete - * @return `0` if the key has been deleted, GIT_ENOTFOUND if no - * such key was found, a negative code in case of an - * error - */ -int git_oidmap_delete(git_oidmap *map, const git_oid *key); - -/** - * Check whether a key exists in the given map. - * - * @param map map to query for the key - * @param key key to search for - * @return 0 if the key has not been found, 1 otherwise - */ -int git_oidmap_exists(git_oidmap *map, const git_oid *key); - -/** - * Iterate over entries of the map. - * - * This functions allows to iterate over all key-value entries of - * the map. The current position is stored in the `iter` variable - * and should be initialized to `0` before the first call to this - * function. - * - * @param map map to iterate over - * @param value pointer to the variable where to store the current - * value. May be NULL. - * @param iter iterator storing the current position. Initialize - * with zero previous to the first call. - * @param key pointer to the variable where to store the current - * key. May be NULL. - * @return `0` if the next entry was correctly retrieved. - * GIT_ITEROVER if no entries are left. A negative error - * code otherwise. - */ -int git_oidmap_iterate(void **value, git_oidmap *map, size_t *iter, const git_oid **key); - -#define git_oidmap_foreach_value(h, vvar, code) { size_t __i = 0; \ - while (git_oidmap_iterate((void **) &(vvar), h, &__i, NULL) == 0) { \ - code; \ - } } - -#endif diff --git a/tests/libgit2/core/oidmap.c b/tests/libgit2/core/oidmap.c deleted file mode 100644 index 34374ceefa4..00000000000 --- a/tests/libgit2/core/oidmap.c +++ /dev/null @@ -1,130 +0,0 @@ -#include "clar_libgit2.h" -#include "oidmap.h" - -static struct { - git_oid oid; - size_t extra; -} test_oids[0x0FFF]; - -static git_oidmap *g_map; - -void test_core_oidmap__initialize(void) -{ - uint32_t i, j; - for (i = 0; i < ARRAY_SIZE(test_oids); ++i) { - uint32_t segment = i / 8; - int modi = i - (segment * 8); - - test_oids[i].extra = i; - - for (j = 0; j < GIT_OID_SHA1_SIZE / 4; ++j) { - test_oids[i].oid.id[j * 4 ] = (unsigned char)modi; - test_oids[i].oid.id[j * 4 + 1] = (unsigned char)(modi >> 8); - test_oids[i].oid.id[j * 4 + 2] = (unsigned char)(modi >> 16); - test_oids[i].oid.id[j * 4 + 3] = (unsigned char)(modi >> 24); - } - - test_oids[i].oid.id[ 8] = (unsigned char)i; - test_oids[i].oid.id[ 9] = (unsigned char)(i >> 8); - test_oids[i].oid.id[10] = (unsigned char)(i >> 16); - test_oids[i].oid.id[11] = (unsigned char)(i >> 24); -#ifdef GIT_EXPERIMENTAL_SHA256 - test_oids[i].oid.type = GIT_OID_SHA1; -#endif - } - - cl_git_pass(git_oidmap_new(&g_map)); -} - -void test_core_oidmap__cleanup(void) -{ - git_oidmap_free(g_map); -} - -void test_core_oidmap__basic(void) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(test_oids); ++i) { - cl_assert(!git_oidmap_exists(g_map, &test_oids[i].oid)); - cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i])); - } - - for (i = 0; i < ARRAY_SIZE(test_oids); ++i) { - cl_assert(git_oidmap_exists(g_map, &test_oids[i].oid)); - cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[i].oid), &test_oids[i]); - } -} - -void test_core_oidmap__hash_collision(void) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(test_oids); ++i) { - cl_assert(!git_oidmap_exists(g_map, &test_oids[i].oid)); - cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i])); - } - - for (i = 0; i < ARRAY_SIZE(test_oids); ++i) { - cl_assert(git_oidmap_exists(g_map, &test_oids[i].oid)); - cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[i].oid), &test_oids[i]); - } -} - -void test_core_oidmap__get_succeeds_with_existing_keys(void) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(test_oids); ++i) - cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i])); - - for (i = 0; i < ARRAY_SIZE(test_oids); ++i) - cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[i].oid), &test_oids[i]); -} - -void test_core_oidmap__get_fails_with_nonexisting_key(void) -{ - size_t i; - - /* Do _not_ add last OID to verify that we cannot look it up */ - for (i = 0; i < ARRAY_SIZE(test_oids) - 1; ++i) - cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i])); - - cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[ARRAY_SIZE(test_oids) - 1].oid), NULL); -} - -void test_core_oidmap__setting_oid_persists(void) -{ - git_oid oids[] = { - GIT_OID_INIT(GIT_OID_SHA1, { 0x01 }), - GIT_OID_INIT(GIT_OID_SHA1, { 0x02 }), - GIT_OID_INIT(GIT_OID_SHA1, { 0x03 }) - }; - - cl_git_pass(git_oidmap_set(g_map, &oids[0], "one")); - cl_git_pass(git_oidmap_set(g_map, &oids[1], "two")); - cl_git_pass(git_oidmap_set(g_map, &oids[2], "three")); - - cl_assert_equal_s(git_oidmap_get(g_map, &oids[0]), "one"); - cl_assert_equal_s(git_oidmap_get(g_map, &oids[1]), "two"); - cl_assert_equal_s(git_oidmap_get(g_map, &oids[2]), "three"); -} - -void test_core_oidmap__setting_existing_key_updates(void) -{ - git_oid oids[] = { - GIT_OID_INIT(GIT_OID_SHA1, { 0x01 }), - GIT_OID_INIT(GIT_OID_SHA1, { 0x02 }), - GIT_OID_INIT(GIT_OID_SHA1, { 0x03 }) - }; - - cl_git_pass(git_oidmap_set(g_map, &oids[0], "one")); - cl_git_pass(git_oidmap_set(g_map, &oids[1], "two")); - cl_git_pass(git_oidmap_set(g_map, &oids[2], "three")); - cl_assert_equal_i(git_oidmap_size(g_map), 3); - - cl_git_pass(git_oidmap_set(g_map, &oids[1], "other")); - cl_assert_equal_i(git_oidmap_size(g_map), 3); - - cl_assert_equal_s(git_oidmap_get(g_map, &oids[1]), "other"); -} From 7ca51a806c2b18c30a9c5b38fabeaa8e4e34c715 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 02:03:54 +0100 Subject: [PATCH 627/816] util: remove now-used khash.h --- src/util/khash.h | 615 ----------------------------------------------- 1 file changed, 615 deletions(-) delete mode 100644 src/util/khash.h diff --git a/src/util/khash.h b/src/util/khash.h deleted file mode 100644 index c9b7f131f0a..00000000000 --- a/src/util/khash.h +++ /dev/null @@ -1,615 +0,0 @@ -/* The MIT License - - Copyright (c) 2008, 2009, 2011 by Attractive Chaos - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -/* - An example: - -#include "khash.h" -KHASH_MAP_INIT_INT(32, char) -int main() { - int ret, is_missing; - khiter_t k; - khash_t(32) *h = kh_init(32); - k = kh_put(32, h, 5, &ret); - kh_value(h, k) = 10; - k = kh_get(32, h, 10); - is_missing = (k == kh_end(h)); - k = kh_get(32, h, 5); - kh_del(32, h, k); - for (k = kh_begin(h); k != kh_end(h); ++k) - if (kh_exist(h, k)) kh_value(h, k) = 1; - kh_destroy(32, h); - return 0; -} -*/ - -/* - 2013-05-02 (0.2.8): - - * Use quadratic probing. When the capacity is power of 2, stepping function - i*(i+1)/2 guarantees to traverse each bucket. It is better than double - hashing on cache performance and is more robust than linear probing. - - In theory, double hashing should be more robust than quadratic probing. - However, my implementation is probably not for large hash tables, because - the second hash function is closely tied to the first hash function, - which reduce the effectiveness of double hashing. - - Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php - - 2011-12-29 (0.2.7): - - * Minor code clean up; no actual effect. - - 2011-09-16 (0.2.6): - - * The capacity is a power of 2. This seems to dramatically improve the - speed for simple keys. Thank Zilong Tan for the suggestion. Reference: - - - http://code.google.com/p/ulib/ - - http://nothings.org/computer/judy/ - - * Allow to optionally use linear probing which usually has better - performance for random input. Double hashing is still the default as it - is more robust to certain non-random input. - - * Added Wang's integer hash function (not used by default). This hash - function is more robust to certain non-random input. - - 2011-02-14 (0.2.5): - - * Allow to declare global functions. - - 2009-09-26 (0.2.4): - - * Improve portability - - 2008-09-19 (0.2.3): - - * Corrected the example - * Improved interfaces - - 2008-09-11 (0.2.2): - - * Improved speed a little in kh_put() - - 2008-09-10 (0.2.1): - - * Added kh_clear() - * Fixed a compiling error - - 2008-09-02 (0.2.0): - - * Changed to token concatenation which increases flexibility. - - 2008-08-31 (0.1.2): - - * Fixed a bug in kh_get(), which has not been tested previously. - - 2008-08-31 (0.1.1): - - * Added destructor -*/ - - -#ifndef __AC_KHASH_H -#define __AC_KHASH_H - -/*! - @header - - Generic hash table library. - */ - -#define AC_VERSION_KHASH_H "0.2.8" - -#include -#include -#include - -/* compiler specific configuration */ - -typedef uint32_t khint32_t; -typedef uint64_t khint64_t; - -#ifndef kh_inline -#ifdef _MSC_VER -#define kh_inline __inline -#elif defined(__GNUC__) -#define kh_inline __inline__ -#else -#define kh_inline -#endif -#endif /* kh_inline */ - -typedef khint32_t khint_t; -typedef khint_t khiter_t; - -#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) -#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) -#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) -#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) -#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) -#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) -#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) - -#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) - -#ifndef kroundup32 -#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) -#endif - -#ifndef kcalloc -#define kcalloc(N,Z) calloc(N,Z) -#endif -#ifndef kmalloc -#define kmalloc(Z) malloc(Z) -#endif -#ifndef krealloc -#define krealloc(P,Z) realloc(P,Z) -#endif -#ifndef kreallocarray -#define kreallocarray(P,N,Z) ((SIZE_MAX - N < Z) ? NULL : krealloc(P, (N*Z))) -#endif -#ifndef kfree -#define kfree(P) free(P) -#endif - -static const double __ac_HASH_UPPER = 0.77; - -#define __KHASH_TYPE(name, khkey_t, khval_t) \ - typedef struct kh_##name##_s { \ - khint_t n_buckets, size, n_occupied, upper_bound; \ - khint32_t *flags; \ - khkey_t *keys; \ - khval_t *vals; \ - } kh_##name##_t; - -#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ - extern kh_##name##_t *kh_init_##name(void); \ - extern void kh_destroy_##name(kh_##name##_t *h); \ - extern void kh_clear_##name(kh_##name##_t *h); \ - extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ - extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ - extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ - extern void kh_del_##name(kh_##name##_t *h, khint_t x); - -#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ - SCOPE kh_##name##_t *kh_init_##name(void) { \ - return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \ - } \ - SCOPE void kh_destroy_##name(kh_##name##_t *h) \ - { \ - if (h) { \ - kfree((void *)h->keys); kfree(h->flags); \ - kfree((void *)h->vals); \ - kfree(h); \ - } \ - } \ - SCOPE void kh_clear_##name(kh_##name##_t *h) \ - { \ - if (h && h->flags) { \ - memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ - h->size = h->n_occupied = 0; \ - } \ - } \ - SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ - { \ - if (h->n_buckets) { \ - khint_t k, i, last, mask, step = 0; \ - mask = h->n_buckets - 1; \ - k = __hash_func(key); i = k & mask; \ - last = i; \ - while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ - i = (i + (++step)) & mask; \ - if (i == last) return h->n_buckets; \ - } \ - return __ac_iseither(h->flags, i)? h->n_buckets : i; \ - } else return 0; \ - } \ - SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ - { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ - khint32_t *new_flags = 0; \ - khint_t j = 1; \ - { \ - kroundup32(new_n_buckets); \ - if (new_n_buckets < 4) new_n_buckets = 4; \ - if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ - else { /* hash table size to be changed (shrink or expand); rehash */ \ - new_flags = (khint32_t*)kreallocarray(NULL, __ac_fsize(new_n_buckets), sizeof(khint32_t)); \ - if (!new_flags) return -1; \ - memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ - if (h->n_buckets < new_n_buckets) { /* expand */ \ - khkey_t *new_keys = (khkey_t*)kreallocarray((void *)h->keys, new_n_buckets, sizeof(khkey_t)); \ - if (!new_keys) { kfree(new_flags); return -1; } \ - h->keys = new_keys; \ - if (kh_is_map) { \ - khval_t *new_vals = (khval_t*)kreallocarray((void *)h->vals, new_n_buckets, sizeof(khval_t)); \ - if (!new_vals) { kfree(new_flags); return -1; } \ - h->vals = new_vals; \ - } \ - } /* otherwise shrink */ \ - } \ - } \ - if (j) { /* rehashing is needed */ \ - for (j = 0; j != h->n_buckets; ++j) { \ - if (__ac_iseither(h->flags, j) == 0) { \ - khkey_t key = h->keys[j]; \ - khval_t val; \ - khint_t new_mask; \ - new_mask = new_n_buckets - 1; \ - if (kh_is_map) val = h->vals[j]; \ - __ac_set_isdel_true(h->flags, j); \ - while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ - khint_t k, i, step = 0; \ - k = __hash_func(key); \ - i = k & new_mask; \ - while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \ - __ac_set_isempty_false(new_flags, i); \ - if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ - { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ - if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \ - __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \ - } else { /* write the element and jump out of the loop */ \ - h->keys[i] = key; \ - if (kh_is_map) h->vals[i] = val; \ - break; \ - } \ - } \ - } \ - } \ - if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ - h->keys = (khkey_t*)kreallocarray((void *)h->keys, new_n_buckets, sizeof(khkey_t)); \ - if (kh_is_map) h->vals = (khval_t*)kreallocarray((void *)h->vals, new_n_buckets, sizeof(khval_t)); \ - } \ - kfree(h->flags); /* free the working space */ \ - h->flags = new_flags; \ - h->n_buckets = new_n_buckets; \ - h->n_occupied = h->size; \ - h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ - } \ - return 0; \ - } \ - SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ - { \ - khint_t x; \ - if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ - if (h->n_buckets > (h->size<<1)) { \ - if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \ - *ret = -1; return h->n_buckets; \ - } \ - } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \ - *ret = -1; return h->n_buckets; \ - } \ - } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ - { \ - khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ - x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \ - if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \ - else { \ - last = i; \ - while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ - if (__ac_isdel(h->flags, i)) site = i; \ - i = (i + (++step)) & mask; \ - if (i == last) { x = site; break; } \ - } \ - if (x == h->n_buckets) { \ - if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \ - else x = i; \ - } \ - } \ - } \ - if (__ac_isempty(h->flags, x)) { /* not present at all */ \ - h->keys[x] = key; \ - __ac_set_isboth_false(h->flags, x); \ - ++h->size; ++h->n_occupied; \ - *ret = 1; \ - } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ - h->keys[x] = key; \ - __ac_set_isboth_false(h->flags, x); \ - ++h->size; \ - *ret = 2; \ - } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ - return x; \ - } \ - SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ - { \ - if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ - __ac_set_isdel_true(h->flags, x); \ - --h->size; \ - } \ - } - -#define KHASH_DECLARE(name, khkey_t, khval_t) \ - __KHASH_TYPE(name, khkey_t, khval_t) \ - __KHASH_PROTOTYPES(name, khkey_t, khval_t) - -#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ - __KHASH_TYPE(name, khkey_t, khval_t) \ - __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) - -#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ - KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) - -/* --- BEGIN OF HASH FUNCTIONS --- */ - -/*! @function - @abstract Integer hash function - @param key The integer [khint32_t] - @return The hash value [khint_t] - */ -#define kh_int_hash_func(key) (khint32_t)(key) -/*! @function - @abstract Integer comparison function - */ -#define kh_int_hash_equal(a, b) ((a) == (b)) -/*! @function - @abstract 64-bit integer hash function - @param key The integer [khint64_t] - @return The hash value [khint_t] - */ -#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11) -/*! @function - @abstract 64-bit integer comparison function - */ -#define kh_int64_hash_equal(a, b) ((a) == (b)) -/*! @function - @abstract const char* hash function - @param s Pointer to a null terminated string - @return The hash value - */ -static kh_inline khint_t __ac_X31_hash_string(const char *s) -{ - khint_t h = (khint_t)*s; - if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s; - return h; -} -/*! @function - @abstract Another interface to const char* hash function - @param key Pointer to a null terminated string [const char*] - @return The hash value [khint_t] - */ -#define kh_str_hash_func(key) __ac_X31_hash_string(key) -/*! @function - @abstract Const char* comparison function - */ -#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) - -static kh_inline khint_t __ac_Wang_hash(khint_t key) -{ - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - return key; -} -#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key) - -/* --- END OF HASH FUNCTIONS --- */ - -/* Other convenient macros... */ - -/*! - @abstract Type of the hash table. - @param name Name of the hash table [symbol] - */ -#define khash_t(name) kh_##name##_t - -/*! @function - @abstract Initiate a hash table. - @param name Name of the hash table [symbol] - @return Pointer to the hash table [khash_t(name)*] - */ -#define kh_init(name) kh_init_##name() - -/*! @function - @abstract Destroy a hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - */ -#define kh_destroy(name, h) kh_destroy_##name(h) - -/*! @function - @abstract Reset a hash table without deallocating memory. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - */ -#define kh_clear(name, h) kh_clear_##name(h) - -/*! @function - @abstract Resize a hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param s New size [khint_t] - */ -#define kh_resize(name, h, s) kh_resize_##name(h, s) - -/*! @function - @abstract Insert a key to the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Key [type of keys] - @param r Extra return code: -1 if the operation failed; - 0 if the key is present in the hash table; - 1 if the bucket is empty (never used); 2 if the element in - the bucket has been deleted [int*] - @return Iterator to the inserted element [khint_t] - */ -#define kh_put(name, h, k, r) kh_put_##name(h, k, r) - -/*! @function - @abstract Retrieve a key from the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Key [type of keys] - @return Iterator to the found element, or kh_end(h) if the element is absent [khint_t] - */ -#define kh_get(name, h, k) kh_get_##name(h, k) - -/*! @function - @abstract Remove a key from the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Iterator to the element to be deleted [khint_t] - */ -#define kh_del(name, h, k) kh_del_##name(h, k) - -/*! @function - @abstract Test whether a bucket contains data. - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return 1 if containing data; 0 otherwise [int] - */ -#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x))) - -/*! @function - @abstract Get key given an iterator - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return Key [type of keys] - */ -#define kh_key(h, x) ((h)->keys[x]) - -/*! @function - @abstract Get value given an iterator - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return Value [type of values] - @discussion For hash sets, calling this results in segfault. - */ -#define kh_val(h, x) ((h)->vals[x]) - -/*! @function - @abstract Alias of kh_val() - */ -#define kh_value(h, x) ((h)->vals[x]) - -/*! @function - @abstract Get the start iterator - @param h Pointer to the hash table [khash_t(name)*] - @return The start iterator [khint_t] - */ -#define kh_begin(h) (khint_t)(0) - -/*! @function - @abstract Get the end iterator - @param h Pointer to the hash table [khash_t(name)*] - @return The end iterator [khint_t] - */ -#define kh_end(h) ((h)->n_buckets) - -/*! @function - @abstract Get the number of elements in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @return Number of elements in the hash table [khint_t] - */ -#define kh_size(h) ((h)->size) - -/*! @function - @abstract Get the number of buckets in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @return Number of buckets in the hash table [khint_t] - */ -#define kh_n_buckets(h) ((h)->n_buckets) - -/*! @function - @abstract Iterate over the entries in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @param kvar Variable to which key will be assigned - @param vvar Variable to which value will be assigned - @param code Block of code to execute - */ -#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \ - for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ - if (!kh_exist(h,__i)) continue; \ - (kvar) = kh_key(h,__i); \ - (vvar) = kh_val(h,__i); \ - code; \ - } } - -/*! @function - @abstract Iterate over the values in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @param vvar Variable to which value will be assigned - @param code Block of code to execute - */ -#define kh_foreach_value(h, vvar, code) { khint_t __i; \ - for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ - if (!kh_exist(h,__i)) continue; \ - (vvar) = kh_val(h,__i); \ - code; \ - } } - -/* More convenient interfaces */ - -/*! @function - @abstract Instantiate a hash set containing integer keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_INT(name) \ - KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing integer keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_INT(name, khval_t) \ - KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing 64-bit integer keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_INT64(name) \ - KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing 64-bit integer keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_INT64(name, khval_t) \ - KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) - -typedef const char *kh_cstr_t; -/*! @function - @abstract Instantiate a hash map containing const char* keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_STR(name) \ - KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing const char* keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_STR(name, khval_t) \ - KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) - -#endif /* __AC_KHASH_H */ From 9d57a7aa8e680026248bc8e36e97ca4c10aeda2f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Oct 2024 02:29:21 +0100 Subject: [PATCH 628/816] hashmap_oid: introduce hashmap_oid A hashmap that uses git_oid's as keys. Move the hashcode function out of git_oid. --- src/libgit2/cache.c | 4 ++-- src/libgit2/cache.h | 4 ++-- src/libgit2/commit_graph.c | 2 +- src/libgit2/describe.c | 4 ++-- src/libgit2/grafts.c | 4 ++-- src/libgit2/hashmap_oid.h | 30 ++++++++++++++++++++++++++++++ src/libgit2/indexer.c | 4 ++-- src/libgit2/merge.c | 2 +- src/libgit2/odb_mempack.c | 2 +- src/libgit2/oid.h | 16 ---------------- src/libgit2/pack-objects.c | 4 ++-- src/libgit2/pack-objects.h | 6 +++--- src/libgit2/pack.c | 3 ++- src/libgit2/pack.h | 5 +++-- src/libgit2/revwalk.c | 3 ++- src/libgit2/revwalk.h | 4 ++-- 16 files changed, 57 insertions(+), 40 deletions(-) create mode 100644 src/libgit2/hashmap_oid.h diff --git a/src/libgit2/cache.c b/src/libgit2/cache.c index b544fa331b3..629c56387e0 100644 --- a/src/libgit2/cache.c +++ b/src/libgit2/cache.c @@ -14,9 +14,9 @@ #include "odb.h" #include "object.h" #include "git2/oid.h" -#include "hashmap.h" +#include "hashmap_oid.h" -GIT_HASHMAP_FUNCTIONS(git_cache_oidmap, GIT_HASHMAP_INLINE, const git_oid *, git_cached_obj *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_FUNCTIONS(git_cache_oidmap, GIT_HASHMAP_INLINE, git_cached_obj *); bool git_cache__enabled = true; ssize_t git_cache__max_storage = (256 * 1024 * 1024); diff --git a/src/libgit2/cache.h b/src/libgit2/cache.h index d6bf2851efc..4c14013a300 100644 --- a/src/libgit2/cache.h +++ b/src/libgit2/cache.h @@ -14,7 +14,7 @@ #include "git2/odb.h" #include "thread.h" -#include "hashmap.h" +#include "hashmap_oid.h" enum { GIT_CACHE_STORE_ANY = 0, @@ -30,7 +30,7 @@ typedef struct { git_atomic32 refcount; } git_cached_obj; -GIT_HASHMAP_STRUCT(git_cache_oidmap, const git_oid *, git_cached_obj *); +GIT_HASHMAP_OID_STRUCT(git_cache_oidmap, git_cached_obj *); typedef struct { git_cache_oidmap map; diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index 948a921b327..e8d64de3a60 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -839,7 +839,7 @@ enum generation_number_commit_state { GENERATION_NUMBER_COMMIT_STATE_VISITED = 3 }; -GIT_HASHMAP_SETUP(git_commit_graph_oidmap, const git_oid *, struct packed_commit *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_SETUP(git_commit_graph_oidmap, struct packed_commit *); static int compute_generation_numbers(git_vector *commits) { diff --git a/src/libgit2/describe.c b/src/libgit2/describe.c index 5964ff87389..dfbe7b4ab0b 100644 --- a/src/libgit2/describe.c +++ b/src/libgit2/describe.c @@ -21,7 +21,7 @@ #include "tag.h" #include "vector.h" #include "wildmatch.h" -#include "hashmap.h" +#include "hashmap_oid.h" /* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */ @@ -36,7 +36,7 @@ struct commit_name { git_oid peeled; }; -GIT_HASHMAP_SETUP(git_describe_oidmap, const git_oid *, struct commit_name *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_SETUP(git_describe_oidmap, struct commit_name *); static struct commit_name *find_commit_name( git_describe_oidmap *names, diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c index 9ead540e1e9..d31b4efddf9 100644 --- a/src/libgit2/grafts.c +++ b/src/libgit2/grafts.c @@ -11,9 +11,9 @@ #include "oid.h" #include "oidarray.h" #include "parse.h" -#include "hashmap.h" +#include "hashmap_oid.h" -GIT_HASHMAP_SETUP(git_grafts_oidmap, const git_oid *, git_commit_graft *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_SETUP(git_grafts_oidmap, git_commit_graft *); struct git_grafts { /* Map of `git_commit_graft`s */ diff --git a/src/libgit2/hashmap_oid.h b/src/libgit2/hashmap_oid.h new file mode 100644 index 00000000000..cb1143cc760 --- /dev/null +++ b/src/libgit2/hashmap_oid.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_hashmap_oid_h__ +#define INCLUDE_hashmap_oid_h__ + +#include "hashmap.h" + +GIT_INLINE(uint32_t) git_hashmap_oid_hashcode(const git_oid *oid) +{ + uint32_t hash; + memcpy(&hash, oid->id, sizeof(uint32_t)); + return hash; +} + +#define GIT_HASHMAP_OID_STRUCT(name, val_t) \ + GIT_HASHMAP_STRUCT(name, const git_oid *, val_t) +#define GIT_HASHMAP_OID_PROTOTYPES(name, val_t) \ + GIT_HASHMAP_PROTOTYPES(name, const git_oid *, val_t) +#define GIT_HASHMAP_OID_FUNCTIONS(name, scope, val_t) \ + GIT_HASHMAP_FUNCTIONS(name, scope, const git_oid *, val_t, git_hashmap_oid_hashcode, git_oid_equal) + +#define GIT_HASHMAP_OID_SETUP(name, val_t) \ + GIT_HASHMAP_OID_STRUCT(name, val_t) \ + GIT_HASHMAP_OID_FUNCTIONS(name, GIT_HASHMAP_INLINE, val_t) + +#endif diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index accb0812f0b..32a37e0670a 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -22,13 +22,13 @@ #include "oidarray.h" #include "zstream.h" #include "object.h" -#include "hashmap.h" +#include "hashmap_oid.h" size_t git_indexer__max_objects = UINT32_MAX; #define UINT31_MAX (0x7FFFFFFF) -GIT_HASHMAP_SETUP(git_indexer_oidmap, const git_oid *, git_oid *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_SETUP(git_indexer_oidmap, git_oid *); struct entry { git_oid oid; diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 17cbc16117f..5f90a8bf87e 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -1143,7 +1143,7 @@ typedef struct { size_t first_entry; } deletes_by_oid_queue; -GIT_HASHMAP_SETUP(git_merge_deletes_oidmap, const git_oid *, deletes_by_oid_queue *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_SETUP(git_merge_deletes_oidmap, deletes_by_oid_queue *); static void deletes_by_oid_dispose(git_merge_deletes_oidmap *map) { diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c index e1ee72cdb55..c6210cec60b 100644 --- a/src/libgit2/odb_mempack.c +++ b/src/libgit2/odb_mempack.c @@ -28,7 +28,7 @@ struct memobject { char data[GIT_FLEX_ARRAY]; }; -GIT_HASHMAP_SETUP(git_odb_mempack_oidmap, const git_oid *, struct memobject *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_SETUP(git_odb_mempack_oidmap, struct memobject *); struct memory_packer_db { git_odb_backend parent; diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h index d6a681caf58..f25a899a681 100644 --- a/src/libgit2/oid.h +++ b/src/libgit2/oid.h @@ -256,22 +256,6 @@ GIT_INLINE(void) git_oid_clear(git_oid *out, git_oid_t type) #endif } -/* A 32 bit representation suitable for a hashmap key */ -GIT_INLINE(uint32_t) git_oid_hash32(const git_oid *oid) -{ - uint32_t hash; - memcpy(&hash, oid->id, sizeof(uint32_t)); - return hash; -} - -/* A 64 bit representation suitable for a hashmap key */ -GIT_INLINE(uint64_t) git_oid_hash64(const git_oid *oid) -{ - uint64_t hash; - memcpy(&hash, oid->id, sizeof(uint64_t)); - return hash; -} - /* SHA256 support */ int git_oid__fromstr(git_oid *out, const char *str, git_oid_t type); diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index 44c591555aa..298e70aa605 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -64,8 +64,8 @@ struct walk_object { /* Size of the buffer to feed to zlib */ #define COMPRESS_BUFLEN (1024 * 1024) -GIT_HASHMAP_FUNCTIONS(git_packbuilder_pobjectmap, GIT_HASHMAP_INLINE, const git_oid *, git_pobject *, git_oid_hash32, git_oid_equal); -GIT_HASHMAP_FUNCTIONS(git_packbuilder_walk_objectmap, GIT_HASHMAP_INLINE, const git_oid *, struct walk_object *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_FUNCTIONS(git_packbuilder_pobjectmap, GIT_HASHMAP_INLINE, git_pobject *); +GIT_HASHMAP_OID_FUNCTIONS(git_packbuilder_walk_objectmap, GIT_HASHMAP_INLINE, struct walk_object *); static unsigned name_hash(const char *name) { diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h index da726c714ce..ad04fb0abc6 100644 --- a/src/libgit2/pack-objects.h +++ b/src/libgit2/pack-objects.h @@ -15,7 +15,7 @@ #include "zstream.h" #include "pool.h" #include "indexer.h" -#include "hashmap.h" +#include "hashmap_oid.h" #include "git2/oid.h" #include "git2/pack.h" @@ -53,8 +53,8 @@ typedef struct git_pobject { typedef struct walk_object walk_object; -GIT_HASHMAP_STRUCT(git_packbuilder_pobjectmap, const git_oid *, git_pobject *); -GIT_HASHMAP_STRUCT(git_packbuilder_walk_objectmap, const git_oid *, walk_object *); +GIT_HASHMAP_OID_STRUCT(git_packbuilder_pobjectmap, git_pobject *); +GIT_HASHMAP_OID_STRUCT(git_packbuilder_walk_objectmap, walk_object *); struct git_packbuilder { git_repository *repo; /* associated repository */ diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index 0688e6aa927..8bdaac3a8d3 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -13,6 +13,7 @@ #include "odb.h" #include "oid.h" #include "oidarray.h" +#include "hashmap_oid.h" /* Option to bypass checking existence of '.keep' files */ bool git_disable_pack_keep_file_checks = false; @@ -45,7 +46,7 @@ static int pack_entry_find_offset( #define off64_equal(a, b) ((a) == (b)) GIT_HASHMAP_FUNCTIONS(git_pack_offsetmap, GIT_HASHMAP_INLINE, off64_t, git_pack_cache_entry *, off64_hash, off64_equal); -GIT_HASHMAP_FUNCTIONS(git_pack_oidmap, , const git_oid *, struct git_pack_entry *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_FUNCTIONS(git_pack_oidmap, , struct git_pack_entry *); static int packfile_error(const char *message) { diff --git a/src/libgit2/pack.h b/src/libgit2/pack.h index 8e0cba15f2c..4fd092149b3 100644 --- a/src/libgit2/pack.h +++ b/src/libgit2/pack.h @@ -18,6 +18,7 @@ #include "odb.h" #include "zstream.h" #include "oid.h" +#include "hashmap_oid.h" /** * Function type for callbacks from git_pack_foreach_entry_offset. @@ -89,8 +90,8 @@ struct git_pack_entry { GIT_HASHMAP_STRUCT(git_pack_offsetmap, off64_t, git_pack_cache_entry *); -GIT_HASHMAP_STRUCT(git_pack_oidmap, const git_oid *, struct git_pack_entry *); -GIT_HASHMAP_PROTOTYPES(git_pack_oidmap, const git_oid *, struct git_pack_entry *); +GIT_HASHMAP_OID_STRUCT(git_pack_oidmap, struct git_pack_entry *); +GIT_HASHMAP_OID_PROTOTYPES(git_pack_oidmap, struct git_pack_entry *); typedef struct { size_t memory_used; diff --git a/src/libgit2/revwalk.c b/src/libgit2/revwalk.c index 7dd31f92fd1..a793a8e179c 100644 --- a/src/libgit2/revwalk.c +++ b/src/libgit2/revwalk.c @@ -14,8 +14,9 @@ #include "git2/revparse.h" #include "merge.h" #include "vector.h" +#include "hashmap_oid.h" -GIT_HASHMAP_FUNCTIONS(git_revwalk_oidmap, GIT_HASHMAP_INLINE, const git_oid *, git_commit_list_node *, git_oid_hash32, git_oid_equal); +GIT_HASHMAP_OID_FUNCTIONS(git_revwalk_oidmap, GIT_HASHMAP_INLINE, git_commit_list_node *); static int get_revision(git_commit_list_node **out, git_revwalk *walk, git_commit_list **list); diff --git a/src/libgit2/revwalk.h b/src/libgit2/revwalk.h index 31c01d2e628..632b2807cd8 100644 --- a/src/libgit2/revwalk.h +++ b/src/libgit2/revwalk.h @@ -14,9 +14,9 @@ #include "pqueue.h" #include "pool.h" #include "vector.h" -#include "hashmap.h" +#include "hashmap_oid.h" -GIT_HASHMAP_STRUCT(git_revwalk_oidmap, const git_oid *, git_commit_list_node *); +GIT_HASHMAP_OID_STRUCT(git_revwalk_oidmap, git_commit_list_node *); struct git_revwalk { git_repository *repo; From a9ba0299e2f9b849189df6992b750960328bc88f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 4 Oct 2024 21:56:11 +0100 Subject: [PATCH 629/816] hashmap: add some asserts Quiet down static code analysis. --- src/util/hashmap.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/util/hashmap.h b/src/util/hashmap.h index b5fd9bce187..dbb88f665c5 100644 --- a/src/util/hashmap.h +++ b/src/util/hashmap.h @@ -340,6 +340,9 @@ typedef uint32_t git_hashmap_iter_t; int error = name##__put_idx(&idx, &key_exists, h, key); \ if (error) \ return error; \ + GIT_ASSERT((h)->flags); \ + GIT_ASSERT((h)->keys); \ + GIT_ASSERT((h)->keys); \ if (!key_exists) \ (h)->keys[idx] = key; \ (h)->vals[idx] = val; \ @@ -382,8 +385,11 @@ typedef uint32_t git_hashmap_iter_t; int error = name##__put_idx(&idx, &key_exists, h, key); \ if (error) \ return error; \ - if (!key_exists) \ + GIT_ASSERT((h)->flags); \ + GIT_ASSERT((h)->keys); \ + if (!key_exists) { \ (h)->keys[idx] = key; \ + } \ return 0; \ } \ GIT_UNUSED_FUNCTION scope int name##_iterate(git_hashmap_iter_t *iter, key_t *key, name *h) \ From e7db282676056fef5ec3a1dbe58e41dc80a015c2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 4 Oct 2024 22:16:09 +0100 Subject: [PATCH 630/816] openssl: dynamic loading fixes --- src/libgit2/streams/openssl_dynamic.c | 2 ++ src/libgit2/streams/openssl_dynamic.h | 2 ++ tests/libgit2/online/customcert.c | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libgit2/streams/openssl_dynamic.c b/src/libgit2/streams/openssl_dynamic.c index fc65fc6195e..fe679526f9d 100644 --- a/src/libgit2/streams/openssl_dynamic.c +++ b/src/libgit2/streams/openssl_dynamic.c @@ -65,6 +65,7 @@ int (*SSL_write)(SSL *ssl, const void *buf, int num); long (*SSL_CTX_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg); void (*SSL_CTX_free)(SSL_CTX *ctx); SSL_CTX *(*SSL_CTX_new)(const SSL_METHOD *method); +X509_STORE *(*SSL_CTX_get_cert_store)(const SSL_CTX *); int (*SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); int (*SSL_CTX_set_default_verify_paths)(SSL_CTX *ctx); long (*SSL_CTX_set_options)(SSL_CTX *ctx, long options); @@ -195,6 +196,7 @@ int git_openssl_stream_dynamic_init(void) SSL_CTX_ctrl = (long (*)(SSL_CTX *, int, long, void *))openssl_sym(&err, "SSL_CTX_ctrl", true); SSL_CTX_free = (void (*)(SSL_CTX *))openssl_sym(&err, "SSL_CTX_free", true); SSL_CTX_new = (SSL_CTX *(*)(const SSL_METHOD *))openssl_sym(&err, "SSL_CTX_new", true); + SSL_CTX_get_cert_store = (X509_STORE *(*)(const SSL_CTX *))openssl_sym(&err, "SSL_CTX_get_cert_store", true); SSL_CTX_set_cipher_list = (int (*)(SSL_CTX *, const char *))openssl_sym(&err, "SSL_CTX_set_cipher_list", true); SSL_CTX_set_default_verify_paths = (int (*)(SSL_CTX *ctx))openssl_sym(&err, "SSL_CTX_set_default_verify_paths", true); SSL_CTX_set_options = (long (*)(SSL_CTX *, long))openssl_sym(&err, "SSL_CTX_set_options", false); diff --git a/src/libgit2/streams/openssl_dynamic.h b/src/libgit2/streams/openssl_dynamic.h index 34f7c749bf8..e59f1f93b2a 100644 --- a/src/libgit2/streams/openssl_dynamic.h +++ b/src/libgit2/streams/openssl_dynamic.h @@ -204,6 +204,7 @@ typedef void SSL_METHOD; typedef void X509; typedef void X509_NAME; typedef void X509_NAME_ENTRY; +typedef void X509_STORE; typedef void X509_STORE_CTX; typedef struct { @@ -309,6 +310,7 @@ extern int (*SSL_write)(SSL *ssl, const void *buf, int num); extern long (*SSL_CTX_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg); extern void (*SSL_CTX_free)(SSL_CTX *ctx); extern SSL_CTX *(*SSL_CTX_new)(const SSL_METHOD *method); +extern X509_STORE *(*SSL_CTX_get_cert_store)(const SSL_CTX *ctx); extern int (*SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); extern int (*SSL_CTX_set_default_verify_paths)(SSL_CTX *ctx); extern long (*SSL_CTX_set_options)(SSL_CTX *ctx, long options); diff --git a/tests/libgit2/online/customcert.c b/tests/libgit2/online/customcert.c index 3acb880641e..89694b5f4cf 100644 --- a/tests/libgit2/online/customcert.c +++ b/tests/libgit2/online/customcert.c @@ -10,7 +10,7 @@ #include "str.h" #include "streams/openssl.h" -#ifdef GIT_OPENSSL +#if (GIT_OPENSSL && !GIT_OPENSSL_DYNAMIC) # include # include # include @@ -91,7 +91,7 @@ void test_online_customcert__path(void) void test_online_customcert__raw_x509(void) { -#ifdef GIT_OPENSSL +#if (GIT_OPENSSL && !GIT_OPENSSL_DYNAMIC) X509* x509_cert = NULL; char cwd[GIT_PATH_MAX]; git_str raw_file = GIT_STR_INIT, From 6c547af7919f956a8dda5d197ef5cbc30fd57288 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 5 Oct 2024 12:17:05 +0100 Subject: [PATCH 631/816] hashmap: asserts Quiet down static code analysis. --- src/util/hashmap.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/util/hashmap.h b/src/util/hashmap.h index dbb88f665c5..9d164b90709 100644 --- a/src/util/hashmap.h +++ b/src/util/hashmap.h @@ -259,6 +259,8 @@ typedef uint32_t git_hashmap_iter_t; return -1; \ } \ } \ + GIT_ASSERT((h)->flags); \ + GIT_ASSERT((h)->keys); \ /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ { \ uint32_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ @@ -340,9 +342,7 @@ typedef uint32_t git_hashmap_iter_t; int error = name##__put_idx(&idx, &key_exists, h, key); \ if (error) \ return error; \ - GIT_ASSERT((h)->flags); \ - GIT_ASSERT((h)->keys); \ - GIT_ASSERT((h)->keys); \ + GIT_ASSERT((h)->vals); \ if (!key_exists) \ (h)->keys[idx] = key; \ (h)->vals[idx] = val; \ @@ -385,8 +385,6 @@ typedef uint32_t git_hashmap_iter_t; int error = name##__put_idx(&idx, &key_exists, h, key); \ if (error) \ return error; \ - GIT_ASSERT((h)->flags); \ - GIT_ASSERT((h)->keys); \ if (!key_exists) { \ (h)->keys[idx] = key; \ } \ From 6d8d5de659058bd60fbc051c117e28a24e976830 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 7 Oct 2024 21:37:29 +0100 Subject: [PATCH 632/816] hashmap: further asserts Continue to quiet down mediocre static code analysis. --- src/util/hashmap.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/hashmap.h b/src/util/hashmap.h index 9d164b90709..c29844f3892 100644 --- a/src/util/hashmap.h +++ b/src/util/hashmap.h @@ -109,6 +109,7 @@ typedef uint32_t git_hashmap_iter_t; { \ if (h->n_buckets) { \ uint32_t k, i, last, mask, step = 0; \ + GIT_ASSERT((h)->flags); \ mask = h->n_buckets - 1; \ k = __hash_fn(key); \ i = k & mask; \ From b72dfb0e73edb905d9846f43d3873a126e5dccaf Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 5 Oct 2024 12:20:31 +0100 Subject: [PATCH 633/816] zlib: update bundled zlib to v1.3.1 --- deps/zlib/deflate.c | 47 +++++++++++++++++++++++++++++++++----------- deps/zlib/deflate.h | 35 +++++++++++++++++++++++++++++++-- deps/zlib/gzguts.h | 8 ++------ deps/zlib/inflate.c | 2 +- deps/zlib/inftrees.c | 6 +++--- deps/zlib/inftrees.h | 4 ++-- deps/zlib/trees.c | 20 ++++++++++++++++--- deps/zlib/zconf.h | 10 +--------- deps/zlib/zlib.h | 22 ++++++++++----------- deps/zlib/zutil.h | 27 +++---------------------- 10 files changed, 109 insertions(+), 72 deletions(-) diff --git a/deps/zlib/deflate.c b/deps/zlib/deflate.c index bd011751920..012ea8148e8 100644 --- a/deps/zlib/deflate.c +++ b/deps/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler "; + " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -493,7 +493,7 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, * symbols from which it is being constructed. */ - s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4); + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS); s->pending_buf_size = (ulg)s->lit_bufsize * 4; if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || @@ -503,8 +503,14 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, deflateEnd (strm); return Z_MEM_ERROR; } +#ifdef LIT_MEM + s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1)); + s->l_buf = s->pending_buf + (s->lit_bufsize << 2); + s->sym_end = s->lit_bufsize - 1; +#else s->sym_buf = s->pending_buf + s->lit_bufsize; s->sym_end = (s->lit_bufsize - 1) * 3; +#endif /* We avoid equality with lit_bufsize*3 because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. @@ -720,9 +726,15 @@ int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; +#ifdef LIT_MEM + if (bits < 0 || bits > 16 || + (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#else if (bits < 0 || bits > 16 || s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; +#endif do { put = Buf_size - s->bi_valid; if (put > bits) @@ -1294,7 +1306,7 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS); if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { @@ -1305,10 +1317,15 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); +#ifdef LIT_MEM + ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1)); + ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); +#else ds->sym_buf = ds->pending_buf + ds->lit_bufsize; +#endif ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; @@ -1539,13 +1556,21 @@ local uInt longest_match(deflate_state *s, IPos cur_match) { */ local void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); + Bytef *back = s->window + (int)match, *here = s->window + start; + IPos len = length; + if (match == (IPos)-1) { + /* match starts one byte before the current window -- just compare the + subsequent length-1 bytes */ + back++; + here++; + len--; + } + if (zmemcmp(back, here, len) != EQUAL) { + fprintf(stderr, " start %u, match %d, length %d\n", + start, (int)match, length); do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); + fprintf(stderr, "(%02x %02x)", *back++, *here++); + } while (--len != 0); z_error("invalid match"); } if (z_verbose > 1) { diff --git a/deps/zlib/deflate.h b/deps/zlib/deflate.h index 8696791429f..300c6ada62b 100644 --- a/deps/zlib/deflate.h +++ b/deps/zlib/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2018 Jean-loup Gailly + * Copyright (C) 1995-2024 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -23,6 +23,10 @@ # define GZIP #endif +/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at + the cost of a larger memory footprint */ +/* #define LIT_MEM */ + /* =========================================================================== * Internal compression state. */ @@ -217,7 +221,14 @@ typedef struct internal_state { /* Depth of each subtree used as tie breaker for trees of equal frequency */ +#ifdef LIT_MEM +# define LIT_BUFS 5 + ushf *d_buf; /* buffer for distances */ + uchf *l_buf; /* buffer for literals/lengths */ +#else +# define LIT_BUFS 4 uchf *sym_buf; /* buffer for distances and literals/lengths */ +#endif uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for @@ -239,7 +250,7 @@ typedef struct internal_state { * - I can't count above 4 */ - uInt sym_next; /* running index in sym_buf */ + uInt sym_next; /* running index in symbol buffer */ uInt sym_end; /* symbol table full when sym_next reaches this */ ulg opt_len; /* bit length of current block with optimal trees */ @@ -318,6 +329,25 @@ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, extern const uch ZLIB_INTERNAL _dist_code[]; #endif +#ifdef LIT_MEM +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->sym_next] = 0; \ + s->l_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->d_buf[s->sym_next] = dist; \ + s->l_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#else # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->sym_buf[s->sym_next++] = 0; \ @@ -337,6 +367,7 @@ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->sym_next == s->sym_end); \ } +#endif #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ diff --git a/deps/zlib/gzguts.h b/deps/zlib/gzguts.h index f9375047e8c..eba72085bb7 100644 --- a/deps/zlib/gzguts.h +++ b/deps/zlib/gzguts.h @@ -1,5 +1,5 @@ /* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004-2019 Mark Adler + * Copyright (C) 2004-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -210,9 +210,5 @@ char ZLIB_INTERNAL *gz_strwinerror(DWORD error); /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ -#ifdef INT_MAX -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) -#else unsigned ZLIB_INTERNAL gz_intmax(void); -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) -#endif +#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) diff --git a/deps/zlib/inflate.c b/deps/zlib/inflate.c index b0757a9b249..94ecff015a9 100644 --- a/deps/zlib/inflate.c +++ b/deps/zlib/inflate.c @@ -1387,7 +1387,7 @@ int ZEXPORT inflateSync(z_streamp strm) { /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; - state->hold <<= state->bits & 7; + state->hold >>= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { diff --git a/deps/zlib/inftrees.c b/deps/zlib/inftrees.c index 8a208c2daa8..98cfe164458 100644 --- a/deps/zlib/inftrees.c +++ b/deps/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2023 Mark Adler + * Copyright (C) 1995-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.3 Copyright 1995-2023 Mark Adler "; + " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -57,7 +57,7 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/deps/zlib/inftrees.h b/deps/zlib/inftrees.h index a10712d8cb5..396f74b5da7 100644 --- a/deps/zlib/inftrees.h +++ b/deps/zlib/inftrees.h @@ -41,8 +41,8 @@ typedef struct { examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes - returns returns 852, and "enough 30 6 15" for distance codes returns 592. - The initial root table size (9 or 6) is found in the fifth argument of the + returns 852, and "enough 30 6 15" for distance codes returns 592. The + initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ diff --git a/deps/zlib/trees.c b/deps/zlib/trees.c index 8dbdc40bacc..6a523ef34e3 100644 --- a/deps/zlib/trees.c +++ b/deps/zlib/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2021 Jean-loup Gailly + * Copyright (C) 1995-2024 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -899,14 +899,19 @@ local void compress_block(deflate_state *s, const ct_data *ltree, const ct_data *dtree) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ - unsigned sx = 0; /* running index in sym_buf */ + unsigned sx = 0; /* running index in symbol buffers */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->sym_next != 0) do { +#ifdef LIT_MEM + dist = s->d_buf[sx]; + lc = s->l_buf[sx++]; +#else dist = s->sym_buf[sx++] & 0xff; dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; lc = s->sym_buf[sx++]; +#endif if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); @@ -931,8 +936,12 @@ local void compress_block(deflate_state *s, const ct_data *ltree, } } /* literal or match pair ? */ - /* Check that the overlay between pending_buf and sym_buf is ok: */ + /* Check for no overlay of pending_buf on needed symbols */ +#ifdef LIT_MEM + Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow"); +#else Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); +#endif } while (sx < s->sym_next); @@ -1082,9 +1091,14 @@ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { +#ifdef LIT_MEM + s->d_buf[s->sym_next] = (ush)dist; + s->l_buf[s->sym_next++] = (uch)lc; +#else s->sym_buf[s->sym_next++] = (uch)dist; s->sym_buf[s->sym_next++] = (uch)(dist >> 8); s->sym_buf[s->sym_next++] = (uch)lc; +#endif if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; diff --git a/deps/zlib/zconf.h b/deps/zlib/zconf.h index fb76ffe312a..62adc8d8431 100644 --- a/deps/zlib/zconf.h +++ b/deps/zlib/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -300,14 +300,6 @@ # endif #endif -#ifndef Z_ARG /* function prototypes for stdarg */ -# if defined(STDC) || defined(Z_HAVE_STDARG_H) -# define Z_ARG(args) args -# else -# define Z_ARG(args) () -# endif -#endif - /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have diff --git a/deps/zlib/zlib.h b/deps/zlib/zlib.h index 6b7244f9943..8d4b932eaf6 100644 --- a/deps/zlib/zlib.h +++ b/deps/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.3, August 18th, 2023 + version 1.3.1, January 22nd, 2024 - Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.3" -#define ZLIB_VERNUM 0x1300 +#define ZLIB_VERSION "1.3.1" +#define ZLIB_VERNUM 0x1310 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 3 -#define ZLIB_VER_REVISION 0 +#define ZLIB_VER_REVISION 1 #define ZLIB_VER_SUBREVISION 0 /* @@ -936,10 +936,10 @@ ZEXTERN int ZEXPORT inflateSync(z_streamp strm); inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. - In the success case, the application may save the current current value of - total_in which indicates where valid compressed data was found. In the - error case, the application may repeatedly call inflateSync, providing more - input each time, until success or end of the input data. + In the success case, the application may save the current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, @@ -1758,14 +1758,14 @@ ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. + len2. len2 must be non-negative. */ /* ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); Return the operator corresponding to length len2, to be used with - crc32_combine_op(). + crc32_combine_op(). len2 must be non-negative. */ ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); diff --git a/deps/zlib/zutil.h b/deps/zlib/zutil.h index 902a304cc2d..48dd7febae6 100644 --- a/deps/zlib/zutil.h +++ b/deps/zlib/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -56,7 +56,7 @@ typedef unsigned long ulg; extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] +#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) @@ -137,17 +137,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif #endif -#if defined(MACOS) || defined(TARGET_OS_MAC) +#if defined(MACOS) # define OS_CODE 7 -# ifndef Z_SOLO -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -# endif #endif #ifdef __acorn @@ -170,18 +161,6 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define OS_CODE 19 #endif -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 From 7f7dfe71ccf85074b33391ed01b96eb87fd1629c Mon Sep 17 00:00:00 2001 From: Marcin Dabrowski Date: Wed, 9 Oct 2024 14:51:42 +0200 Subject: [PATCH 634/816] Add OpenSSL-FIPS CMake flag Usage of the deprecated 'SHA256_*' OpenSSL API in a FIPS compliant environment results in OpenSSL's assertion failure with the following description: "OpenSSL internal error, assertion failed: Low level API call to digest SHA256 forbidden in FIPS mode!" This commit adds a possibility to use the OpenSSL's 'EVP_MD*' API instead of the deprecated 'SHA256_*' API, by extending the optional CMake flag 'USE_SHA256' with the new option called 'OpenSSL-FIPS'. The new option is used to choose a hashing backend used by libgit2 to calculate SHA256 hashes, in a similar way that currently existing options like 'OpenSSL', 'OpenSSL-Dynamic', 'mbedTLS' etc do. 'OpenSSL-FIPS' is a fully opt-in option which is purposely not interfering with the existing options, because, after running some benchmarks, it's been discovered that using the 'EVP_MD*' API causes hashing to be a bit slower in comparison to using the deprecated 'SHA256_*' API. Another change introduced in this commit is the enhancement of the Nightly workflow (nightly.yml) which will cause libgit2 to be automatically built with '-DUSE_SHA256="OpenSSL-FIPS"' CMake flag, on Linux, macOS and Windows. --- .github/workflows/nightly.yml | 28 ++++++++++++++ cmake/SelectHashes.cmake | 2 + src/util/CMakeLists.txt | 2 +- src/util/git2_features.h.in | 1 + src/util/hash/openssl.c | 72 +++++++++++++++++++++++++++++++++++ src/util/hash/openssl.h | 12 +++++- src/util/hash/sha.h | 2 +- 7 files changed, 116 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3bed061fdec..df43ff5690a 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -373,6 +373,34 @@ jobs: CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + - name: "Linux (SHA256-FIPS, Xenial, Clang, OpenSSL)" + id: linux-sha256-fips + container: + name: xenial + env: + CC: clang + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DUSE_SHA256="OpenSSL-FIPS" + os: ubuntu-latest + - name: "macOS (SHA256-FIPS)" + id: macos-sha256-fips + os: macos-13 + setup-script: osx + env: + CC: clang + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON -DUSE_SHA256="OpenSSL-FIPS" + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (SHA256-FIPS, amd64, Visual Studio)" + id: windows-sha256-fips + os: windows-2022 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 17 2022 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON -DUSE_SHA256="OpenSSL-FIPS" + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true fail-fast: false env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 5c007e58749..59ae53b2049 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -70,6 +70,8 @@ elseif(USE_SHA256 STREQUAL "OpenSSL-Dynamic") set(GIT_SHA256_OPENSSL 1) set(GIT_SHA256_OPENSSL_DYNAMIC 1) list(APPEND LIBGIT2_SYSTEM_LIBS dl) +elseif(USE_SHA256 STREQUAL "OpenSSL-FIPS") + set(GIT_SHA256_OPENSSL_FIPS 1) elseif(USE_SHA256 STREQUAL "CommonCrypto") set(GIT_SHA256_COMMON_CRYPTO 1) elseif(USE_SHA256 STREQUAL "mbedTLS") diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index ee35eb9610e..dc992dfc4a0 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -53,7 +53,7 @@ list(SORT UTIL_SRC_SHA1) if(USE_SHA256 STREQUAL "Builtin") file(GLOB UTIL_SRC_SHA256 hash/builtin.* hash/rfc6234/*) -elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic") +elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) file(GLOB UTIL_SRC_SHA256 hash/openssl.*) elseif(USE_SHA256 STREQUAL "CommonCrypto") diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 52b73284687..a99c8bc373f 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -62,6 +62,7 @@ #cmakedefine GIT_SHA256_COMMON_CRYPTO 1 #cmakedefine GIT_SHA256_OPENSSL 1 #cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 +#cmakedefine GIT_SHA256_OPENSSL_FIPS 1 #cmakedefine GIT_SHA256_MBEDTLS 1 #cmakedefine GIT_RAND_GETENTROPY 1 diff --git a/src/util/hash/openssl.c b/src/util/hash/openssl.c index eaf91e74c1d..fae48f0a1f5 100644 --- a/src/util/hash/openssl.c +++ b/src/util/hash/openssl.c @@ -193,3 +193,75 @@ int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) } #endif + +#ifdef GIT_SHA256_OPENSSL_FIPS + +static const EVP_MD* SHA256_ENGINE_DIGEST_TYPE = NULL; + +int git_hash_sha256_global_init(void) +{ + SHA256_ENGINE_DIGEST_TYPE = EVP_sha256(); + return SHA256_ENGINE_DIGEST_TYPE != NULL ? 0 : -1; +} + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) +{ + return git_hash_sha256_init(ctx); +} + +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX_destroy(ctx->c); +#else + EVP_MD_CTX_free(ctx->c); +#endif +} + +int git_hash_sha256_init(git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + + GIT_ASSERT(SHA256_ENGINE_DIGEST_TYPE); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + ctx->c = EVP_MD_CTX_create(); +#else + ctx->c = EVP_MD_CTX_new(); +#endif + GIT_ASSERT(ctx->c); + + if (EVP_DigestInit_ex(ctx->c, SHA256_ENGINE_DIGEST_TYPE, NULL) != 1) { + git_hash_sha256_ctx_cleanup(ctx); + git_error_set(GIT_ERROR_SHA, "failed to initialize sha256 context"); + return -1; + } + + return 0; +} + +int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + + if (EVP_DigestUpdate(ctx->c, data, len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to update sha256"); + return -1; + } + + return 0; +} + +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) +{ + unsigned int len = 0; + GIT_ASSERT_ARG(ctx); + + if (EVP_DigestFinal(ctx->c, out, &len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to finalize sha256"); + return -1; + } + + return 0; +} + +#endif \ No newline at end of file diff --git a/src/util/hash/openssl.h b/src/util/hash/openssl.h index 7cb089abc1e..96ff922d9fc 100644 --- a/src/util/hash/openssl.h +++ b/src/util/hash/openssl.h @@ -11,7 +11,11 @@ #include "hash/sha.h" #ifndef GIT_OPENSSL_DYNAMIC -# include +#ifdef GIT_SHA256_OPENSSL_FIPS +#include +#else +#include +#endif #else typedef struct { @@ -42,4 +46,10 @@ struct git_hash_sha256_ctx { }; #endif +#ifdef GIT_SHA256_OPENSSL_FIPS +struct git_hash_sha256_ctx { + EVP_MD_CTX* c; +}; +#endif + #endif diff --git a/src/util/hash/sha.h b/src/util/hash/sha.h index 4f596234c37..be224000a0a 100644 --- a/src/util/hash/sha.h +++ b/src/util/hash/sha.h @@ -17,7 +17,7 @@ typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; # include "common_crypto.h" #endif -#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) +#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) || defined(GIT_SHA256_OPENSSL_FIPS) # include "openssl.h" #endif From 3d268285f9c1a9795496af0ffd4a04c5238ebd49 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 10 Oct 2024 00:01:16 +0100 Subject: [PATCH 635/816] sha: support FIPS-compliant OpenSSL for SHA1 --- cmake/SelectHashes.cmake | 9 +++-- src/util/CMakeLists.txt | 2 +- src/util/git2_features.h.in | 3 +- src/util/hash/openssl.c | 80 +++++++++++++++++++++++++++++++++++-- src/util/hash/openssl.h | 16 +++++--- src/util/hash/sha.h | 5 ++- 6 files changed, 101 insertions(+), 14 deletions(-) diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 59ae53b2049..06cfabc3cd0 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -28,6 +28,8 @@ if(USE_SHA1 STREQUAL "CollisionDetection") set(GIT_SHA1_COLLISIONDETECT 1) elseif(USE_SHA1 STREQUAL "OpenSSL") set(GIT_SHA1_OPENSSL 1) +elseif(USE_SHA1 STREQUAL "OpenSSL-FIPS") + set(GIT_SHA1_OPENSSL_FIPS 1) elseif(USE_SHA1 STREQUAL "OpenSSL-Dynamic") set(GIT_SHA1_OPENSSL 1) set(GIT_SHA1_OPENSSL_DYNAMIC 1) @@ -66,12 +68,12 @@ if(USE_SHA256 STREQUAL "Builtin") set(GIT_SHA256_BUILTIN 1) elseif(USE_SHA256 STREQUAL "OpenSSL") set(GIT_SHA256_OPENSSL 1) +elseif(USE_SHA256 STREQUAL "OpenSSL-FIPS") + set(GIT_SHA256_OPENSSL_FIPS 1) elseif(USE_SHA256 STREQUAL "OpenSSL-Dynamic") set(GIT_SHA256_OPENSSL 1) set(GIT_SHA256_OPENSSL_DYNAMIC 1) list(APPEND LIBGIT2_SYSTEM_LIBS dl) -elseif(USE_SHA256 STREQUAL "OpenSSL-FIPS") - set(GIT_SHA256_OPENSSL_FIPS 1) elseif(USE_SHA256 STREQUAL "CommonCrypto") set(GIT_SHA256_COMMON_CRYPTO 1) elseif(USE_SHA256 STREQUAL "mbedTLS") @@ -83,7 +85,8 @@ else() endif() # add library requirements -if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL") +if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL" OR + USE_SHA1 STREQUAL "OpenSSL-FIPS" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LIBGIT2_PC_LIBS "-lssl") else() diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index dc992dfc4a0..a92505fe9df 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -36,7 +36,7 @@ if(USE_SHA1 STREQUAL "CollisionDetection") target_compile_definitions(util PRIVATE SHA1DC_NO_STANDARD_INCLUDES=1) target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_SHA1_C=\"git2_util.h\") target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"git2_util.h\") -elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic") +elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic" OR USE_SHA1 STREQUAL "OpenSSL-FIPS") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) file(GLOB UTIL_SRC_SHA1 hash/openssl.*) elseif(USE_SHA1 STREQUAL "CommonCrypto") diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index a99c8bc373f..9408f9b00f6 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -54,6 +54,7 @@ #cmakedefine GIT_SHA1_WIN32 1 #cmakedefine GIT_SHA1_COMMON_CRYPTO 1 #cmakedefine GIT_SHA1_OPENSSL 1 +#cmakedefine GIT_SHA1_OPENSSL_FIPS 1 #cmakedefine GIT_SHA1_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SHA1_MBEDTLS 1 @@ -61,8 +62,8 @@ #cmakedefine GIT_SHA256_WIN32 1 #cmakedefine GIT_SHA256_COMMON_CRYPTO 1 #cmakedefine GIT_SHA256_OPENSSL 1 -#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SHA256_OPENSSL_FIPS 1 +#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SHA256_MBEDTLS 1 #cmakedefine GIT_RAND_GETENTROPY 1 diff --git a/src/util/hash/openssl.c b/src/util/hash/openssl.c index fae48f0a1f5..06297eea96f 100644 --- a/src/util/hash/openssl.c +++ b/src/util/hash/openssl.c @@ -120,6 +120,79 @@ int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) #endif +#ifdef GIT_SHA1_OPENSSL_FIPS + +static const EVP_MD *SHA1_ENGINE_DIGEST_TYPE = NULL; + +int git_hash_sha1_global_init(void) +{ + SHA1_ENGINE_DIGEST_TYPE = EVP_sha1(); + return SHA1_ENGINE_DIGEST_TYPE != NULL ? 0 : -1; +} + +int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) +{ + return git_hash_sha1_init(ctx); +} + +void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX_destroy(ctx->c); +#else + EVP_MD_CTX_free(ctx->c); +#endif +} + +int git_hash_sha1_init(git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + GIT_ASSERT(SHA1_ENGINE_DIGEST_TYPE); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + ctx->c = EVP_MD_CTX_create(); +#else + ctx->c = EVP_MD_CTX_new(); +#endif + + GIT_ASSERT(ctx->c); + + if (EVP_DigestInit_ex(ctx->c, SHA1_ENGINE_DIGEST_TYPE, NULL) != 1) { + git_hash_sha1_ctx_cleanup(ctx); + git_error_set(GIT_ERROR_SHA, "failed to initialize sha1 context"); + return -1; + } + + return 0; +} + +int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + + if (EVP_DigestUpdate(ctx->c, data, len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to update sha1"); + return -1; + } + + return 0; +} + +int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) +{ + unsigned int len = 0; + GIT_ASSERT_ARG(ctx); + + if (EVP_DigestFinal(ctx->c, out, &len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to finalize sha1"); + return -1; + } + + return 0; +} + +#endif + #ifdef GIT_SHA256_OPENSSL # ifdef GIT_OPENSSL_DYNAMIC @@ -196,7 +269,7 @@ int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) #ifdef GIT_SHA256_OPENSSL_FIPS -static const EVP_MD* SHA256_ENGINE_DIGEST_TYPE = NULL; +static const EVP_MD *SHA256_ENGINE_DIGEST_TYPE = NULL; int git_hash_sha256_global_init(void) { @@ -221,13 +294,14 @@ void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) int git_hash_sha256_init(git_hash_sha256_ctx *ctx) { GIT_ASSERT_ARG(ctx); - GIT_ASSERT(SHA256_ENGINE_DIGEST_TYPE); + #if OPENSSL_VERSION_NUMBER < 0x10100000L ctx->c = EVP_MD_CTX_create(); #else ctx->c = EVP_MD_CTX_new(); #endif + GIT_ASSERT(ctx->c); if (EVP_DigestInit_ex(ctx->c, SHA256_ENGINE_DIGEST_TYPE, NULL) != 1) { @@ -264,4 +338,4 @@ int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) return 0; } -#endif \ No newline at end of file +#endif diff --git a/src/util/hash/openssl.h b/src/util/hash/openssl.h index 96ff922d9fc..8be37fd44e8 100644 --- a/src/util/hash/openssl.h +++ b/src/util/hash/openssl.h @@ -11,11 +11,11 @@ #include "hash/sha.h" #ifndef GIT_OPENSSL_DYNAMIC -#ifdef GIT_SHA256_OPENSSL_FIPS -#include -#else -#include -#endif +# if defined(GIT_SHA1_OPENSSL_FIPS) || defined(GIT_SHA256_OPENSSL_FIPS) +# include +# else +# include +# endif #else typedef struct { @@ -40,6 +40,12 @@ struct git_hash_sha1_ctx { }; #endif +#ifdef GIT_SHA1_OPENSSL_FIPS +struct git_hash_sha1_ctx { + EVP_MD_CTX* c; +}; +#endif + #ifdef GIT_SHA256_OPENSSL struct git_hash_sha256_ctx { SHA256_CTX c; diff --git a/src/util/hash/sha.h b/src/util/hash/sha.h index be224000a0a..8e7eeae8c34 100644 --- a/src/util/hash/sha.h +++ b/src/util/hash/sha.h @@ -17,7 +17,10 @@ typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; # include "common_crypto.h" #endif -#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) || defined(GIT_SHA256_OPENSSL_FIPS) +#if defined(GIT_SHA1_OPENSSL) || \ + defined(GIT_SHA1_OPENSSL_FIPS) || \ + defined(GIT_SHA256_OPENSSL) || \ + defined(GIT_SHA256_OPENSSL_FIPS) # include "openssl.h" #endif From 41c8c46df105717a582f7a4b471c2f55fcf8c464 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 11 Oct 2024 11:32:12 +0100 Subject: [PATCH 636/816] README updates --- README.md | 230 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 154 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index afeaeaaa38f..9776620154a 100644 --- a/README.md +++ b/README.md @@ -10,26 +10,23 @@ libgit2 - the Git linkable library `libgit2` is a portable, pure C implementation of the Git core methods provided as a linkable library with a solid API, allowing to build Git -functionality into your application. Language bindings like -[Rugged](https://github.com/libgit2/rugged) (Ruby), -[LibGit2Sharp](https://github.com/libgit2/libgit2sharp) (.NET), -[pygit2](http://www.pygit2.org/) (Python) and -[NodeGit](http://nodegit.org) (Node) allow you to build Git tooling -in your favorite language. - -`libgit2` is used to power Git GUI clients like -[GitKraken](https://gitkraken.com/) and [GitButler](https://gitbutler.com/) -and on Git hosting providers like [GitHub](https://github.com/), -[GitLab](https://gitlab.com/) and -[Azure DevOps](https://azure.com/devops). -We perform the merge every time you click "merge pull request". - -`libgit2` is licensed under a **very permissive license** (GPLv2 with a special -Linking Exception). This means that you can link against the library with any -kind of software without making that software fall under the GPL. -Changes to libgit2 would still be covered under its GPL license. -Additionally, the example code has been released to the public domain (see the -[separate license](examples/COPYING) for more information). +functionality into your application. + +`libgit2` is used in a variety of places, from GUI clients to hosting +providers ("forges") and countless utilities and applications in +between. Because it's written in C, it can be made available to any +other programming language through "bindings", so you can use it in +[Ruby](https://github.com/libgit2/rugged), +[.NET](https://github.com/libgit2/libgit2sharp), +[Python](http://www.pygit2.org/), +[Node.js](http://nodegit.org), +[Rust](https://github.com/rust-lang/git2-rs), and more. + +`libgit2` is licensed under a **very permissive license** (GPLv2 with +a special Linking Exception). This means that you can link against +the library with any kind of software without making that software +fall under the GPL. Changes to libgit2 would still be covered under +its GPL license. Table of Contents ================= @@ -93,8 +90,8 @@ Quick Start **Build** -1. Create a build directory beneath the libgit2 source directory, and change - into it: `mkdir build && cd build` +1. Create a build directory beneath the libgit2 source directory, + and change into it: `mkdir build && cd build` 2. Create the cmake build environment: `cmake ..` 3. Build libgit2: `cmake --build .` @@ -108,22 +105,24 @@ Getting Help - via IRC: join [#libgit2](https://web.libera.chat/#libgit2) on [libera](https://libera.chat). -- via Slack: visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up, - then join us in `#libgit2` +- via Slack: visit [slack.libgit2.org](http://slack.libgit2.org/) + to sign up, then join us in `#libgit2` **Getting Help** If you have questions about the library, please be sure to check out the [API documentation](https://libgit2.org/libgit2/). If you still have questions, reach out to us on Slack or post a question on -[StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) (with the `libgit2` tag). +[StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) +(with the `libgit2` tag). **Reporting Bugs** -Please open a [GitHub Issue](https://github.com/libgit2/libgit2/issues) and -include as much information as possible. If possible, provide sample code -that illustrates the problem you're seeing. If you're seeing a bug only -on a specific repository, please provide a link to it if possible. +Please open a [GitHub Issue](https://github.com/libgit2/libgit2/issues) +and include as much information as possible. If possible, provide +sample code that illustrates the problem you're seeing. If you're +seeing a bug only on a specific repository, please provide a link to +it if possible. We ask that you not open a GitHub Issue for help, only for bug reports. @@ -138,10 +137,10 @@ libgit2 provides you with the ability to manage Git repositories in the programming language of your choice. It's used in production to power many applications including GitHub.com, Plastic SCM and Azure DevOps. -It does not aim to replace the git tool or its user-facing commands. Some APIs -resemble the plumbing commands as those align closely with the concepts of the -Git system, but most commands a user would type are out of scope for this -library to implement directly. +It does not aim to replace the git tool or its user-facing commands. Some +APIs resemble the plumbing commands as those align closely with the +concepts of the Git system, but most commands a user would type are out +of scope for this library to implement directly. The library provides: @@ -161,23 +160,31 @@ The library provides: As libgit2 is purely a consumer of the Git system, we have to adjust to changes made upstream. This has two major consequences: -* Some changes may require us to change provided interfaces. While we try to - implement functions in a generic way so that no future changes are required, - we cannot promise a completely stable API. -* As we have to keep up with changes in behavior made upstream, we may lag - behind in some areas. We usually to document these incompatibilities in our - issue tracker with the label "git change". +* Some changes may require us to change provided interfaces. While + we try to implement functions in a generic way so that no future + changes are required, we cannot promise a completely stable API. +* As we have to keep up with changes in behavior made upstream, we + may lag behind in some areas. We usually to document these + incompatibilities in our issue tracker with the label "git change". Optional dependencies ===================== -While the library provides git functionality without the need for -dependencies, it can make use of a few libraries to add to it: - -- pthreads (non-Windows) to enable threadsafe access as well as multi-threaded pack generation -- OpenSSL (non-Windows) to talk over HTTPS and provide the SHA-1 functions -- LibSSH2 to enable the SSH transport -- iconv (OSX) to handle the HFS+ path encoding peculiarities +While the library provides git functionality with very few +dependencies, some recommended dependencies are used for performance +or complete functionality. + +- Hash generation: Git uses SHA1DC (collision detecting SHA1) for + its default hash generation. SHA256 support is experimental, and + optimized support is provided by system libraries on macOS and + Windows, or by the HTTPS library on Unix systems when available. +- Threading: is provided by the system libraries on Windows, and + pthreads on Unix systems. +- HTTPS: is provided by the system libraries on macOS and Windows, + or by OpenSSL or mbedTLS on other Unix systems. +- SSH: is provided by [libssh2](https://libssh2.org/) or by invoking + [OpenSSH](https://www.openssh.com). +- Unicode: is provided by the system libraries on Windows and macOS. Initialization =============== @@ -212,12 +219,9 @@ Building libgit2 - Using CMake Building -------- -`libgit2` builds cleanly on most platforms without any external dependencies. -Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthreads` to be available; -they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API -for threading. - -The `libgit2` library is built using [CMake]() (version 2.8 or newer) on all platforms. +`libgit2` builds cleanly on most platforms without any external +dependencies as a requirement. `libgit2` is built using +[CMake]() (version 2.8 or newer) on all platforms. On most systems you can build the library using the following commands @@ -225,14 +229,80 @@ On most systems you can build the library using the following commands $ cmake .. $ cmake --build . -To include the examples in the build, use `cmake -DBUILD_EXAMPLES=True ..` instead of `cmake ..`. - -The built executable for the examples can then be found in `build/examples`, relative to the toplevel directory. +To include the examples in the build, use `cmake -DBUILD_EXAMPLES=ON ..` +instead of `cmake ..`. The built executable for the examples can then +be found in `build/examples`, relative to the toplevel directory. Alternatively you can point the CMake GUI tool to the CMakeLists.txt file and generate platform specific build project or IDE workspace. If you're not familiar with CMake, [a more detailed explanation](https://preshing.com/20170511/how-to-build-a-cmake-based-project/) may be helpful. +Advanced Options +---------------- + +You can specify a number of options to `cmake` that will change the +way `libgit2` is built. To use this, specify `-Doption=value` during +the initial `cmake` configuration. For example, to enable SHA256 +compatibility: + + $ mkdir build && cd build + $ cmake -DEXPERIMENTAL_SHA256=ON .. + $ cmake --build . + +libgit2 options: + +* `EXPERIMENTAL_SHA256=ON`: turns on SHA256 compatibility; note that + this is an API-incompatible change, hence why it is labeled + "experimental" + +Build options: + +* `BUILD_EXAMPLES=ON`: builds the suite of example code +* `BUILD_FUZZERS=ON`: builds the fuzzing suite +* `ENABLE_WERROR=ON`: build with `-Werror` or the equivalent, which turns + compiler warnings into errors in the libgit2 codebase (but not its + dependencies) + +Dependency options: + +* `USE_SSH=type`: enables SSH support; `type` can be set to `libssh2` + or `exec` (which will execute an external OpenSSH command) +* `USE_HTTPS=type`: enables HTTPS support; `type` can be set to + `OpenSSL`, `mbedTLS`, `SecureTransport`, `Schannel`, or `WinHTTP`; + the default is `SecureTransport` on macOS, `WinHTTP` on Windows, and + whichever of `OpenSSL` or `mbedTLS` is detected on other platforms. +* `USE_SHA1=type`: selects the SHA1 mechanism to use; `type` can be set + to `CollisionDetection` (default), or `HTTPS` to use the HTTPS + driver specified above as the hashing provider. +* `USE_SHA256=type`: selects the SHA256 mechanism to use; `type` can be + set to `HTTPS` (default) to use the HTTPS driver specified above as + the hashing provider, or `Builtin`. +* `USE_GSSAPI=`: enables GSSAPI for SPNEGO authentication on + Unix +* `USE_HTTP_PARSER=type`: selects the HTTP Parser; either `http-parser` + for an external + [`http-parser`](https://github.com/nodejs/http-parser) dependency, + `llhttp` for an external [`llhttp`](https://github.com/nodejs/llhttp) + dependency, or `builtin` +* `REGEX_BACKEND=type`: selects the regular expression backend to use; + one of `regcomp_l`, `pcre2`, `pcre`, `regcomp`, or `builtin`. +* `USE_BUNDLED_ZLIB=type`: selects the zlib dependency to use; one of + `bundled` or `Chromium`. + +Locating Dependencies +--------------------- + +The `libgit2` project uses `cmake` since it helps with cross-platform +projects, especially those with many dependencies. If your dependencies +are in non-standard places, you may want to use the `_ROOT_DIR` options +to specify their location. For example, to specify an OpenSSL location: + + $ cmake -DOPENSSL_ROOT_DIR=/tmp/openssl-3.3.2 .. + +Since these options are general to CMake, their +[documentation](https://cmake.org/documentation/) may be helpful. If +you have questions about dependencies, please [contact us](#getting-help). + Running Tests ------------- @@ -248,12 +318,13 @@ Invoking the test suite directly is useful because it allows you to execute individual tests, or groups of tests using the `-s` flag. For example, to run the index tests: - $ ./libgit2_tests -sindex + $ ./libgit2_tests -sindex -To run a single test named `index::racy::diff`, which corresponds to the test -function [`test_index_racy__diff`](https://github.com/libgit2/libgit2/blob/main/tests/index/racy.c#L23): +To run a single test named `index::racy::diff`, which corresponds to +the test function +[`test_index_racy__diff`](https://github.com/libgit2/libgit2/blob/main/tests/index/racy.c#L23): - $ ./libgit2_tests -sindex::racy::diff + $ ./libgit2_tests -sindex::racy::diff The test suite will print a `.` for every passing test, and an `F` for any failing test. An `S` indicates that a test was skipped because it is not @@ -262,7 +333,8 @@ applicable to your platform or is particularly expensive. **Note:** There should be _no_ failing tests when you build an unmodified source tree from a [release](https://github.com/libgit2/libgit2/releases), or from the [main branch](https://github.com/libgit2/libgit2/tree/main). -Please contact us or [open an issue](https://github.com/libgit2/libgit2/issues) +Please contact us or +[open an issue](https://github.com/libgit2/libgit2/issues) if you see test failures. Installation @@ -276,7 +348,8 @@ To install the library you can specify the install prefix by setting: Advanced Usage -------------- -For more advanced use or questions about CMake please read . +For more advanced use or questions about CMake please read the +[CMake FAQ](https://cmake.org/Wiki/CMake_FAQ). The following CMake variables are declared: @@ -293,6 +366,7 @@ following: # Create and set up a build directory $ mkdir build && cd build $ cmake .. + # List all build options and their values $ cmake -L @@ -379,16 +453,19 @@ when configuring. MinGW ----- -If you want to build the library in MinGW environment with SSH support enabled, -you may need to pass `-DCMAKE_LIBRARY_PATH="${MINGW_PREFIX}/${MINGW_CHOST}/lib/"` flag -to CMake when configuring. This is because CMake cannot find the Win32 libraries in -MinGW folders by default and you might see an error message stating that CMake -could not resolve `ws2_32` library during configuration. +If you want to build the library in MinGW environment with SSH support +enabled, you may need to pass +`-DCMAKE_LIBRARY_PATH="${MINGW_PREFIX}/${MINGW_CHOST}/lib/"` flag +to CMake when configuring. This is because CMake cannot find the +Win32 libraries in MinGW folders by default and you might see an +error message stating that CMake could not resolve `ws2_32` library +during configuration. -Another option would be to install `msys2-w32api-runtime` package before configuring. -This package installs the Win32 libraries into `/usr/lib` folder which is by default -recognized as the library path by CMake. Please note though that this package is meant -for MSYS subsystem which is different from MinGW. +Another option would be to install `msys2-w32api-runtime` package before +configuring. This package installs the Win32 libraries into `/usr/lib` +folder which is by default recognized as the library path by CMake. +Please note though that this package is meant for MSYS subsystem which +is different from MinGW. Language Bindings ================================== @@ -468,15 +545,16 @@ and that are good places to jump in and get started. There's much more detailed information in our list of [outstanding projects](docs/projects.md). -Please be sure to check the [contribution guidelines](docs/contributing.md) to -understand our workflow, and the libgit2 [coding conventions](docs/conventions.md). +Please be sure to check the [contribution guidelines](docs/contributing.md) +to understand our workflow, and the libgit2 +[coding conventions](docs/conventions.md). License ================================== -`libgit2` is under GPL2 **with linking exception**. This means you can link to -and use the library from any program, proprietary or open source; paid or -gratis. However, if you modify libgit2 itself, you must distribute the -source to your modified version of libgit2. +`libgit2` is under GPL2 **with linking exception**. This means you can +link to and use the library from any program, proprietary or open source; +paid or gratis. However, if you modify libgit2 itself, you must distribute +the source to your modified version of libgit2. See the [COPYING file](COPYING) for the full license text. From c2d697e3ce208c02d84889326207cbb075643172 Mon Sep 17 00:00:00 2001 From: John Colvin Date: Wed, 16 Oct 2024 14:55:12 +0100 Subject: [PATCH 637/816] s/size on bytes/size in bytes/ --- include/git2/blob.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/git2/blob.h b/include/git2/blob.h index 6db85f38d1b..e8f8381321b 100644 --- a/include/git2/blob.h +++ b/include/git2/blob.h @@ -92,7 +92,7 @@ GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob); * Get the size in bytes of the contents of a blob * * @param blob pointer to the blob - * @return size on bytes + * @return size in bytes */ GIT_EXTERN(git_object_size_t) git_blob_rawsize(const git_blob *blob); From 9cea29d15401ee091da2c9212ac584e42510d462 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 22 Jun 2024 21:20:34 +0100 Subject: [PATCH 638/816] blame: update API Use `size_t` for sizes, standardize naming with the rest of the library. --- examples/blame.c | 2 +- include/git2/blame.h | 106 +++++++++++++++++++++------- src/libgit2/blame.c | 55 +++++++++++---- tests/libgit2/blame/blame_helpers.c | 2 +- tests/libgit2/blame/buffer.c | 14 ++-- tests/libgit2/blame/getters.c | 8 +-- tests/libgit2/blame/harder.c | 4 +- tests/libgit2/blame/simple.c | 18 ++--- tests/libgit2/mailmap/blame.c | 4 +- 9 files changed, 146 insertions(+), 67 deletions(-) diff --git a/examples/blame.c b/examples/blame.c index 0996e7a1fdb..1e2869a6395 100644 --- a/examples/blame.c +++ b/examples/blame.c @@ -97,7 +97,7 @@ int lg2_blame(git_repository *repo, int argc, char *argv[]) while (i < rawsize) { const char *eol = memchr(rawdata + i, '\n', (size_t)(rawsize - i)); char oid[10] = {0}; - const git_blame_hunk *hunk = git_blame_get_hunk_byline(blame, line); + const git_blame_hunk *hunk = git_blame_hunk_byline(blame, line); if (break_on_null_hunk && !hunk) break; diff --git a/include/git2/blame.h b/include/git2/blame.h index cb961a56209..dec2a8a3fa1 100644 --- a/include/git2/blame.h +++ b/include/git2/blame.h @@ -87,7 +87,7 @@ typedef struct git_blame_options { unsigned int version; /** A combination of `git_blame_flag_t` */ - uint32_t flags; + unsigned int flags; /** * The lower bound on the number of alphanumeric characters that @@ -207,6 +207,39 @@ typedef struct git_blame git_blame; * @param blame The blame structure to query. * @return The number of hunks. */ +GIT_EXTERN(size_t) git_blame_hunkcount(git_blame *blame); + +/** + * Gets the blame hunk at the given index. + * + * @param blame the blame structure to query + * @param index index of the hunk to retrieve + * @return the hunk at the given index, or NULL on error + */ +GIT_EXTERN(const git_blame_hunk *) git_blame_hunk_byindex( + git_blame *blame, + size_t index); + +/** + * Gets the hunk that relates to the given line number in the newest + * commit. + * + * @param blame the blame structure to query + * @param lineno the (1-based) line number to find a hunk for + * @return the hunk that contains the given line, or NULL on error + */ +GIT_EXTERN(const git_blame_hunk *) git_blame_hunk_byline( + git_blame *blame, + size_t lineno); + +#ifndef GIT_DEPRECATE_HARD +/** + * Gets the number of hunks that exist in the blame structure. + * + * @param blame The blame structure to query. + * @return The number of hunks. + */ + GIT_EXTERN(uint32_t) git_blame_get_hunk_count(git_blame *blame); /** @@ -216,9 +249,9 @@ GIT_EXTERN(uint32_t) git_blame_get_hunk_count(git_blame *blame); * @param index index of the hunk to retrieve * @return the hunk at the given index, or NULL on error */ -GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byindex( - git_blame *blame, - uint32_t index); +GIT_EXTERN(const git_blame_hunk *) git_blame_get_hunk_byindex( + git_blame *blame, + uint32_t index); /** * Gets the hunk that relates to the given line number in the newest commit. @@ -227,39 +260,58 @@ GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byindex( * @param lineno the (1-based) line number to find a hunk for * @return the hunk that contains the given line, or NULL on error */ -GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byline( - git_blame *blame, - size_t lineno); +GIT_EXTERN(const git_blame_hunk *) git_blame_get_hunk_byline( + git_blame *blame, + size_t lineno); +#endif /** - * Get the blame for a single file. + * Get the blame for a single file in the repository. * * @param out pointer that will receive the blame object * @param repo repository whose history is to be walked * @param path path to file to consider - * @param options options for the blame operation. If NULL, this is treated as - * though GIT_BLAME_OPTIONS_INIT were passed. - * @return 0 on success, or an error code. (use git_error_last for information - * about the error.) + * @param options options for the blame operation or NULL + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_blame_file( - git_blame **out, - git_repository *repo, - const char *path, - git_blame_options *options); + git_blame **out, + git_repository *repo, + const char *path, + git_blame_options *options); +/** + * Get the blame for a single file in the repository, using the specified + * buffer contents as the uncommitted changes of the file (the working + * directory contents). + * + * @param out pointer that will receive the blame object + * @param repo repository whose history is to be walked + * @param path path to file to consider + * @param contents the uncommitted changes + * @param contents_len the length of the changes buffer + * @param options options for the blame operation or NULL + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_blame_file_from_buffer( + git_blame **out, + git_repository *repo, + const char *path, + const char *contents, + size_t contents_len, + git_blame_options *options); /** - * Get blame data for a file that has been modified in memory. The `reference` - * parameter is a pre-calculated blame for the in-odb history of the file. This - * means that once a file blame is completed (which can be expensive), updating - * the buffer blame is very fast. + * Get blame data for a file that has been modified in memory. The `blame` + * parameter is a pre-calculated blame for the in-odb history of the file. + * This means that once a file blame is completed (which can be expensive), + * updating the buffer blame is very fast. * - * Lines that differ between the buffer and the committed version are marked as - * having a zero OID for their final_commit_id. + * Lines that differ between the buffer and the committed version are + * marked as having a zero OID for their final_commit_id. * * @param out pointer that will receive the resulting blame data - * @param reference cached blame from the history of the file (usually the output + * @param base cached blame from the history of the file (usually the output * from git_blame_file) * @param buffer the (possibly) modified contents of the file * @param buffer_len number of valid bytes in the buffer @@ -267,10 +319,10 @@ GIT_EXTERN(int) git_blame_file( * about the error) */ GIT_EXTERN(int) git_blame_buffer( - git_blame **out, - git_blame *reference, - const char *buffer, - size_t buffer_len); + git_blame **out, + git_blame *base, + const char *buffer, + size_t buffer_len); /** * Free memory allocated by git_blame_file or git_blame_buffer. diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index 693e39b5e82..7b872dc7636 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -19,7 +19,6 @@ #include "repository.h" #include "blame_git.h" - static int hunk_byfinalline_search_cmp(const void *key, const void *entry) { git_blame_hunk *hunk = (git_blame_hunk*)entry; @@ -178,31 +177,59 @@ void git_blame_free(git_blame *blame) git__free(blame); } -uint32_t git_blame_get_hunk_count(git_blame *blame) +size_t git_blame_hunkcount(git_blame *blame) { GIT_ASSERT_ARG(blame); - return (uint32_t)blame->hunks.length; + + return blame->hunks.length; } -const git_blame_hunk *git_blame_get_hunk_byindex(git_blame *blame, uint32_t index) +const git_blame_hunk *git_blame_hunk_byindex( + git_blame *blame, + size_t index) { GIT_ASSERT_ARG_WITH_RETVAL(blame, NULL); - return (git_blame_hunk*)git_vector_get(&blame->hunks, index); + return git_vector_get(&blame->hunks, index); } -const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_t lineno) +const git_blame_hunk *git_blame_hunk_byline( + git_blame *blame, + size_t lineno) { size_t i, new_lineno = lineno; GIT_ASSERT_ARG_WITH_RETVAL(blame, NULL); - if (!git_vector_bsearch2(&i, &blame->hunks, hunk_byfinalline_search_cmp, &new_lineno)) { - return git_blame_get_hunk_byindex(blame, (uint32_t)i); - } + if (git_vector_bsearch2(&i, &blame->hunks, + hunk_byfinalline_search_cmp, &new_lineno) != 0) + return NULL; - return NULL; + return git_blame_hunk_byindex(blame, i); } +#ifndef GIT_DEPRECATE_HARD +uint32_t git_blame_get_hunk_count(git_blame *blame) +{ + size_t count = git_blame_hunkcount(blame); + GIT_ASSERT(count < UINT32_MAX); + return (uint32_t)count; +} + +const git_blame_hunk *git_blame_get_hunk_byindex( + git_blame *blame, + uint32_t index) +{ + return git_blame_hunk_byindex(blame, index); +} + +const git_blame_hunk *git_blame_get_hunk_byline( + git_blame *blame, + size_t lineno) +{ + return git_blame_hunk_byline(blame, lineno); +} +#endif + static int normalize_options( git_blame_options *out, const git_blame_options *in, @@ -444,9 +471,9 @@ static int buffer_hunk_cb( GIT_UNUSED(delta); - wedge_line = (hunk->new_start >= hunk->old_start || hunk->old_lines==0) ? hunk->new_start : hunk->old_start; + wedge_line = (hunk->new_start >= hunk->old_start || hunk->old_lines==0) ? hunk->new_start : hunk->old_start; blame->current_diff_line = wedge_line; - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byline(blame, wedge_line); + blame->current_hunk = (git_blame_hunk*)git_blame_hunk_byline(blame, wedge_line); if (!blame->current_hunk) { /* Line added at the end of the file */ blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, @@ -504,8 +531,8 @@ static int buffer_line_cb( if (!git_vector_search2(&i, &blame->hunks, ptrs_equal_cmp, blame->current_hunk)) { git_vector_remove(&blame->hunks, i); free_hunk(blame->current_hunk); - i_next = min( i , blame->hunks.length -1); - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i_next); + i_next = min( i , blame->hunks.length -1); + blame->current_hunk = (git_blame_hunk*)git_blame_hunk_byindex(blame, (uint32_t)i_next); } } shift_hunks_by(&blame->hunks, shift_base, -1); diff --git a/tests/libgit2/blame/blame_helpers.c b/tests/libgit2/blame/blame_helpers.c index 8aeaa58866a..c8c3d48329f 100644 --- a/tests/libgit2/blame/blame_helpers.c +++ b/tests/libgit2/blame/blame_helpers.c @@ -18,7 +18,7 @@ void check_blame_hunk_index(git_repository *repo, git_blame *blame, int idx, size_t start_line, size_t len, char boundary, const char *commit_id, const char *orig_path) { char expected[GIT_OID_SHA1_HEXSIZE+1] = {0}, actual[GIT_OID_SHA1_HEXSIZE+1] = {0}; - const git_blame_hunk *hunk = git_blame_get_hunk_byindex(blame, idx); + const git_blame_hunk *hunk = git_blame_hunk_byindex(blame, idx); cl_assert(hunk); if (!strncmp(commit_id, "0000", 4)) { diff --git a/tests/libgit2/blame/buffer.c b/tests/libgit2/blame/buffer.c index 456402c4e8b..cf70dbb31bc 100644 --- a/tests/libgit2/blame/buffer.c +++ b/tests/libgit2/blame/buffer.c @@ -220,14 +220,14 @@ void test_blame_buffer__index(void) cl_git_pass(git_blame_file(&g_fileblame, g_repo, "file.txt", NULL)); cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 1, 0, "836bc00b", "file.txt"); - hunk = git_blame_get_hunk_byline(g_bufferblame, 1); + hunk = git_blame_hunk_byline(g_bufferblame, 1); cl_assert(hunk); cl_assert_equal_s("lhchavez", hunk->final_signature->name); check_blame_hunk_index(g_repo, g_bufferblame, 1, 2, 1, 0, "00000000", "file.txt"); - hunk = git_blame_get_hunk_byline(g_bufferblame, 2); + hunk = git_blame_hunk_byline(g_bufferblame, 2); cl_assert(hunk); cl_assert(hunk->final_signature == NULL); } @@ -256,10 +256,10 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n"; cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(5, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(5, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, 0, "000000", "b.txt"); - hunk = git_blame_get_hunk_byline(g_bufferblame, 16); + hunk = git_blame_hunk_byline(g_bufferblame, 16); cl_assert(hunk); cl_assert_equal_s("Ben Straub", hunk->final_signature->name); } @@ -294,7 +294,7 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC \n"; cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(7, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(7, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 3, 0, "000000", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 4, 14, 3, 0, "000000", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 6, 22, 3, 0, "000000", "b.txt"); @@ -411,7 +411,7 @@ abc\n\ def\n"; cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(5, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(5, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 5, 0, "63d671eb", "b.txt"); diff --git a/tests/libgit2/blame/getters.c b/tests/libgit2/blame/getters.c index c160cd38367..eb7936a9be5 100644 --- a/tests/libgit2/blame/getters.c +++ b/tests/libgit2/blame/getters.c @@ -37,20 +37,20 @@ void test_blame_getters__cleanup(void) void test_blame_getters__byindex(void) { - const git_blame_hunk *h = git_blame_get_hunk_byindex(g_blame, 2); + const git_blame_hunk *h = git_blame_hunk_byindex(g_blame, 2); cl_assert(h); cl_assert_equal_s(h->orig_path, "c"); - h = git_blame_get_hunk_byindex(g_blame, 95); + h = git_blame_hunk_byindex(g_blame, 95); cl_assert_equal_p(h, NULL); } void test_blame_getters__byline(void) { - const git_blame_hunk *h = git_blame_get_hunk_byline(g_blame, 5); + const git_blame_hunk *h = git_blame_hunk_byline(g_blame, 5); cl_assert(h); cl_assert_equal_s(h->orig_path, "b"); - h = git_blame_get_hunk_byline(g_blame, 95); + h = git_blame_hunk_byline(g_blame, 95); cl_assert_equal_p(h, NULL); } diff --git a/tests/libgit2/blame/harder.c b/tests/libgit2/blame/harder.c index e7774172051..412949a3bb9 100644 --- a/tests/libgit2/blame/harder.c +++ b/tests/libgit2/blame/harder.c @@ -10,7 +10,7 @@ * |\ * | * (B) aa06ecc * * | (C) 63d671e - * |/ + * |/ * * (D) da23739 * * (E) b99f7ac * @@ -71,7 +71,7 @@ void test_blame_harder__ccc(void) git_blame_options opts = GIT_BLAME_OPTIONS_INIT; GIT_UNUSED(opts); - + /* Attribute the third hunk in b.txt to (E). This hunk was deleted from * a.txt in (D), but reintroduced in (B). */ diff --git a/tests/libgit2/blame/simple.c b/tests/libgit2/blame/simple.c index 6b13cccd418..ee6d5f866c0 100644 --- a/tests/libgit2/blame/simple.c +++ b/tests/libgit2/blame/simple.c @@ -27,7 +27,7 @@ void test_blame_simple__trivial_testrepo(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo/.gitted"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "branch_file.txt", NULL)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 1, 0, "c47800c7", "branch_file.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 2, 1, 0, "a65fedf3", "branch_file.txt"); } @@ -57,7 +57,7 @@ void test_blame_simple__trivial_blamerepo(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", NULL)); - cl_assert_equal_i(4, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(4, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 5, 0, "63d671eb", "b.txt"); @@ -233,7 +233,7 @@ void test_blame_simple__can_restrict_lines_min(void) opts.min_line = 8; cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 8, 3, 0, "63d671eb", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 11, 5, 0, "aa06ecca", "b.txt"); } @@ -252,7 +252,7 @@ void test_blame_simple__can_ignore_whitespace_change(void) opts.flags |= GIT_BLAME_IGNORE_WHITESPACE; cl_git_pass(git_blame_file(&g_blame, g_repo, "c.txt", &opts)); - cl_assert_equal_i(1, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(1, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "702c7aa5", "c.txt"); } @@ -275,7 +275,7 @@ void test_blame_simple__can_restrict_lines_max(void) opts.max_line = 6; cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(3, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(3, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 1, 0, "63d671eb", "b.txt"); @@ -301,7 +301,7 @@ void test_blame_simple__can_restrict_lines_both(void) opts.min_line = 2; opts.max_line = 7; cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(3, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(3, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 2, 3, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 2, 0, "63d671eb", "b.txt"); @@ -314,7 +314,7 @@ void test_blame_simple__can_blame_huge_file(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "huge.txt", &opts)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 65536, 0, "4eecfea", "huge.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 65537, 1, 0, "6653ff4", "huge.txt"); } @@ -341,7 +341,7 @@ void test_blame_simple__can_restrict_to_newish_commits(void) cl_git_pass(git_blame_file(&g_blame, g_repo, "branch_file.txt", &opts)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 1, 1, "be3563a", "branch_file.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 2, 1, 0, "a65fedf", "branch_file.txt"); } @@ -354,7 +354,7 @@ void test_blame_simple__can_restrict_to_first_parent_commits(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(4, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(4, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 5, 0, "63d671eb", "b.txt"); diff --git a/tests/libgit2/mailmap/blame.c b/tests/libgit2/mailmap/blame.c index e6bc1a41f43..ce2c9d48a00 100644 --- a/tests/libgit2/mailmap/blame.c +++ b/tests/libgit2/mailmap/blame.c @@ -33,7 +33,7 @@ void test_mailmap_blame__hunks(void) cl_assert(g_blame); for (idx = 0; idx < ARRAY_SIZE(resolved); ++idx) { - hunk = git_blame_get_hunk_byline(g_blame, idx + 1); + hunk = git_blame_hunk_byline(g_blame, idx + 1); cl_assert(hunk->final_signature != NULL); cl_assert(hunk->orig_signature != NULL); @@ -54,7 +54,7 @@ void test_mailmap_blame__hunks_no_mailmap(void) cl_assert(g_blame); for (idx = 0; idx < ARRAY_SIZE(resolved); ++idx) { - hunk = git_blame_get_hunk_byline(g_blame, idx + 1); + hunk = git_blame_hunk_byline(g_blame, idx + 1); cl_assert(hunk->final_signature != NULL); cl_assert(hunk->orig_signature != NULL); From 5378b80a9f0a23d4a8cdda154abbbb5277587eb6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 9 Jul 2024 20:03:25 +0100 Subject: [PATCH 639/816] blame: add final committer information Our blame implementation tracks final _author_ but not final _committer_. Make it so. --- include/git2/blame.h | 14 ++++++++++++++ src/libgit2/blame.c | 20 ++++++++++++++++---- tests/libgit2/blame/getters.c | 10 +++++----- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/include/git2/blame.h b/include/git2/blame.h index dec2a8a3fa1..f6ef61c3cf0 100644 --- a/include/git2/blame.h +++ b/include/git2/blame.h @@ -165,6 +165,13 @@ typedef struct git_blame_hunk { */ git_signature *final_signature; + /** + * The committer of `final_commit_id`. If `GIT_BLAME_USE_MAILMAP` has + * been specified, it will contain the canonical real name and email + * address. + */ + git_signature *final_committer; + /** * The OID of the commit where this hunk was found. * This will usually be the same as `final_commit_id`, except when @@ -190,6 +197,13 @@ typedef struct git_blame_hunk { */ git_signature *orig_signature; + /** + * The committer of `orig_commit_id`. If `GIT_BLAME_USE_MAILMAP` has + * been specified, it will contain the canonical real name and email + * address. + */ + git_signature *orig_committer; + /** * The 1 iff the hunk has been tracked to a boundary commit (the root, * or the commit specified in git_blame_options.oldest_commit) diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index 7b872dc7636..25f28db40c8 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -82,7 +82,9 @@ static void free_hunk(git_blame_hunk *hunk) { git__free((void*)hunk->orig_path); git_signature_free(hunk->final_signature); + git_signature_free(hunk->final_committer); git_signature_free(hunk->orig_signature); + git_signature_free(hunk->orig_committer); git__free(hunk); } @@ -103,7 +105,9 @@ static git_blame_hunk *dup_hunk(git_blame_hunk *hunk, git_blame *blame) newhunk->boundary = hunk->boundary; if (git_signature_dup(&newhunk->final_signature, hunk->final_signature) < 0 || - git_signature_dup(&newhunk->orig_signature, hunk->orig_signature) < 0) { + git_signature_dup(&newhunk->final_committer, hunk->final_committer) < 0 || + git_signature_dup(&newhunk->orig_signature, hunk->orig_signature) < 0 || + git_signature_dup(&newhunk->orig_committer, hunk->orig_committer) < 0) { free_hunk(newhunk); return NULL; } @@ -343,9 +347,17 @@ static git_blame_hunk *hunk_from_entry(git_blame__entry *e, git_blame *blame) git_oid_cpy(&h->final_commit_id, git_commit_id(e->suspect->commit)); git_oid_cpy(&h->orig_commit_id, git_commit_id(e->suspect->commit)); - git_commit_author_with_mailmap( - &h->final_signature, e->suspect->commit, blame->mailmap); - git_signature_dup(&h->orig_signature, h->final_signature); + + if (git_commit_author_with_mailmap( + &h->final_signature, e->suspect->commit, blame->mailmap) < 0 || + git_commit_committer_with_mailmap( + &h->final_committer, e->suspect->commit, blame->mailmap) < 0 || + git_signature_dup(&h->orig_signature, h->final_signature) < 0 || + git_signature_dup(&h->orig_committer, h->final_committer) < 0) { + free_hunk(h); + return NULL; + } + h->boundary = e->is_boundary ? 1 : 0; return h; } diff --git a/tests/libgit2/blame/getters.c b/tests/libgit2/blame/getters.c index eb7936a9be5..fc7e4444591 100644 --- a/tests/libgit2/blame/getters.c +++ b/tests/libgit2/blame/getters.c @@ -10,11 +10,11 @@ void test_blame_getters__initialize(void) git_blame_options opts = GIT_BLAME_OPTIONS_INIT; git_blame_hunk hunks[] = { - { 3, GIT_OID_SHA1_ZERO, 1, NULL, GIT_OID_SHA1_ZERO, "a", 0}, - { 3, GIT_OID_SHA1_ZERO, 4, NULL, GIT_OID_SHA1_ZERO, "b", 0}, - { 3, GIT_OID_SHA1_ZERO, 7, NULL, GIT_OID_SHA1_ZERO, "c", 0}, - { 3, GIT_OID_SHA1_ZERO, 10, NULL, GIT_OID_SHA1_ZERO, "d", 0}, - { 3, GIT_OID_SHA1_ZERO, 13, NULL, GIT_OID_SHA1_ZERO, "e", 0}, + { 3, GIT_OID_SHA1_ZERO, 1, NULL, NULL, GIT_OID_SHA1_ZERO, "a", 0}, + { 3, GIT_OID_SHA1_ZERO, 4, NULL, NULL, GIT_OID_SHA1_ZERO, "b", 0}, + { 3, GIT_OID_SHA1_ZERO, 7, NULL, NULL, GIT_OID_SHA1_ZERO, "c", 0}, + { 3, GIT_OID_SHA1_ZERO, 10, NULL, NULL, GIT_OID_SHA1_ZERO, "d", 0}, + { 3, GIT_OID_SHA1_ZERO, 13, NULL, NULL, GIT_OID_SHA1_ZERO, "e", 0}, }; g_blame = git_blame__alloc(NULL, opts, ""); From 49402cc61451db8d29bc8aa0a568318b78ebf01c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 9 Jul 2024 20:04:39 +0100 Subject: [PATCH 640/816] blame: add commit summary information --- include/git2/blame.h | 5 +++++ src/libgit2/blame.c | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/git2/blame.h b/include/git2/blame.h index f6ef61c3cf0..99f481c453d 100644 --- a/include/git2/blame.h +++ b/include/git2/blame.h @@ -204,6 +204,11 @@ typedef struct git_blame_hunk { */ git_signature *orig_committer; + /* + * The summary of the commit. + */ + const char *summary; + /** * The 1 iff the hunk has been tracked to a boundary commit (the root, * or the commit specified in git_blame_options.oldest_commit) diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index 25f28db40c8..6db0fa6c4ee 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -80,7 +80,8 @@ static git_blame_hunk *new_hunk( static void free_hunk(git_blame_hunk *hunk) { - git__free((void*)hunk->orig_path); + git__free((char *)hunk->orig_path); + git__free((char *)hunk->summary); git_signature_free(hunk->final_signature); git_signature_free(hunk->final_committer); git_signature_free(hunk->orig_signature); @@ -107,7 +108,8 @@ static git_blame_hunk *dup_hunk(git_blame_hunk *hunk, git_blame *blame) if (git_signature_dup(&newhunk->final_signature, hunk->final_signature) < 0 || git_signature_dup(&newhunk->final_committer, hunk->final_committer) < 0 || git_signature_dup(&newhunk->orig_signature, hunk->orig_signature) < 0 || - git_signature_dup(&newhunk->orig_committer, hunk->orig_committer) < 0) { + git_signature_dup(&newhunk->orig_committer, hunk->orig_committer) < 0 || + (newhunk->summary = git__strdup(hunk->summary)) == NULL) { free_hunk(newhunk); return NULL; } @@ -338,6 +340,7 @@ static int index_blob_lines(git_blame *blame) static git_blame_hunk *hunk_from_entry(git_blame__entry *e, git_blame *blame) { + const char *summary; git_blame_hunk *h = new_hunk( e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path, blame); @@ -353,7 +356,9 @@ static git_blame_hunk *hunk_from_entry(git_blame__entry *e, git_blame *blame) git_commit_committer_with_mailmap( &h->final_committer, e->suspect->commit, blame->mailmap) < 0 || git_signature_dup(&h->orig_signature, h->final_signature) < 0 || - git_signature_dup(&h->orig_committer, h->final_committer) < 0) { + git_signature_dup(&h->orig_committer, h->final_committer) < 0 || + (summary = git_commit_summary(e->suspect->commit)) == NULL || + (h->summary = git__strdup(summary)) == NULL) { free_hunk(h); return NULL; } From 1474c892f90de07e21d37c8f45c37f429408a4a2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 9 Jul 2024 20:12:08 +0100 Subject: [PATCH 641/816] cli: introduce `cli_resolve_path` The git CLI takes paths as command-line inputs from the current working directory; provide a helper method to provide a repo-relative path based on paths specified on the command-line. --- src/cli/common.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/cli/common.h | 5 +++++ 2 files changed, 47 insertions(+) diff --git a/src/cli/common.c b/src/cli/common.c index fcb3676cef0..dbeefea48ed 100644 --- a/src/cli/common.c +++ b/src/cli/common.c @@ -10,6 +10,7 @@ #include "git2_util.h" #include "vector.h" +#include "fs_path.h" #include "common.h" #include "error.h" @@ -124,3 +125,44 @@ int cli_repository_open( *out = repo; return 0; } + +/* + * This resolves paths - not _pathspecs_ like git - it accepts an absolute + * path (to a path within the repository working directory) or a path + * relative to the current directory. + */ +int cli_resolve_path(git_str *out, git_repository *repo, const char *given_path) +{ + git_str path = GIT_STR_INIT; + int error = 0; + + if (!git_fs_path_is_absolute(given_path)) { + char cwd[GIT_PATH_MAX]; + + if (p_getcwd(cwd, GIT_PATH_MAX) < 0) + error = cli_error_os(); + else if (git_str_puts(&path, cwd) < 0 || + git_fs_path_apply_relative(&path, given_path) < 0) + error = cli_error_git(); + + if (error) + goto done; + } else if (git_str_puts(&path, given_path) < 0) { + error = cli_error_git(); + goto done; + } + + error = git_fs_path_make_relative(&path, git_repository_workdir(repo)); + + if (error == GIT_ENOTFOUND) + error = cli_error("path '%s' is not inside the git repository '%s'", + given_path, git_repository_workdir(repo)); + else if (error < 0) + error = cli_error_git(); + else + git_str_swap(out, &path); + +done: + git_str_dispose(&path); + return error; +} diff --git a/src/cli/common.h b/src/cli/common.h index 3aed8ad8a42..6392ae68580 100644 --- a/src/cli/common.h +++ b/src/cli/common.h @@ -44,6 +44,11 @@ extern int cli_repository_open( git_repository **out, cli_repository_open_options *opts); +extern int cli_resolve_path( + git_str *out, + git_repository *repo, + const char *given_path); + /* * Common command arguments. */ From 1ee2c339934fdf00d30a24a361c94809918bdf33 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 9 Jul 2024 20:14:26 +0100 Subject: [PATCH 642/816] blame: provide line accessor blame: introduce git_blame_line Provide a structure that can provide the line-level information. --- include/git2/blame.h | 26 +++++++++++++++++++++++ src/libgit2/blame.c | 49 ++++++++++++++++++++++++++++++++++++++++---- src/libgit2/blame.h | 1 + 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/include/git2/blame.h b/include/git2/blame.h index 99f481c453d..2ddd9e077e0 100644 --- a/include/git2/blame.h +++ b/include/git2/blame.h @@ -216,10 +216,25 @@ typedef struct git_blame_hunk { char boundary; } git_blame_hunk; +/** + * Structure that represents a line in a blamed file. + */ +typedef struct git_blame_line { + const char *ptr; + size_t len; +} git_blame_line; /** Opaque structure to hold blame results */ typedef struct git_blame git_blame; +/** + * Gets the number of lines that exist in the blame structure. + * + * @param blame The blame structure to query. + * @return The number of line. + */ +GIT_EXTERN(size_t) git_blame_linecount(git_blame *blame); + /** * Gets the number of hunks that exist in the blame structure. * @@ -251,6 +266,17 @@ GIT_EXTERN(const git_blame_hunk *) git_blame_hunk_byline( git_blame *blame, size_t lineno); +/** + * Gets the information about the line in the blame. + * + * @param blame the blame structure to query + * @param idx the (1-based) line number + * @return the blamed line, or NULL on error + */ +GIT_EXTERN(const git_blame_line *) git_blame_line_byindex( + git_blame *blame, + size_t idx); + #ifndef GIT_DEPRECATE_HARD /** * Gets the number of hunks that exist in the blame structure. diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index 6db0fa6c4ee..bb1e6e271ff 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -144,10 +144,9 @@ git_blame *git_blame__alloc( gbr->options = opts; if (git_vector_init(&gbr->hunks, 8, hunk_cmp) < 0 || - git_vector_init(&gbr->paths, 8, paths_cmp) < 0 || - (gbr->path = git__strdup(path)) == NULL || - git_vector_insert(&gbr->paths, git__strdup(path)) < 0) - { + git_vector_init(&gbr->paths, 8, paths_cmp) < 0 || + (gbr->path = git__strdup(path)) == NULL || + git_vector_insert(&gbr->paths, git__strdup(path)) < 0) { git_blame_free(gbr); return NULL; } @@ -170,7 +169,9 @@ void git_blame_free(git_blame *blame) git_vector_foreach(&blame->hunks, i, hunk) free_hunk(hunk); + git_vector_dispose(&blame->hunks); + git_array_clear(blame->lines); git_vector_dispose_deep(&blame->paths); @@ -190,6 +191,23 @@ size_t git_blame_hunkcount(git_blame *blame) return blame->hunks.length; } +size_t git_blame_linecount(git_blame *blame) +{ + GIT_ASSERT_ARG(blame); + + return git_array_size(blame->line_index); +} + +const git_blame_line *git_blame_line_byindex( + git_blame *blame, + size_t idx) +{ + GIT_ASSERT_ARG_WITH_RETVAL(blame, NULL); + GIT_ASSERT_WITH_RETVAL(idx > 0 && idx <= git_array_size(blame->line_index), NULL); + + return git_array_get(blame->lines, idx - 1); +} + const git_blame_hunk *git_blame_hunk_byindex( git_blame *blame, size_t index) @@ -315,25 +333,48 @@ static int index_blob_lines(git_blame *blame) const char *buf = blame->final_buf; size_t len = blame->final_buf_size; int num = 0, incomplete = 0, bol = 1; + git_blame_line *line = NULL; size_t *i; if (len && buf[len-1] != '\n') incomplete++; /* incomplete line at the end */ + while (len--) { if (bol) { i = git_array_alloc(blame->line_index); GIT_ERROR_CHECK_ALLOC(i); *i = buf - blame->final_buf; + + GIT_ASSERT(line == NULL); + line = git_array_alloc(blame->lines); + GIT_ERROR_CHECK_ALLOC(line); + + line->ptr = buf; bol = 0; } + if (*buf++ == '\n') { + GIT_ASSERT(line); + line->len = (buf - line->ptr) - 1; + line = NULL; + num++; bol = 1; } } + i = git_array_alloc(blame->line_index); GIT_ERROR_CHECK_ALLOC(i); *i = buf - blame->final_buf; + + if (!bol) { + GIT_ASSERT(line); + line->len = buf - line->ptr; + line = NULL; + } + + GIT_ASSERT(!line); + blame->num_lines = num + incomplete; return blame->num_lines; } diff --git a/src/libgit2/blame.h b/src/libgit2/blame.h index 4141e2bb557..152834ebba7 100644 --- a/src/libgit2/blame.h +++ b/src/libgit2/blame.h @@ -71,6 +71,7 @@ struct git_blame { git_blame_options options; git_vector hunks; + git_array_t(git_blame_line) lines; git_vector paths; git_blob *final_blob; From b02a858e0cad67d59ca6a6ff116d10af7e118383 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Oct 2024 10:24:19 +0100 Subject: [PATCH 643/816] fips: clear context after finalization Clear the FIPS-compatible OpenSSL context when completed; this will aide debugging during improper usage. --- src/util/hash/openssl.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/util/hash/openssl.c b/src/util/hash/openssl.c index 06297eea96f..1ed1b4409f9 100644 --- a/src/util/hash/openssl.c +++ b/src/util/hash/openssl.c @@ -168,7 +168,7 @@ int git_hash_sha1_init(git_hash_sha1_ctx *ctx) int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) { - GIT_ASSERT_ARG(ctx); + GIT_ASSERT_ARG(ctx && ctx->c); if (EVP_DigestUpdate(ctx->c, data, len) != 1) { git_error_set(GIT_ERROR_SHA, "failed to update sha1"); @@ -181,13 +181,16 @@ int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) { unsigned int len = 0; - GIT_ASSERT_ARG(ctx); + + GIT_ASSERT_ARG(ctx && ctx->c); if (EVP_DigestFinal(ctx->c, out, &len) != 1) { git_error_set(GIT_ERROR_SHA, "failed to finalize sha1"); return -1; } + ctx->c = NULL; + return 0; } @@ -315,7 +318,7 @@ int git_hash_sha256_init(git_hash_sha256_ctx *ctx) int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) { - GIT_ASSERT_ARG(ctx); + GIT_ASSERT_ARG(ctx && ctx->c); if (EVP_DigestUpdate(ctx->c, data, len) != 1) { git_error_set(GIT_ERROR_SHA, "failed to update sha256"); @@ -328,13 +331,16 @@ int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t le int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) { unsigned int len = 0; - GIT_ASSERT_ARG(ctx); + + GIT_ASSERT_ARG(ctx && ctx->c); if (EVP_DigestFinal(ctx->c, out, &len) != 1) { git_error_set(GIT_ERROR_SHA, "failed to finalize sha256"); return -1; } + ctx->c = NULL; + return 0; } From 637ab37e4bf6a42ea2a2a775468b3791b86cad05 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Oct 2024 10:23:00 +0100 Subject: [PATCH 644/816] commitgraph: don't update finalized hash Ensure that we don't update the finalized commit graph hash; clear it instead. --- src/libgit2/commit_graph.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index e8d64de3a60..8fd59692730 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -1027,9 +1027,12 @@ static int commit_graph_write_hash(const char *buf, size_t size, void *data) struct commit_graph_write_hash_context *ctx = data; int error; - error = git_hash_update(ctx->ctx, buf, size); - if (error < 0) - return error; + if (ctx->ctx) { + error = git_hash_update(ctx->ctx, buf, size); + + if (error < 0) + return error; + } return ctx->write_cb(buf, size, ctx->cb_data); } @@ -1225,6 +1228,9 @@ static int commit_graph_write( error = git_hash_final(checksum, &ctx); if (error < 0) goto cleanup; + + hash_cb_data.ctx = NULL; + error = write_cb((char *)checksum, checksum_size, cb_data); if (error < 0) goto cleanup; From a7ca589b43e7aefccbfe994c964c8ce0e262f5f3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Oct 2024 10:30:02 +0100 Subject: [PATCH 645/816] midx: don't update finalized hash Ensure that we don't update the finalized commit graph hash; clear it instead. --- src/libgit2/midx.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index 9ec1c3dcd0e..0b16af94390 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -660,9 +660,11 @@ static int midx_write_hash(const char *buf, size_t size, void *data) struct midx_write_hash_context *ctx = (struct midx_write_hash_context *)data; int error; - error = git_hash_update(ctx->ctx, buf, size); - if (error < 0) - return error; + if (ctx->ctx) { + error = git_hash_update(ctx->ctx, buf, size); + if (error < 0) + return error; + } return ctx->write_cb(buf, size, ctx->cb_data); } @@ -863,6 +865,9 @@ static int midx_write( error = git_hash_final(checksum, &ctx); if (error < 0) goto cleanup; + + hash_cb_data.ctx = NULL; + error = write_cb((char *)checksum, checksum_size, cb_data); if (error < 0) goto cleanup; From 8cf4cc2a9f9807e24b4e8f5e8a12846d7284d128 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 10 Oct 2024 23:16:20 +0100 Subject: [PATCH 646/816] ci: test FIPS on Linux only --- .github/workflows/nightly.yml | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index df43ff5690a..81db85ac410 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -373,34 +373,15 @@ jobs: CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Linux (SHA256-FIPS, Xenial, Clang, OpenSSL)" + - name: "Linux (SHA256, Xenial, Clang, OpenSSL-FIPS)" id: linux-sha256-fips container: name: xenial env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DUSE_SHA256="OpenSSL-FIPS" + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DUSE_SHA1=OpenSSL-FIPS -DUSE_SHA256=OpenSSL-FIPS os: ubuntu-latest - - name: "macOS (SHA256-FIPS)" - id: macos-sha256-fips - os: macos-13 - setup-script: osx - env: - CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON -DUSE_SHA256="OpenSSL-FIPS" - PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (SHA256-FIPS, amd64, Visual Studio)" - id: windows-sha256-fips - os: windows-2022 - env: - ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 17 2022 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON -DUSE_SHA256="OpenSSL-FIPS" - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true fail-fast: false env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} From 1925889139f3cd028b1c7d6133c176c27d9f6463 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 9 Jul 2024 20:14:47 +0100 Subject: [PATCH 647/816] cli: add a blame command --- src/cli/cmd.h | 1 + src/cli/cmd_blame.c | 288 ++++++++++++++++++++++++++++++++++++++++++++ src/cli/main.c | 1 + 3 files changed, 290 insertions(+) create mode 100644 src/cli/cmd_blame.c diff --git a/src/cli/cmd.h b/src/cli/cmd.h index bd881223db9..5ac67f52615 100644 --- a/src/cli/cmd.h +++ b/src/cli/cmd.h @@ -25,6 +25,7 @@ extern const cli_cmd_spec cli_cmds[]; extern const cli_cmd_spec *cli_cmd_spec_byname(const char *name); /* Commands */ +extern int cmd_blame(int argc, char **argv); extern int cmd_cat_file(int argc, char **argv); extern int cmd_clone(int argc, char **argv); extern int cmd_config(int argc, char **argv); diff --git a/src/cli/cmd_blame.c b/src/cli/cmd_blame.c new file mode 100644 index 00000000000..3e2f5744ca9 --- /dev/null +++ b/src/cli/cmd_blame.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include "common.h" +#include "cmd.h" +#include "error.h" +#include "sighandler.h" +#include "progress.h" + +#include "fs_path.h" +#include "futils.h" +#include "date.h" +#include "hashmap.h" + +#define COMMAND_NAME "blame" + +static char *file; +static int porcelain, line_porcelain; +static int show_help; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, + + { CLI_OPT_TYPE_SWITCH, "porcelain", 'p', &porcelain, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "show machine readable output" }, + { CLI_OPT_TYPE_SWITCH, "line-porcelain", 0, &line_porcelain, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "show individual lines in machine readable output" }, + { CLI_OPT_TYPE_LITERAL }, + { CLI_OPT_TYPE_ARG, "file", 0, &file, 0, + CLI_OPT_USAGE_REQUIRED, "file", "file to blame" }, + + { 0 } +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Show the origin of each line of a file.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +static int strintlen(size_t n) +{ + int len = 1; + + while (n > 10) { + n /= 10; + len++; + + if (len == INT_MAX) + break; + } + + return len; +} + +static int fmt_date(git_str *out, git_time_t time, int offset) +{ + time_t t; + struct tm gmt; + + GIT_ASSERT_ARG(out); + + t = (time_t)(time + offset * 60); + + if (p_gmtime_r(&t, &gmt) == NULL) + return -1; + + return git_str_printf(out, "%.4u-%02u-%02u %02u:%02u:%02u %+03d%02d", + gmt.tm_year + 1900, gmt.tm_mon + 1, gmt.tm_mday, + gmt.tm_hour, gmt.tm_min, gmt.tm_sec, + offset / 60, offset % 60); +} + +static int print_standard(git_blame *blame) +{ + size_t max_line_number = 0; + int max_lineno_len, max_line_len, max_author_len = 0, max_path_len = 0; + const char *last_path = NULL; + const git_blame_line *line; + bool paths_differ = false; + git_str date_str = GIT_STR_INIT; + size_t i; + int ret = 0; + + /* Compute the maximum size of things */ + for (i = 0; i < git_blame_hunkcount(blame); i++) { + const git_blame_hunk *hunk = git_blame_hunk_byindex(blame, i); + size_t hunk_author_len = strlen(hunk->orig_signature->name); + size_t hunk_path_len = strlen(hunk->orig_path); + size_t hunk_max_line_number = + hunk->orig_start_line_number + hunk->lines_in_hunk; + + if (hunk_max_line_number > max_line_number) + max_line_number = hunk_max_line_number; + + if (hunk_author_len > INT_MAX) + max_author_len = INT_MAX; + else if ((int)hunk_author_len > max_author_len) + max_author_len = (int)hunk_author_len; + + if (hunk_path_len > INT_MAX) + hunk_path_len = INT_MAX; + else if ((int)hunk_path_len > max_path_len) + max_path_len = (int)hunk_path_len; + + if (!paths_differ && last_path != NULL && + strcmp(last_path, hunk->orig_path) != 0) { + paths_differ = true; + } + + last_path = hunk->orig_path; + } + + max_lineno_len = strintlen(max_line_number); + + max_author_len--; + + for (i = 1; i < git_blame_linecount(blame); i++) { + const git_blame_hunk *hunk = git_blame_hunk_byline(blame, i); + int oid_abbrev; + + if (!hunk) + break; + + oid_abbrev = hunk->boundary ? 7 : 8; + printf("%s%.*s ", hunk->boundary ? "^" : "", + oid_abbrev, git_oid_tostr_s(&hunk->orig_commit_id)); + + if (paths_differ) + printf("%-*.*s ", max_path_len, max_path_len, hunk->orig_path); + + git_str_clear(&date_str); + if (fmt_date(&date_str, + hunk->orig_signature->when.time, + hunk->orig_signature->when.offset) < 0) { + ret = cli_error_git(); + goto done; + } + + if ((line = git_blame_line_byindex(blame, i)) == NULL) { + ret = cli_error_git(); + goto done; + } + + max_line_len = (int)min(line->len, INT_MAX); + + printf("(%-*.*s %s %*" PRIuZ ") %.*s" , + max_author_len, max_author_len, hunk->orig_signature->name, + date_str.ptr, + max_lineno_len, i, + max_line_len, line->ptr); + printf("\n"); + } + +done: + git_str_dispose(&date_str); + return ret; +} + +GIT_INLINE(uint32_t) oid_hashcode(const git_oid *oid) +{ + uint32_t hash; + memcpy(&hash, oid->id, sizeof(uint32_t)); + return hash; +} + +GIT_HASHSET_SETUP(git_blame_commitmap, const git_oid *, oid_hashcode, git_oid_equal); + +static int print_porcelain(git_blame *blame) +{ + git_blame_commitmap seen_ids = GIT_HASHSET_INIT; + size_t i, j; + + for (i = 0; i < git_blame_hunkcount(blame); i++) { + const git_blame_line *line; + const git_blame_hunk *hunk = git_blame_hunk_byindex(blame, i); + + for (j = 0; j < hunk->lines_in_hunk; j++) { + size_t line_number = hunk->final_start_line_number + j; + bool seen = git_blame_commitmap_contains(&seen_ids, &hunk->orig_commit_id); + + printf("%s %" PRIuZ " %" PRIuZ, + git_oid_tostr_s(&hunk->orig_commit_id), + hunk->orig_start_line_number + j, + hunk->final_start_line_number + j); + + if (!j) + printf(" %" PRIuZ, hunk->lines_in_hunk); + + printf("\n"); + + if ((!j && !seen) || line_porcelain) { + printf("author %s\n", hunk->orig_signature->name); + printf("author-mail <%s>\n", hunk->orig_signature->email); + printf("author-time %" PRId64 "\n", hunk->orig_signature->when.time); + printf("author-tz %+03d%02d\n", + hunk->orig_signature->when.offset / 60, + hunk->orig_signature->when.offset % 60); + + printf("committer %s\n", hunk->orig_committer->name); + printf("committer-mail <%s>\n", hunk->orig_committer->email); + printf("committer-time %" PRId64 "\n", hunk->orig_committer->when.time); + printf("committer-tz %+03d%02d\n", + hunk->orig_committer->when.offset / 60, + hunk->orig_committer->when.offset % 60); + + printf("summary %s\n", hunk->summary); + + /* TODO: previous */ + + printf("filename %s\n", hunk->orig_path); + } + + if ((line = git_blame_line_byindex(blame, line_number)) == NULL) + return cli_error_git(); + + printf("\t%.*s\n", (int)min(line->len, INT_MAX), + line->ptr); + + if (!seen) + git_blame_commitmap_add(&seen_ids, &hunk->orig_commit_id); + } + } + + git_blame_commitmap_dispose(&seen_ids); + return 0; +} + +int cmd_blame(int argc, char **argv) +{ + cli_repository_open_options open_opts = { argv + 1, argc - 1 }; + git_blame_options blame_opts = GIT_BLAME_OPTIONS_INIT; + git_repository *repo = NULL; + git_str workdir_path = GIT_STR_INIT; + git_blame *blame = NULL; + cli_opt invalid_opt; + int ret = 0; + + blame_opts.flags |= GIT_BLAME_USE_MAILMAP; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (!file) { + ret = cli_error_usage("you must specify a file to blame"); + goto done; + } + + if (cli_repository_open(&repo, &open_opts) < 0) + return cli_error_git(); + + if ((ret = cli_resolve_path(&workdir_path, repo, file)) != 0) + goto done; + + if (git_blame_file(&blame, repo, workdir_path.ptr, &blame_opts) < 0) { + ret = cli_error_git(); + goto done; + } + + if (porcelain || line_porcelain) + ret = print_porcelain(blame); + else + ret = print_standard(blame); + +done: + git_str_dispose(&workdir_path); + git_blame_free(blame); + git_repository_free(repo); + return ret; +} diff --git a/src/cli/main.c b/src/cli/main.c index c7a6fcfce26..715feab8998 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -32,6 +32,7 @@ const cli_opt_spec cli_common_opts[] = { }; const cli_cmd_spec cli_cmds[] = { + { "blame", cmd_blame, "Show the origin of each line of a file" }, { "cat-file", cmd_cat_file, "Display an object in the repository" }, { "clone", cmd_clone, "Clone a repository into a new directory" }, { "config", cmd_config, "View or set configuration values " }, From 2cfb83bcccf6073d426395d1648b601f1dc4ec95 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 13 Jul 2024 11:06:42 +0100 Subject: [PATCH 648/816] blame: don't try to create a blame on error When an error occurs... deal with the error, don't try to still create hunks. --- src/libgit2/blame.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index bb1e6e271ff..4f99de69bd1 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -432,12 +432,12 @@ static int blame_internal(git_blame *blame) if ((error = load_blob(blame)) < 0 || (error = git_blame__get_origin(&o, blame, blame->final, blame->path)) < 0) - goto cleanup; + goto on_error; if (git_blob_rawsize(blame->final_blob) > SIZE_MAX) { git_error_set(GIT_ERROR_NOMEMORY, "blob is too large to blame"); error = -1; - goto cleanup; + goto on_error; } blame->final_buf = git_blob_rawcontent(blame->final_blob); @@ -456,17 +456,19 @@ static int blame_internal(git_blame *blame) blame->ent = ent; - error = git_blame__like_git(blame, blame->options.flags); + if ((error = git_blame__like_git(blame, blame->options.flags)) < 0) + goto on_error; -cleanup: - for (ent = blame->ent; ent; ) { - git_blame__entry *e = ent->next; + for (ent = blame->ent; ent; ent = ent->next) { git_blame_hunk *h = hunk_from_entry(ent, blame); - git_vector_insert(&blame->hunks, h); + } +on_error: + for (ent = blame->ent; ent; ) { + git_blame__entry *next = ent->next; git_blame__free_entry(ent); - ent = e; + ent = next; } return error; From f1cac063baada36900fa1060c665c36281a8168b Mon Sep 17 00:00:00 2001 From: GravisZro Date: Mon, 18 Mar 2024 10:04:27 -0400 Subject: [PATCH 649/816] Mandate C90 conformance This PR ensures and enforces C90 conformance for all files C, including tests. * Modify CMakeLists.txt to mandate C90 conformance (for better compiler compatibility) * Update deps/ntlmclient/utf8.h to latest version * Modify two tests and one header to use C comments instead of C++ comments --- deps/ntlmclient/utf8.h | 1883 ++++++++++++++++++++------------ examples/CMakeLists.txt | 1 + fuzzers/CMakeLists.txt | 2 +- include/git2/stdint.h | 172 +-- src/cli/CMakeLists.txt | 1 + src/libgit2/CMakeLists.txt | 1 + tests/libgit2/CMakeLists.txt | 2 +- tests/libgit2/grafts/shallow.c | 4 +- tests/libgit2/index/tests256.c | 2 +- tests/util/CMakeLists.txt | 1 + 10 files changed, 1261 insertions(+), 808 deletions(-) diff --git a/deps/ntlmclient/utf8.h b/deps/ntlmclient/utf8.h index a26ae85c37e..5f02b555549 100644 --- a/deps/ntlmclient/utf8.h +++ b/deps/ntlmclient/utf8.h @@ -1,30 +1,30 @@ -// The latest version of this library is available on GitHub; -// https://github.com/sheredom/utf8.h - -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. -// -// In jurisdictions that recognize copyright laws, the author or authors -// of this software dedicate any and all copyright interest in the -// software to the public domain. We make this dedication for the benefit -// of the public at large and to the detriment of our heirs and -// successors. We intend this dedication to be an overt act of -// relinquishment in perpetuity of all present and future rights to this -// software under copyright law. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// For more information, please refer to +/* The latest version of this library is available on GitHub; + * https://github.com/sheredom/utf8.h */ + +/* This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to */ #ifndef SHEREDOM_UTF8_H_INCLUDED #define SHEREDOM_UTF8_H_INCLUDED @@ -32,7 +32,14 @@ #if defined(_MSC_VER) #pragma warning(push) -// disable 'bytes padding added after construct' warning +/* disable warning: no function prototype given: converting '()' to '(void)' */ +#pragma warning(disable : 4255) + +/* disable warning: '__cplusplus' is not defined as a preprocessor macro, + * replacing with '0' for '#if/#elif' */ +#pragma warning(disable : 4668) + +/* disable warning: bytes padding added after construct */ #pragma warning(disable : 4820) #endif @@ -43,7 +50,7 @@ #pragma warning(pop) #endif -#if defined(_MSC_VER) +#if defined(_MSC_VER) && (_MSC_VER < 1920) typedef __int32 utf8_int32_t; #else #include @@ -54,24 +61,39 @@ typedef int32_t utf8_int32_t; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" #pragma clang diagnostic ignored "-Wcast-qual" + +#if __has_warning("-Wunsafe-buffer-usage") +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#endif #endif #ifdef __cplusplus extern "C" { #endif -#if defined(__clang__) || defined(__GNUC__) -#define utf8_nonnull __attribute__((nonnull)) -#define utf8_pure __attribute__((pure)) -#define utf8_restrict __restrict__ -#define utf8_weak __attribute__((weak)) -#elif defined(_MSC_VER) +#if defined(__TINYC__) +#define UTF8_ATTRIBUTE(a) __attribute((a)) +#else +#define UTF8_ATTRIBUTE(a) __attribute__((a)) +#endif + +#if defined(_MSC_VER) #define utf8_nonnull #define utf8_pure #define utf8_restrict __restrict #define utf8_weak __inline +#elif defined(__clang__) || defined(__GNUC__) +#define utf8_nonnull UTF8_ATTRIBUTE(nonnull) +#define utf8_pure UTF8_ATTRIBUTE(pure) +#define utf8_restrict __restrict__ +#define utf8_weak UTF8_ATTRIBUTE(weak) +#elif defined(__TINYC__) +#define utf8_nonnull UTF8_ATTRIBUTE(nonnull) +#define utf8_pure UTF8_ATTRIBUTE(pure) +#define utf8_restrict +#define utf8_weak UTF8_ATTRIBUTE(weak) #else -#error Non clang, non gcc, non MSVC compiler found! +#error Non clang, non gcc, non MSVC, non tcc compiler found! #endif #ifdef __cplusplus @@ -80,385 +102,475 @@ extern "C" { #define utf8_null 0 #endif -// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > -// src2 respectively, case insensitive. -utf8_nonnull utf8_pure utf8_weak int utf8casecmp(const void *src1, - const void *src2); - -// Append the utf8 string src onto the utf8 string dst. -utf8_nonnull utf8_weak void *utf8cat(void *utf8_restrict dst, - const void *utf8_restrict src); - -// Find the first match of the utf8 codepoint chr in the utf8 string src. -utf8_nonnull utf8_pure utf8_weak void *utf8chr(const void *src, - utf8_int32_t chr); - -// Return less than 0, 0, greater than 0 if src1 < src2, -// src1 == src2, src1 > src2 respectively. -utf8_nonnull utf8_pure utf8_weak int utf8cmp(const void *src1, - const void *src2); - -// Copy the utf8 string src onto the memory allocated in dst. -utf8_nonnull utf8_weak void *utf8cpy(void *utf8_restrict dst, - const void *utf8_restrict src); - -// Number of utf8 codepoints in the utf8 string src that consists entirely -// of utf8 codepoints not from the utf8 string reject. -utf8_nonnull utf8_pure utf8_weak size_t utf8cspn(const void *src, - const void *reject); - -// Duplicate the utf8 string src by getting its size, malloc'ing a new buffer -// copying over the data, and returning that. Or 0 if malloc failed. -utf8_nonnull utf8_weak void *utf8dup(const void *src); - -// Number of utf8 codepoints in the utf8 string str, -// excluding the null terminating byte. -utf8_nonnull utf8_pure utf8_weak size_t utf8len(const void *str); - -// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > -// src2 respectively, case insensitive. Checking at most n bytes of each utf8 -// string. -utf8_nonnull utf8_pure utf8_weak int utf8ncasecmp(const void *src1, - const void *src2, size_t n); - -// Append the utf8 string src onto the utf8 string dst, -// writing at most n+1 bytes. Can produce an invalid utf8 -// string if n falls partway through a utf8 codepoint. -utf8_nonnull utf8_weak void *utf8ncat(void *utf8_restrict dst, - const void *utf8_restrict src, size_t n); - -// Return less than 0, 0, greater than 0 if src1 < src2, -// src1 == src2, src1 > src2 respectively. Checking at most n -// bytes of each utf8 string. -utf8_nonnull utf8_pure utf8_weak int utf8ncmp(const void *src1, - const void *src2, size_t n); - -// Copy the utf8 string src onto the memory allocated in dst. -// Copies at most n bytes. If there is no terminating null byte in -// the first n bytes of src, the string placed into dst will not be -// null-terminated. If the size (in bytes) of src is less than n, -// extra null terminating bytes are appended to dst such that at -// total of n bytes are written. Can produce an invalid utf8 -// string if n falls partway through a utf8 codepoint. -utf8_nonnull utf8_weak void *utf8ncpy(void *utf8_restrict dst, - const void *utf8_restrict src, size_t n); - -// Similar to utf8dup, except that at most n bytes of src are copied. If src is -// longer than n, only n bytes are copied and a null byte is added. -// -// Returns a new string if successful, 0 otherwise -utf8_nonnull utf8_weak void *utf8ndup(const void *src, size_t n); - -// Locates the first occurence in the utf8 string str of any byte in the -// utf8 string accept, or 0 if no match was found. -utf8_nonnull utf8_pure utf8_weak void *utf8pbrk(const void *str, - const void *accept); - -// Find the last match of the utf8 codepoint chr in the utf8 string src. -utf8_nonnull utf8_pure utf8_weak void *utf8rchr(const void *src, int chr); - -// Number of bytes in the utf8 string str, -// including the null terminating byte. -utf8_nonnull utf8_pure utf8_weak size_t utf8size(const void *str); - -// Number of utf8 codepoints in the utf8 string src that consists entirely -// of utf8 codepoints from the utf8 string accept. -utf8_nonnull utf8_pure utf8_weak size_t utf8spn(const void *src, - const void *accept); - -// The position of the utf8 string needle in the utf8 string haystack. -utf8_nonnull utf8_pure utf8_weak void *utf8str(const void *haystack, - const void *needle); - -// The position of the utf8 string needle in the utf8 string haystack, case -// insensitive. -utf8_nonnull utf8_pure utf8_weak void *utf8casestr(const void *haystack, - const void *needle); - -// Return 0 on success, or the position of the invalid -// utf8 codepoint on failure. -utf8_nonnull utf8_pure utf8_weak void *utf8valid(const void *str); - -// Sets out_codepoint to the next utf8 codepoint in str, and returns the address -// of the utf8 codepoint after the current one in str. -utf8_nonnull utf8_weak void * -utf8codepoint(const void *utf8_restrict str, - utf8_int32_t *utf8_restrict out_codepoint); - -// Returns the size of the given codepoint in bytes. -utf8_weak size_t utf8codepointsize(utf8_int32_t chr); - -// Write a codepoint to the given string, and return the address to the next -// place after the written codepoint. Pass how many bytes left in the buffer to -// n. If there is not enough space for the codepoint, this function returns -// null. -utf8_nonnull utf8_weak void *utf8catcodepoint(void *utf8_restrict str, - utf8_int32_t chr, size_t n); - -// Returns 1 if the given character is lowercase, or 0 if it is not. -utf8_weak int utf8islower(utf8_int32_t chr); - -// Returns 1 if the given character is uppercase, or 0 if it is not. -utf8_weak int utf8isupper(utf8_int32_t chr); - -// Transform the given string into all lowercase codepoints. -utf8_nonnull utf8_weak void utf8lwr(void *utf8_restrict str); +#if (defined(__cplusplus) && __cplusplus >= 201402L) +#define utf8_constexpr14 constexpr +#define utf8_constexpr14_impl constexpr +#else +/* constexpr and weak are incompatible. so only enable one of them */ +#define utf8_constexpr14 utf8_weak +#define utf8_constexpr14_impl +#endif -// Transform the given string into all uppercase codepoints. -utf8_nonnull utf8_weak void utf8upr(void *utf8_restrict str); +#if defined(__cplusplus) && __cplusplus >= 202002L +using utf8_int8_t = char8_t; /* Introduced in C++20 */ +#else +typedef char utf8_int8_t; +#endif -// Make a codepoint lower case if possible. -utf8_weak utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); +/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > + * src2 respectively, case insensitive. */ +utf8_constexpr14 utf8_nonnull utf8_pure int +utf8casecmp(const utf8_int8_t *src1, const utf8_int8_t *src2); + +/* Append the utf8 string src onto the utf8 string dst. */ +utf8_nonnull utf8_weak utf8_int8_t * +utf8cat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src); + +/* Find the first match of the utf8 codepoint chr in the utf8 string src. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8chr(const utf8_int8_t *src, utf8_int32_t chr); + +/* Return less than 0, 0, greater than 0 if src1 < src2, + * src1 == src2, src1 > src2 respectively. */ +utf8_constexpr14 utf8_nonnull utf8_pure int utf8cmp(const utf8_int8_t *src1, + const utf8_int8_t *src2); + +/* Copy the utf8 string src onto the memory allocated in dst. */ +utf8_nonnull utf8_weak utf8_int8_t * +utf8cpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src); + +/* Number of utf8 codepoints in the utf8 string src that consists entirely + * of utf8 codepoints not from the utf8 string reject. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8cspn(const utf8_int8_t *src, const utf8_int8_t *reject); + +/* Duplicate the utf8 string src by getting its size, malloc'ing a new buffer + * copying over the data, and returning that. Or 0 if malloc failed. */ +utf8_weak utf8_int8_t *utf8dup(const utf8_int8_t *src); + +/* Number of utf8 codepoints in the utf8 string str, + * excluding the null terminating byte. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8len(const utf8_int8_t *str); + +/* Similar to utf8len, except that only at most n bytes of src are looked. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8nlen(const utf8_int8_t *str, + size_t n); + +/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > + * src2 respectively, case insensitive. Checking at most n bytes of each utf8 + * string. */ +utf8_constexpr14 utf8_nonnull utf8_pure int +utf8ncasecmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n); + +/* Append the utf8 string src onto the utf8 string dst, + * writing at most n+1 bytes. Can produce an invalid utf8 + * string if n falls partway through a utf8 codepoint. */ +utf8_nonnull utf8_weak utf8_int8_t * +utf8ncat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src, + size_t n); + +/* Return less than 0, 0, greater than 0 if src1 < src2, + * src1 == src2, src1 > src2 respectively. Checking at most n + * bytes of each utf8 string. */ +utf8_constexpr14 utf8_nonnull utf8_pure int +utf8ncmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n); + +/* Copy the utf8 string src onto the memory allocated in dst. + * Copies at most n bytes. If n falls partway through a utf8 + * codepoint, or if dst doesn't have enough room for a null + * terminator, the final string will be cut short to preserve + * utf8 validity. */ + +utf8_nonnull utf8_weak utf8_int8_t * +utf8ncpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src, + size_t n); + +/* Similar to utf8dup, except that at most n bytes of src are copied. If src is + * longer than n, only n bytes are copied and a null byte is added. + * + * Returns a new string if successful, 0 otherwise */ +utf8_weak utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n); + +/* Locates the first occurrence in the utf8 string str of any byte in the + * utf8 string accept, or 0 if no match was found. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8pbrk(const utf8_int8_t *str, const utf8_int8_t *accept); + +/* Find the last match of the utf8 codepoint chr in the utf8 string src. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8rchr(const utf8_int8_t *src, int chr); + +/* Number of bytes in the utf8 string str, + * including the null terminating byte. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8size(const utf8_int8_t *str); + +/* Similar to utf8size, except that the null terminating byte is excluded. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8size_lazy(const utf8_int8_t *str); + +/* Similar to utf8size, except that only at most n bytes of src are looked and + * the null terminating byte is excluded. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8nsize_lazy(const utf8_int8_t *str, size_t n); + +/* Number of utf8 codepoints in the utf8 string src that consists entirely + * of utf8 codepoints from the utf8 string accept. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8spn(const utf8_int8_t *src, const utf8_int8_t *accept); + +/* The position of the utf8 string needle in the utf8 string haystack. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle); + +/* The position of the utf8 string needle in the utf8 string haystack, case + * insensitive. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle); + +/* Return 0 on success, or the position of the invalid + * utf8 codepoint on failure. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8valid(const utf8_int8_t *str); + +/* Similar to utf8valid, except that only at most n bytes of src are looked. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8nvalid(const utf8_int8_t *str, size_t n); + +/* Given a null-terminated string, makes the string valid by replacing invalid + * codepoints with a 1-byte replacement. Returns 0 on success. */ +utf8_nonnull utf8_weak int utf8makevalid(utf8_int8_t *str, + const utf8_int32_t replacement); + +/* Sets out_codepoint to the current utf8 codepoint in str, and returns the + * address of the next utf8 codepoint after the current one in str. */ +utf8_constexpr14 utf8_nonnull utf8_int8_t * +utf8codepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint); -// Make a codepoint upper case if possible. -utf8_weak utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); +/* Calculates the size of the next utf8 codepoint in str. */ +utf8_constexpr14 utf8_nonnull size_t +utf8codepointcalcsize(const utf8_int8_t *str); + +/* Returns the size of the given codepoint in bytes. */ +utf8_constexpr14 size_t utf8codepointsize(utf8_int32_t chr); + +/* Write a codepoint to the given string, and return the address to the next + * place after the written codepoint. Pass how many bytes left in the buffer to + * n. If there is not enough space for the codepoint, this function returns + * null. */ +utf8_nonnull utf8_weak utf8_int8_t * +utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n); + +/* Returns 1 if the given character is lowercase, or 0 if it is not. */ +utf8_constexpr14 int utf8islower(utf8_int32_t chr); + +/* Returns 1 if the given character is uppercase, or 0 if it is not. */ +utf8_constexpr14 int utf8isupper(utf8_int32_t chr); + +/* Transform the given string into all lowercase codepoints. */ +utf8_nonnull utf8_weak void utf8lwr(utf8_int8_t *utf8_restrict str); + +/* Transform the given string into all uppercase codepoints. */ +utf8_nonnull utf8_weak void utf8upr(utf8_int8_t *utf8_restrict str); + +/* Make a codepoint lower case if possible. */ +utf8_constexpr14 utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); + +/* Make a codepoint upper case if possible. */ +utf8_constexpr14 utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); + +/* Sets out_codepoint to the current utf8 codepoint in str, and returns the + * address of the previous utf8 codepoint before the current one in str. */ +utf8_constexpr14 utf8_nonnull utf8_int8_t * +utf8rcodepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint); + +/* Duplicate the utf8 string src by getting its size, calling alloc_func_ptr to + * copy over data to a new buffer, and returning that. Or 0 if alloc_func_ptr + * returned null. */ +utf8_weak utf8_int8_t *utf8dup_ex(const utf8_int8_t *src, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, + size_t), + utf8_int8_t *user_data); + +/* Similar to utf8dup, except that at most n bytes of src are copied. If src is + * longer than n, only n bytes are copied and a null byte is added. + * + * Returns a new string if successful, 0 otherwise. */ +utf8_weak utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, + size_t), + utf8_int8_t *user_data); #undef utf8_weak #undef utf8_pure #undef utf8_nonnull -int utf8casecmp(const void *src1, const void *src2) { - utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; +utf8_constexpr14_impl int utf8casecmp(const utf8_int8_t *src1, + const utf8_int8_t *src2) { + utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0, + src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0; for (;;) { - src1 = utf8codepoint(src1, &src1_cp); - src2 = utf8codepoint(src2, &src2_cp); + src1 = utf8codepoint(src1, &src1_orig_cp); + src2 = utf8codepoint(src2, &src2_orig_cp); - // Take a copy of src1 & src2 - src1_orig_cp = src1_cp; - src2_orig_cp = src2_cp; + /* lower the srcs if required */ + src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp); + src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp); - // Lower the srcs if required - src1_cp = utf8lwrcodepoint(src1_cp); - src2_cp = utf8lwrcodepoint(src2_cp); + /* lower the srcs if required */ + src1_upr_cp = utf8uprcodepoint(src1_orig_cp); + src2_upr_cp = utf8uprcodepoint(src2_orig_cp); - // Check if the lowered codepoints match + /* check if the lowered codepoints match */ if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { return 0; - } else if (src1_cp == src2_cp) { + } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) { continue; } - // If they don't match, then we return which of the original's are less - if (src1_orig_cp < src2_orig_cp) { - return -1; - } else if (src1_orig_cp > src2_orig_cp) { - return 1; - } + /* if they don't match, then we return the difference between the characters + */ + return src1_lwr_cp - src2_lwr_cp; } } -void *utf8cat(void *utf8_restrict dst, const void *utf8_restrict src) { - char *d = (char *)dst; - const char *s = (const char *)src; - - // find the null terminating byte in dst +utf8_int8_t *utf8cat(utf8_int8_t *utf8_restrict dst, + const utf8_int8_t *utf8_restrict src) { + utf8_int8_t *d = dst; + /* find the null terminating byte in dst */ while ('\0' != *d) { d++; } - // overwriting the null terminating byte in dst, append src byte-by-byte - while ('\0' != *s) { - *d++ = *s++; + /* overwriting the null terminating byte in dst, append src byte-by-byte */ + while ('\0' != *src) { + *d++ = *src++; } - // write out a new null terminating byte into dst + /* write out a new null terminating byte into dst */ *d = '\0'; return dst; } -void *utf8chr(const void *src, utf8_int32_t chr) { - char c[5] = {'\0', '\0', '\0', '\0', '\0'}; +utf8_constexpr14_impl utf8_int8_t *utf8chr(const utf8_int8_t *src, + utf8_int32_t chr) { + utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'}; if (0 == chr) { - // being asked to return position of null terminating byte, so - // just run s to the end, and return! - const char *s = (const char *)src; - while ('\0' != *s) { - s++; + /* being asked to return position of null terminating byte, so + * just run s to the end, and return! */ + while ('\0' != *src) { + src++; } - return (void *)s; + return (utf8_int8_t *)src; } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) { - // 1-byte/7-bit ascii - // (0b0xxxxxxx) - c[0] = (char)chr; + /* 1-byte/7-bit ascii + * (0b0xxxxxxx) */ + c[0] = (utf8_int8_t)chr; } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { - // 2-byte/11-bit utf8 code point - // (0b110xxxxx 0b10xxxxxx) - c[0] = 0xc0 | (char)(chr >> 6); - c[1] = 0x80 | (char)(chr & 0x3f); + /* 2-byte/11-bit utf8 code point + * (0b110xxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { - // 3-byte/16-bit utf8 code point - // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xe0 | (char)(chr >> 12); - c[1] = 0x80 | (char)((chr >> 6) & 0x3f); - c[2] = 0x80 | (char)(chr & 0x3f); - } else { // if (0 == ((int)0xffe00000 & chr)) { - // 4-byte/21-bit utf8 code point - // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xf0 | (char)(chr >> 18); - c[1] = 0x80 | (char)((chr >> 12) & 0x3f); - c[2] = 0x80 | (char)((chr >> 6) & 0x3f); - c[3] = 0x80 | (char)(chr & 0x3f); + /* 3-byte/16-bit utf8 code point + * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); + } else { /* if (0 == ((int)0xffe00000 & chr)) { */ + /* 4-byte/21-bit utf8 code point + * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } - // we've made c into a 2 utf8 codepoint string, one for the chr we are - // seeking, another for the null terminating byte. Now use utf8str to - // search + /* we've made c into a 2 utf8 codepoint string, one for the chr we are + * seeking, another for the null terminating byte. Now use utf8str to + * search */ return utf8str(src, c); } -int utf8cmp(const void *src1, const void *src2) { - const unsigned char *s1 = (const unsigned char *)src1; - const unsigned char *s2 = (const unsigned char *)src2; - - while (('\0' != *s1) || ('\0' != *s2)) { - if (*s1 < *s2) { +utf8_constexpr14_impl int utf8cmp(const utf8_int8_t *src1, + const utf8_int8_t *src2) { + while (('\0' != *src1) || ('\0' != *src2)) { + if (*src1 < *src2) { return -1; - } else if (*s1 > *s2) { + } else if (*src1 > *src2) { return 1; } - s1++; - s2++; + src1++; + src2++; } - // both utf8 strings matched + /* both utf8 strings matched */ return 0; } -int utf8coll(const void *src1, const void *src2); +utf8_constexpr14_impl int utf8coll(const utf8_int8_t *src1, + const utf8_int8_t *src2); -void *utf8cpy(void *utf8_restrict dst, const void *utf8_restrict src) { - char *d = (char *)dst; - const char *s = (const char *)src; +utf8_int8_t *utf8cpy(utf8_int8_t *utf8_restrict dst, + const utf8_int8_t *utf8_restrict src) { + utf8_int8_t *d = dst; - // overwriting anything previously in dst, write byte-by-byte - // from src - while ('\0' != *s) { - *d++ = *s++; + /* overwriting anything previously in dst, write byte-by-byte + * from src */ + while ('\0' != *src) { + *d++ = *src++; } - // append null terminating byte + /* append null terminating byte */ *d = '\0'; return dst; } -size_t utf8cspn(const void *src, const void *reject) { - const char *s = (const char *)src; +utf8_constexpr14_impl size_t utf8cspn(const utf8_int8_t *src, + const utf8_int8_t *reject) { size_t chars = 0; - while ('\0' != *s) { - const char *r = (const char *)reject; + while ('\0' != *src) { + const utf8_int8_t *r = reject; size_t offset = 0; while ('\0' != *r) { - // checking that if *r is the start of a utf8 codepoint - // (it is not 0b10xxxxxx) and we have successfully matched - // a previous character (0 < offset) - we found a match + /* checking that if *r is the start of a utf8 codepoint + * (it is not 0b10xxxxxx) and we have successfully matched + * a previous character (0 < offset) - we found a match */ if ((0x80 != (0xc0 & *r)) && (0 < offset)) { return chars; } else { - if (*r == s[offset]) { - // part of a utf8 codepoint matched, so move our checking - // onwards to the next byte + if (*r == src[offset]) { + /* part of a utf8 codepoint matched, so move our checking + * onwards to the next byte */ offset++; r++; } else { - // r could be in the middle of an unmatching utf8 code point, - // so we need to march it on to the next character beginning, + /* r could be in the middle of an unmatching utf8 code point, + * so we need to march it on to the next character beginning, */ do { r++; } while (0x80 == (0xc0 & *r)); - // reset offset too as we found a mismatch + /* reset offset too as we found a mismatch */ offset = 0; } } } - // the current utf8 codepoint in src did not match reject, but src - // could have been partway through a utf8 codepoint, so we need to - // march it onto the next utf8 codepoint starting byte + /* found a match at the end of *r, so didn't get a chance to test it */ + if (0 < offset) { + return chars; + } + + /* the current utf8 codepoint in src did not match reject, but src + * could have been partway through a utf8 codepoint, so we need to + * march it onto the next utf8 codepoint starting byte */ do { - s++; - } while ((0x80 == (0xc0 & *s))); + src++; + } while ((0x80 == (0xc0 & *src))); chars++; } return chars; } -size_t utf8size(const void *str); +utf8_int8_t *utf8dup(const utf8_int8_t *src) { + return utf8dup_ex(src, utf8_null, utf8_null); +} -void *utf8dup(const void *src) { - const char *s = (const char *)src; - char *n = utf8_null; +utf8_int8_t *utf8dup_ex(const utf8_int8_t *src, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t), + utf8_int8_t *user_data) { + utf8_int8_t *n = utf8_null; - // figure out how many bytes (including the terminator) we need to copy first + /* figure out how many bytes (including the terminator) we need to copy first + */ size_t bytes = utf8size(src); - n = (char *)malloc(bytes); + if (alloc_func_ptr) { + n = alloc_func_ptr(user_data, bytes); + } else { +#if !defined(UTF8_NO_STD_MALLOC) + n = (utf8_int8_t *)malloc(bytes); +#else + return utf8_null; +#endif + } if (utf8_null == n) { - // out of memory so we bail + /* out of memory so we bail */ return utf8_null; } else { bytes = 0; - // copy src byte-by-byte into our new utf8 string - while ('\0' != s[bytes]) { - n[bytes] = s[bytes]; + /* copy src byte-by-byte into our new utf8 string */ + while ('\0' != src[bytes]) { + n[bytes] = src[bytes]; bytes++; } - // append null terminating byte + /* append null terminating byte */ n[bytes] = '\0'; return n; } } -void *utf8fry(const void *str); +utf8_constexpr14_impl utf8_int8_t *utf8fry(const utf8_int8_t *str); -size_t utf8len(const void *str) { - const unsigned char *s = (const unsigned char *)str; +utf8_constexpr14_impl size_t utf8len(const utf8_int8_t *str) { + return utf8nlen(str, SIZE_MAX); +} + +utf8_constexpr14_impl size_t utf8nlen(const utf8_int8_t *str, size_t n) { + const utf8_int8_t *t = str; size_t length = 0; - while ('\0' != *s) { - if (0xf0 == (0xf8 & *s)) { - // 4-byte utf8 code point (began with 0b11110xxx) - s += 4; - } else if (0xe0 == (0xf0 & *s)) { - // 3-byte utf8 code point (began with 0b1110xxxx) - s += 3; - } else if (0xc0 == (0xe0 & *s)) { - // 2-byte utf8 code point (began with 0b110xxxxx) - s += 2; - } else { // if (0x00 == (0x80 & *s)) { - // 1-byte ascii (began with 0b0xxxxxxx) - s += 1; + while ((size_t)(str - t) < n && '\0' != *str) { + if (0xf0 == (0xf8 & *str)) { + /* 4-byte utf8 code point (began with 0b11110xxx) */ + str += 4; + } else if (0xe0 == (0xf0 & *str)) { + /* 3-byte utf8 code point (began with 0b1110xxxx) */ + str += 3; + } else if (0xc0 == (0xe0 & *str)) { + /* 2-byte utf8 code point (began with 0b110xxxxx) */ + str += 2; + } else { /* if (0x00 == (0x80 & *s)) { */ + /* 1-byte ascii (began with 0b0xxxxxxx) */ + str += 1; } - // no matter the bytes we marched s forward by, it was - // only 1 utf8 codepoint + /* no matter the bytes we marched s forward by, it was + * only 1 utf8 codepoint */ length++; } + if ((size_t)(str - t) > n) { + length--; + } return length; } -int utf8ncasecmp(const void *src1, const void *src2, size_t n) { - utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; +utf8_constexpr14_impl int utf8ncasecmp(const utf8_int8_t *src1, + const utf8_int8_t *src2, size_t n) { + utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0, + src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0; do { - const unsigned char *const s1 = (const unsigned char *)src1; - const unsigned char *const s2 = (const unsigned char *)src2; + const utf8_int8_t *const s1 = src1; + const utf8_int8_t *const s2 = src2; - // first check that we have enough bytes left in n to contain an entire - // codepoint + /* first check that we have enough bytes left in n to contain an entire + * codepoint */ if (0 == n) { return 0; } @@ -467,10 +579,8 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) { const utf8_int32_t c1 = (0xe0 & *s1); const utf8_int32_t c2 = (0xe0 & *s2); - if (c1 < c2) { - return -1; - } else if (c1 > c2) { - return 1; + if (c1 != c2) { + return c1 - c2; } else { return 0; } @@ -480,10 +590,8 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) { const utf8_int32_t c1 = (0xf0 & *s1); const utf8_int32_t c2 = (0xf0 & *s2); - if (c1 < c2) { - return -1; - } else if (c1 > c2) { - return 1; + if (c1 != c2) { + return c1 - c2; } else { return 0; } @@ -493,307 +601,343 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) { const utf8_int32_t c1 = (0xf8 & *s1); const utf8_int32_t c2 = (0xf8 & *s2); - if (c1 < c2) { - return -1; - } else if (c1 > c2) { - return 1; + if (c1 != c2) { + return c1 - c2; } else { return 0; } } - src1 = utf8codepoint(src1, &src1_cp); - src2 = utf8codepoint(src2, &src2_cp); - n -= utf8codepointsize(src1_cp); + src1 = utf8codepoint(src1, &src1_orig_cp); + src2 = utf8codepoint(src2, &src2_orig_cp); + n -= utf8codepointsize(src1_orig_cp); - // Take a copy of src1 & src2 - src1_orig_cp = src1_cp; - src2_orig_cp = src2_cp; + src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp); + src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp); - // Lower srcs if required - src1_cp = utf8lwrcodepoint(src1_cp); - src2_cp = utf8lwrcodepoint(src2_cp); + src1_upr_cp = utf8uprcodepoint(src1_orig_cp); + src2_upr_cp = utf8uprcodepoint(src2_orig_cp); - // Check if the lowered codepoints match + /* check if the lowered codepoints match */ if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { return 0; - } else if (src1_cp == src2_cp) { + } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) { continue; } - // If they don't match, then we return which of the original's are less - if (src1_orig_cp < src2_orig_cp) { - return -1; - } else if (src1_orig_cp > src2_orig_cp) { - return 1; - } + /* if they don't match, then we return the difference between the characters + */ + return src1_lwr_cp - src2_lwr_cp; } while (0 < n); - // both utf8 strings matched + /* both utf8 strings matched */ return 0; } -void *utf8ncat(void *utf8_restrict dst, const void *utf8_restrict src, - size_t n) { - char *d = (char *)dst; - const char *s = (const char *)src; +utf8_int8_t *utf8ncat(utf8_int8_t *utf8_restrict dst, + const utf8_int8_t *utf8_restrict src, size_t n) { + utf8_int8_t *d = dst; - // find the null terminating byte in dst + /* find the null terminating byte in dst */ while ('\0' != *d) { d++; } - // overwriting the null terminating byte in dst, append src byte-by-byte - // stopping if we run out of space - do { - *d++ = *s++; - } while (('\0' != *s) && (0 != --n)); + /* overwriting the null terminating byte in dst, append src byte-by-byte + * stopping if we run out of space */ + while (('\0' != *src) && (0 != n--)) { + *d++ = *src++; + } - // write out a new null terminating byte into dst + /* write out a new null terminating byte into dst */ *d = '\0'; return dst; } -int utf8ncmp(const void *src1, const void *src2, size_t n) { - const unsigned char *s1 = (const unsigned char *)src1; - const unsigned char *s2 = (const unsigned char *)src2; - - while ((('\0' != *s1) || ('\0' != *s2)) && (0 != n--)) { - if (*s1 < *s2) { +utf8_constexpr14_impl int utf8ncmp(const utf8_int8_t *src1, + const utf8_int8_t *src2, size_t n) { + while ((0 != n--) && (('\0' != *src1) || ('\0' != *src2))) { + if (*src1 < *src2) { return -1; - } else if (*s1 > *s2) { + } else if (*src1 > *src2) { return 1; } - s1++; - s2++; + src1++; + src2++; } - // both utf8 strings matched + /* both utf8 strings matched */ return 0; } -void *utf8ncpy(void *utf8_restrict dst, const void *utf8_restrict src, - size_t n) { - char *d = (char *)dst; - const char *s = (const char *)src; +utf8_int8_t *utf8ncpy(utf8_int8_t *utf8_restrict dst, + const utf8_int8_t *utf8_restrict src, size_t n) { + utf8_int8_t *d = dst; + size_t index = 0, check_index = 0; - // overwriting anything previously in dst, write byte-by-byte - // from src - do { - *d++ = *s++; - } while (('\0' != *s) && (0 != --n)); + if (n == 0) { + return dst; + } + + /* overwriting anything previously in dst, write byte-by-byte + * from src */ + for (index = 0; index < n; index++) { + d[index] = src[index]; + if ('\0' == src[index]) { + break; + } + } + + for (check_index = index - 1; + check_index > 0 && 0x80 == (0xc0 & d[check_index]); check_index--) { + /* just moving the index */ + } + + if (check_index < index && + ((index - check_index) < utf8codepointcalcsize(&d[check_index]) || + (index - check_index) == n)) { + index = check_index; + } - // append null terminating byte - while (0 != n) { - *d++ = '\0'; - n--; + /* append null terminating byte */ + for (; index < n; index++) { + d[index] = 0; } return dst; } -void *utf8ndup(const void *src, size_t n) { - const char *s = (const char *)src; - char *c = utf8_null; +utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n) { + return utf8ndup_ex(src, n, utf8_null, utf8_null); +} + +utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t), + utf8_int8_t *user_data) { + utf8_int8_t *c = utf8_null; size_t bytes = 0; - // Find the end of the string or stop when n is reached - while ('\0' != s[bytes] && bytes < n) { + /* Find the end of the string or stop when n is reached */ + while ('\0' != src[bytes] && bytes < n) { bytes++; } - // In case bytes is actually less than n, we need to set it - // to be used later in the copy byte by byte. + /* In case bytes is actually less than n, we need to set it + * to be used later in the copy byte by byte. */ n = bytes; - c = (char *)malloc(bytes + 1); + if (alloc_func_ptr) { + c = alloc_func_ptr(user_data, bytes + 1); + } else { +#if !defined(UTF8_NO_STD_MALLOC) + c = (utf8_int8_t *)malloc(bytes + 1); +#else + c = utf8_null; +#endif + } + if (utf8_null == c) { - // out of memory so we bail + /* out of memory so we bail */ return utf8_null; } bytes = 0; - // copy src byte-by-byte into our new utf8 string - while ('\0' != s[bytes] && bytes < n) { - c[bytes] = s[bytes]; + /* copy src byte-by-byte into our new utf8 string */ + while ('\0' != src[bytes] && bytes < n) { + c[bytes] = src[bytes]; bytes++; } - // append null terminating byte + /* append null terminating byte */ c[bytes] = '\0'; return c; } -void *utf8rchr(const void *src, int chr) { - const char *s = (const char *)src; - const char *match = utf8_null; - char c[5] = {'\0', '\0', '\0', '\0', '\0'}; +utf8_constexpr14_impl utf8_int8_t *utf8rchr(const utf8_int8_t *src, int chr) { + + utf8_int8_t *match = utf8_null; + utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'}; if (0 == chr) { - // being asked to return position of null terminating byte, so - // just run s to the end, and return! - while ('\0' != *s) { - s++; + /* being asked to return position of null terminating byte, so + * just run s to the end, and return! */ + while ('\0' != *src) { + src++; } - return (void *)s; + return (utf8_int8_t *)src; } else if (0 == ((int)0xffffff80 & chr)) { - // 1-byte/7-bit ascii - // (0b0xxxxxxx) - c[0] = (char)chr; + /* 1-byte/7-bit ascii + * (0b0xxxxxxx) */ + c[0] = (utf8_int8_t)chr; } else if (0 == ((int)0xfffff800 & chr)) { - // 2-byte/11-bit utf8 code point - // (0b110xxxxx 0b10xxxxxx) - c[0] = 0xc0 | (char)(chr >> 6); - c[1] = 0x80 | (char)(chr & 0x3f); + /* 2-byte/11-bit utf8 code point + * (0b110xxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } else if (0 == ((int)0xffff0000 & chr)) { - // 3-byte/16-bit utf8 code point - // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xe0 | (char)(chr >> 12); - c[1] = 0x80 | (char)((chr >> 6) & 0x3f); - c[2] = 0x80 | (char)(chr & 0x3f); - } else { // if (0 == ((int)0xffe00000 & chr)) { - // 4-byte/21-bit utf8 code point - // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xf0 | (char)(chr >> 18); - c[1] = 0x80 | (char)((chr >> 12) & 0x3f); - c[2] = 0x80 | (char)((chr >> 6) & 0x3f); - c[3] = 0x80 | (char)(chr & 0x3f); + /* 3-byte/16-bit utf8 code point + * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); + } else { /* if (0 == ((int)0xffe00000 & chr)) { */ + /* 4-byte/21-bit utf8 code point + * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } - // we've created a 2 utf8 codepoint string in c that is - // the utf8 character asked for by chr, and a null - // terminating byte + /* we've created a 2 utf8 codepoint string in c that is + * the utf8 character asked for by chr, and a null + * terminating byte */ - while ('\0' != *s) { + while ('\0' != *src) { size_t offset = 0; - while (s[offset] == c[offset]) { + while ((src[offset] == c[offset]) && ('\0' != src[offset])) { offset++; } if ('\0' == c[offset]) { - // we found a matching utf8 code point - match = s; - s += offset; + /* we found a matching utf8 code point */ + match = (utf8_int8_t *)src; + src += offset; + + if ('\0' == *src) { + break; + } } else { - s += offset; + src += offset; - // need to march s along to next utf8 codepoint start - // (the next byte that doesn't match 0b10xxxxxx) - if ('\0' != *s) { + /* need to march s along to next utf8 codepoint start + * (the next byte that doesn't match 0b10xxxxxx) */ + if ('\0' != *src) { do { - s++; - } while (0x80 == (0xc0 & *s)); + src++; + } while (0x80 == (0xc0 & *src)); } } } - // return the last match we found (or 0 if no match was found) - return (void *)match; + /* return the last match we found (or 0 if no match was found) */ + return match; } -void *utf8pbrk(const void *str, const void *accept) { - const char *s = (const char *)str; - - while ('\0' != *s) { - const char *a = (const char *)accept; +utf8_constexpr14_impl utf8_int8_t *utf8pbrk(const utf8_int8_t *str, + const utf8_int8_t *accept) { + while ('\0' != *str) { + const utf8_int8_t *a = accept; size_t offset = 0; while ('\0' != *a) { - // checking that if *a is the start of a utf8 codepoint - // (it is not 0b10xxxxxx) and we have successfully matched - // a previous character (0 < offset) - we found a match + /* checking that if *a is the start of a utf8 codepoint + * (it is not 0b10xxxxxx) and we have successfully matched + * a previous character (0 < offset) - we found a match */ if ((0x80 != (0xc0 & *a)) && (0 < offset)) { - return (void *)s; + return (utf8_int8_t *)str; } else { - if (*a == s[offset]) { - // part of a utf8 codepoint matched, so move our checking - // onwards to the next byte + if (*a == str[offset]) { + /* part of a utf8 codepoint matched, so move our checking + * onwards to the next byte */ offset++; a++; } else { - // r could be in the middle of an unmatching utf8 code point, - // so we need to march it on to the next character beginning, + /* r could be in the middle of an unmatching utf8 code point, + * so we need to march it on to the next character beginning, */ do { a++; } while (0x80 == (0xc0 & *a)); - // reset offset too as we found a mismatch + /* reset offset too as we found a mismatch */ offset = 0; } } } - // we found a match on the last utf8 codepoint + /* we found a match on the last utf8 codepoint */ if (0 < offset) { - return (void *)s; + return (utf8_int8_t *)str; } - // the current utf8 codepoint in src did not match accept, but src - // could have been partway through a utf8 codepoint, so we need to - // march it onto the next utf8 codepoint starting byte + /* the current utf8 codepoint in src did not match accept, but src + * could have been partway through a utf8 codepoint, so we need to + * march it onto the next utf8 codepoint starting byte */ do { - s++; - } while ((0x80 == (0xc0 & *s))); + str++; + } while ((0x80 == (0xc0 & *str))); } return utf8_null; } -size_t utf8size(const void *str) { - const char *s = (const char *)str; +utf8_constexpr14_impl size_t utf8size(const utf8_int8_t *str) { + return utf8size_lazy(str) + 1; +} + +utf8_constexpr14_impl size_t utf8size_lazy(const utf8_int8_t *str) { + return utf8nsize_lazy(str, SIZE_MAX); +} + +utf8_constexpr14_impl size_t utf8nsize_lazy(const utf8_int8_t *str, size_t n) { size_t size = 0; - while ('\0' != s[size]) { + while (size < n && '\0' != str[size]) { size++; } - - // we are including the null terminating byte in the size calculation - size++; return size; } -size_t utf8spn(const void *src, const void *accept) { - const char *s = (const char *)src; +utf8_constexpr14_impl size_t utf8spn(const utf8_int8_t *src, + const utf8_int8_t *accept) { size_t chars = 0; - while ('\0' != *s) { - const char *a = (const char *)accept; + while ('\0' != *src) { + const utf8_int8_t *a = accept; size_t offset = 0; while ('\0' != *a) { - // checking that if *r is the start of a utf8 codepoint - // (it is not 0b10xxxxxx) and we have successfully matched - // a previous character (0 < offset) - we found a match + /* checking that if *r is the start of a utf8 codepoint + * (it is not 0b10xxxxxx) and we have successfully matched + * a previous character (0 < offset) - we found a match */ if ((0x80 != (0xc0 & *a)) && (0 < offset)) { - // found a match, so increment the number of utf8 codepoints - // that have matched and stop checking whether any other utf8 - // codepoints in a match + /* found a match, so increment the number of utf8 codepoints + * that have matched and stop checking whether any other utf8 + * codepoints in a match */ chars++; - s += offset; + src += offset; + offset = 0; break; } else { - if (*a == s[offset]) { + if (*a == src[offset]) { offset++; a++; } else { - // a could be in the middle of an unmatching utf8 codepoint, - // so we need to march it on to the next character beginning, + /* a could be in the middle of an unmatching utf8 codepoint, + * so we need to march it on to the next character beginning, */ do { a++; } while (0x80 == (0xc0 & *a)); - // reset offset too as we found a mismatch + /* reset offset too as we found a mismatch */ offset = 0; } } } - // if a got to its terminating null byte, then we didn't find a match. - // Return the current number of matched utf8 codepoints + /* found a match at the end of *a, so didn't get a chance to test it */ + if (0 < offset) { + chars++; + src += offset; + continue; + } + + /* if a got to its terminating null byte, then we didn't find a match. + * Return the current number of matched utf8 codepoints */ if ('\0' == *a) { return chars; } @@ -802,302 +946,405 @@ size_t utf8spn(const void *src, const void *accept) { return chars; } -void *utf8str(const void *haystack, const void *needle) { - const char *h = (const char *)haystack; +utf8_constexpr14_impl utf8_int8_t *utf8str(const utf8_int8_t *haystack, + const utf8_int8_t *needle) { + utf8_int32_t throwaway_codepoint = 0; - // if needle has no utf8 codepoints before the null terminating - // byte then return haystack - if ('\0' == *((const char *)needle)) { - return (void *)haystack; + /* if needle has no utf8 codepoints before the null terminating + * byte then return haystack */ + if ('\0' == *needle) { + return (utf8_int8_t *)haystack; } - while ('\0' != *h) { - const char *maybeMatch = h; - const char *n = (const char *)needle; + while ('\0' != *haystack) { + const utf8_int8_t *maybeMatch = haystack; + const utf8_int8_t *n = needle; - while (*h == *n && (*h != '\0' && *n != '\0')) { + while (*haystack == *n && (*haystack != '\0' && *n != '\0')) { n++; - h++; + haystack++; } if ('\0' == *n) { - // we found the whole utf8 string for needle in haystack at - // maybeMatch, so return it - return (void *)maybeMatch; + /* we found the whole utf8 string for needle in haystack at + * maybeMatch, so return it */ + return (utf8_int8_t *)maybeMatch; } else { - // h could be in the middle of an unmatching utf8 codepoint, - // so we need to march it on to the next character beginning, - if ('\0' != *h) { - do { - h++; - } while (0x80 == (0xc0 & *h)); - } + /* h could be in the middle of an unmatching utf8 codepoint, + * so we need to march it on to the next character beginning + * starting from the current character */ + haystack = utf8codepoint(maybeMatch, &throwaway_codepoint); } } - // no match + /* no match */ return utf8_null; } -void *utf8casestr(const void *haystack, const void *needle) { - const void *h = haystack; - - // if needle has no utf8 codepoints before the null terminating - // byte then return haystack - if ('\0' == *((const char *)needle)) { - return (void *)haystack; +utf8_constexpr14_impl utf8_int8_t *utf8casestr(const utf8_int8_t *haystack, + const utf8_int8_t *needle) { + /* if needle has no utf8 codepoints before the null terminating + * byte then return haystack */ + if ('\0' == *needle) { + return (utf8_int8_t *)haystack; } for (;;) { - const void *maybeMatch = h; - const void *n = needle; - utf8_int32_t h_cp, n_cp; + const utf8_int8_t *maybeMatch = haystack; + const utf8_int8_t *n = needle; + utf8_int32_t h_cp = 0, n_cp = 0; - h = utf8codepoint(h, &h_cp); + /* Get the next code point and track it */ + const utf8_int8_t *nextH = haystack = utf8codepoint(haystack, &h_cp); n = utf8codepoint(n, &n_cp); while ((0 != h_cp) && (0 != n_cp)) { h_cp = utf8lwrcodepoint(h_cp); n_cp = utf8lwrcodepoint(n_cp); - // if we find a mismatch, bail out! + /* if we find a mismatch, bail out! */ if (h_cp != n_cp) { break; } - h = utf8codepoint(h, &h_cp); + haystack = utf8codepoint(haystack, &h_cp); n = utf8codepoint(n, &n_cp); } if (0 == n_cp) { - // we found the whole utf8 string for needle in haystack at - // maybeMatch, so return it - return (void *)maybeMatch; + /* we found the whole utf8 string for needle in haystack at + * maybeMatch, so return it */ + return (utf8_int8_t *)maybeMatch; } if (0 == h_cp) { - // no match + /* no match */ return utf8_null; } + + /* Roll back to the next code point in the haystack to test */ + haystack = nextH; } } -void *utf8valid(const void *str) { - const char *s = (const char *)str; +utf8_constexpr14_impl utf8_int8_t *utf8valid(const utf8_int8_t *str) { + return utf8nvalid(str, SIZE_MAX); +} + +utf8_constexpr14_impl utf8_int8_t *utf8nvalid(const utf8_int8_t *str, + size_t n) { + const utf8_int8_t *t = str; + size_t consumed = 0; - while ('\0' != *s) { - if (0xf0 == (0xf8 & *s)) { - // ensure each of the 3 following bytes in this 4-byte - // utf8 codepoint began with 0b10xxxxxx - if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2])) || - (0x80 != (0xc0 & s[3]))) { - return (void *)s; + while ((void)(consumed = (size_t)(str - t)), consumed < n && '\0' != *str) { + const size_t remaining = n - consumed; + + if (0xf0 == (0xf8 & *str)) { + /* ensure that there's 4 bytes or more remaining */ + if (remaining < 4) { + return (utf8_int8_t *)str; + } + + /* ensure each of the 3 following bytes in this 4-byte + * utf8 codepoint began with 0b10xxxxxx */ + if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2])) || + (0x80 != (0xc0 & str[3]))) { + return (utf8_int8_t *)str; + } + + /* ensure that our utf8 codepoint ended after 4 bytes */ + if ((remaining != 4) && (0x80 == (0xc0 & str[4]))) { + return (utf8_int8_t *)str; } - // ensure that our utf8 codepoint ended after 4 bytes - if (0x80 == (0xc0 & s[4])) { - return (void *)s; + /* ensure that the top 5 bits of this 4-byte utf8 + * codepoint were not 0, as then we could have used + * one of the smaller encodings */ + if ((0 == (0x07 & str[0])) && (0 == (0x30 & str[1]))) { + return (utf8_int8_t *)str; } - // ensure that the top 5 bits of this 4-byte utf8 - // codepoint were not 0, as then we could have used - // one of the smaller encodings - if ((0 == (0x07 & s[0])) && (0 == (0x30 & s[1]))) { - return (void *)s; + /* 4-byte utf8 code point (began with 0b11110xxx) */ + str += 4; + } else if (0xe0 == (0xf0 & *str)) { + /* ensure that there's 3 bytes or more remaining */ + if (remaining < 3) { + return (utf8_int8_t *)str; } - // 4-byte utf8 code point (began with 0b11110xxx) - s += 4; - } else if (0xe0 == (0xf0 & *s)) { - // ensure each of the 2 following bytes in this 3-byte - // utf8 codepoint began with 0b10xxxxxx - if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2]))) { - return (void *)s; + /* ensure each of the 2 following bytes in this 3-byte + * utf8 codepoint began with 0b10xxxxxx */ + if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2]))) { + return (utf8_int8_t *)str; } - // ensure that our utf8 codepoint ended after 3 bytes - if (0x80 == (0xc0 & s[3])) { - return (void *)s; + /* ensure that our utf8 codepoint ended after 3 bytes */ + if ((remaining != 3) && (0x80 == (0xc0 & str[3]))) { + return (utf8_int8_t *)str; } - // ensure that the top 5 bits of this 3-byte utf8 - // codepoint were not 0, as then we could have used - // one of the smaller encodings - if ((0 == (0x0f & s[0])) && (0 == (0x20 & s[1]))) { - return (void *)s; + /* ensure that the top 5 bits of this 3-byte utf8 + * codepoint were not 0, as then we could have used + * one of the smaller encodings */ + if ((0 == (0x0f & str[0])) && (0 == (0x20 & str[1]))) { + return (utf8_int8_t *)str; } - // 3-byte utf8 code point (began with 0b1110xxxx) - s += 3; - } else if (0xc0 == (0xe0 & *s)) { - // ensure the 1 following byte in this 2-byte - // utf8 codepoint began with 0b10xxxxxx - if (0x80 != (0xc0 & s[1])) { - return (void *)s; + /* 3-byte utf8 code point (began with 0b1110xxxx) */ + str += 3; + } else if (0xc0 == (0xe0 & *str)) { + /* ensure that there's 2 bytes or more remaining */ + if (remaining < 2) { + return (utf8_int8_t *)str; } - // ensure that our utf8 codepoint ended after 2 bytes - if (0x80 == (0xc0 & s[2])) { - return (void *)s; + /* ensure the 1 following byte in this 2-byte + * utf8 codepoint began with 0b10xxxxxx */ + if (0x80 != (0xc0 & str[1])) { + return (utf8_int8_t *)str; } - // ensure that the top 4 bits of this 2-byte utf8 - // codepoint were not 0, as then we could have used - // one of the smaller encodings - if (0 == (0x1e & s[0])) { - return (void *)s; + /* ensure that our utf8 codepoint ended after 2 bytes */ + if ((remaining != 2) && (0x80 == (0xc0 & str[2]))) { + return (utf8_int8_t *)str; } - // 2-byte utf8 code point (began with 0b110xxxxx) - s += 2; - } else if (0x00 == (0x80 & *s)) { - // 1-byte ascii (began with 0b0xxxxxxx) - s += 1; + /* ensure that the top 4 bits of this 2-byte utf8 + * codepoint were not 0, as then we could have used + * one of the smaller encodings */ + if (0 == (0x1e & str[0])) { + return (utf8_int8_t *)str; + } + + /* 2-byte utf8 code point (began with 0b110xxxxx) */ + str += 2; + } else if (0x00 == (0x80 & *str)) { + /* 1-byte ascii (began with 0b0xxxxxxx) */ + str += 1; } else { - // we have an invalid 0b1xxxxxxx utf8 code point entry - return (void *)s; + /* we have an invalid 0b1xxxxxxx utf8 code point entry */ + return (utf8_int8_t *)str; } } return utf8_null; } -void *utf8codepoint(const void *utf8_restrict str, - utf8_int32_t *utf8_restrict out_codepoint) { - const char *s = (const char *)str; +int utf8makevalid(utf8_int8_t *str, const utf8_int32_t replacement) { + utf8_int8_t *read = str; + utf8_int8_t *write = read; + const utf8_int8_t r = (utf8_int8_t)replacement; + utf8_int32_t codepoint = 0; - if (0xf0 == (0xf8 & s[0])) { - // 4 byte utf8 codepoint - *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | - ((0x3f & s[2]) << 6) | (0x3f & s[3]); - s += 4; - } else if (0xe0 == (0xf0 & s[0])) { - // 3 byte utf8 codepoint + if (replacement > 0x7f) { + return -1; + } + + while ('\0' != *read) { + if (0xf0 == (0xf8 & *read)) { + /* ensure each of the 3 following bytes in this 4-byte + * utf8 codepoint began with 0b10xxxxxx */ + if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2])) || + (0x80 != (0xc0 & read[3]))) { + *write++ = r; + read++; + continue; + } + + /* 4-byte utf8 code point (began with 0b11110xxx) */ + read = utf8codepoint(read, &codepoint); + write = utf8catcodepoint(write, codepoint, 4); + } else if (0xe0 == (0xf0 & *read)) { + /* ensure each of the 2 following bytes in this 3-byte + * utf8 codepoint began with 0b10xxxxxx */ + if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2]))) { + *write++ = r; + read++; + continue; + } + + /* 3-byte utf8 code point (began with 0b1110xxxx) */ + read = utf8codepoint(read, &codepoint); + write = utf8catcodepoint(write, codepoint, 3); + } else if (0xc0 == (0xe0 & *read)) { + /* ensure the 1 following byte in this 2-byte + * utf8 codepoint began with 0b10xxxxxx */ + if (0x80 != (0xc0 & read[1])) { + *write++ = r; + read++; + continue; + } + + /* 2-byte utf8 code point (began with 0b110xxxxx) */ + read = utf8codepoint(read, &codepoint); + write = utf8catcodepoint(write, codepoint, 2); + } else if (0x00 == (0x80 & *read)) { + /* 1-byte ascii (began with 0b0xxxxxxx) */ + read = utf8codepoint(read, &codepoint); + write = utf8catcodepoint(write, codepoint, 1); + } else { + /* if we got here then we've got a dangling continuation (0b10xxxxxx) */ + *write++ = r; + read++; + continue; + } + } + + *write = '\0'; + + return 0; +} + +utf8_constexpr14_impl utf8_int8_t * +utf8codepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint) { + if (0xf0 == (0xf8 & str[0])) { + /* 4 byte utf8 codepoint */ + *out_codepoint = ((0x07 & str[0]) << 18) | ((0x3f & str[1]) << 12) | + ((0x3f & str[2]) << 6) | (0x3f & str[3]); + str += 4; + } else if (0xe0 == (0xf0 & str[0])) { + /* 3 byte utf8 codepoint */ *out_codepoint = - ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); - s += 3; - } else if (0xc0 == (0xe0 & s[0])) { - // 2 byte utf8 codepoint - *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); - s += 2; + ((0x0f & str[0]) << 12) | ((0x3f & str[1]) << 6) | (0x3f & str[2]); + str += 3; + } else if (0xc0 == (0xe0 & str[0])) { + /* 2 byte utf8 codepoint */ + *out_codepoint = ((0x1f & str[0]) << 6) | (0x3f & str[1]); + str += 2; } else { - // 1 byte utf8 codepoint otherwise - *out_codepoint = s[0]; - s += 1; + /* 1 byte utf8 codepoint otherwise */ + *out_codepoint = str[0]; + str += 1; + } + + return (utf8_int8_t *)str; +} + +utf8_constexpr14_impl size_t utf8codepointcalcsize(const utf8_int8_t *str) { + if (0xf0 == (0xf8 & str[0])) { + /* 4 byte utf8 codepoint */ + return 4; + } else if (0xe0 == (0xf0 & str[0])) { + /* 3 byte utf8 codepoint */ + return 3; + } else if (0xc0 == (0xe0 & str[0])) { + /* 2 byte utf8 codepoint */ + return 2; } - return (void *)s; + /* 1 byte utf8 codepoint otherwise */ + return 1; } -size_t utf8codepointsize(utf8_int32_t chr) { +utf8_constexpr14_impl size_t utf8codepointsize(utf8_int32_t chr) { if (0 == ((utf8_int32_t)0xffffff80 & chr)) { return 1; } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { return 2; } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { return 3; - } else { // if (0 == ((int)0xffe00000 & chr)) { + } else { /* if (0 == ((int)0xffe00000 & chr)) { */ return 4; } } -void *utf8catcodepoint(void *utf8_restrict str, utf8_int32_t chr, size_t n) { - char *s = (char *)str; - +utf8_int8_t *utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n) { if (0 == ((utf8_int32_t)0xffffff80 & chr)) { - // 1-byte/7-bit ascii - // (0b0xxxxxxx) + /* 1-byte/7-bit ascii + * (0b0xxxxxxx) */ if (n < 1) { return utf8_null; } - s[0] = (char)chr; - s += 1; + str[0] = (utf8_int8_t)chr; + str += 1; } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { - // 2-byte/11-bit utf8 code point - // (0b110xxxxx 0b10xxxxxx) + /* 2-byte/11-bit utf8 code point + * (0b110xxxxx 0b10xxxxxx) */ if (n < 2) { return utf8_null; } - s[0] = 0xc0 | (char)(chr >> 6); - s[1] = 0x80 | (char)(chr & 0x3f); - s += 2; + str[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)((chr >> 6) & 0x1f)); + str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); + str += 2; } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { - // 3-byte/16-bit utf8 code point - // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) + /* 3-byte/16-bit utf8 code point + * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */ if (n < 3) { return utf8_null; } - s[0] = 0xe0 | (char)(chr >> 12); - s[1] = 0x80 | (char)((chr >> 6) & 0x3f); - s[2] = 0x80 | (char)(chr & 0x3f); - s += 3; - } else { // if (0 == ((int)0xffe00000 & chr)) { - // 4-byte/21-bit utf8 code point - // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) + str[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)((chr >> 12) & 0x0f)); + str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); + str += 3; + } else { /* if (0 == ((int)0xffe00000 & chr)) { */ + /* 4-byte/21-bit utf8 code point + * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */ if (n < 4) { return utf8_null; } - s[0] = 0xf0 | (char)(chr >> 18); - s[1] = 0x80 | (char)((chr >> 12) & 0x3f); - s[2] = 0x80 | (char)((chr >> 6) & 0x3f); - s[3] = 0x80 | (char)(chr & 0x3f); - s += 4; + str[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)((chr >> 18) & 0x07)); + str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f)); + str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + str[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); + str += 4; } - return s; + return str; } -int utf8islower(utf8_int32_t chr) { return chr != utf8uprcodepoint(chr); } - -int utf8isupper(utf8_int32_t chr) { return chr != utf8lwrcodepoint(chr); } +utf8_constexpr14_impl int utf8islower(utf8_int32_t chr) { + return chr != utf8uprcodepoint(chr); +} -void utf8lwr(void *utf8_restrict str) { - void *p, *pn; - utf8_int32_t cp; +utf8_constexpr14_impl int utf8isupper(utf8_int32_t chr) { + return chr != utf8lwrcodepoint(chr); +} - p = (char *)str; - pn = utf8codepoint(p, &cp); +void utf8lwr(utf8_int8_t *utf8_restrict str) { + utf8_int32_t cp = 0; + utf8_int8_t *pn = utf8codepoint(str, &cp); while (cp != 0) { const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp); const size_t size = utf8codepointsize(lwr_cp); if (lwr_cp != cp) { - utf8catcodepoint(p, lwr_cp, size); + utf8catcodepoint(str, lwr_cp, size); } - p = pn; - pn = utf8codepoint(p, &cp); + str = pn; + pn = utf8codepoint(str, &cp); } } -void utf8upr(void *utf8_restrict str) { - void *p, *pn; - utf8_int32_t cp; - - p = (char *)str; - pn = utf8codepoint(p, &cp); +void utf8upr(utf8_int8_t *utf8_restrict str) { + utf8_int32_t cp = 0; + utf8_int8_t *pn = utf8codepoint(str, &cp); while (cp != 0) { const utf8_int32_t lwr_cp = utf8uprcodepoint(cp); const size_t size = utf8codepointsize(lwr_cp); if (lwr_cp != cp) { - utf8catcodepoint(p, lwr_cp, size); + utf8catcodepoint(str, lwr_cp, size); } - p = pn; - pn = utf8codepoint(p, &cp); + str = pn; + pn = utf8codepoint(str, &cp); } } -utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { +utf8_constexpr14_impl utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { if (((0x0041 <= cp) && (0x005a >= cp)) || ((0x00c0 <= cp) && (0x00d6 >= cp)) || ((0x00d8 <= cp) && (0x00de >= cp)) || ((0x0391 <= cp) && (0x03a1 >= cp)) || - ((0x03a3 <= cp) && (0x03ab >= cp))) { + ((0x03a3 <= cp) && (0x03ab >= cp)) || + ((0x0410 <= cp) && (0x042f >= cp))) { cp += 32; + } else if ((0x0400 <= cp) && (0x040f >= cp)) { + cp += 80; } else if (((0x0100 <= cp) && (0x012f >= cp)) || ((0x0132 <= cp) && (0x0137 >= cp)) || ((0x014a <= cp) && (0x0177 >= cp)) || @@ -1107,7 +1354,9 @@ utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { ((0x01f8 <= cp) && (0x021f >= cp)) || ((0x0222 <= cp) && (0x0233 >= cp)) || ((0x0246 <= cp) && (0x024f >= cp)) || - ((0x03d8 <= cp) && (0x03ef >= cp))) { + ((0x03d8 <= cp) && (0x03ef >= cp)) || + ((0x0460 <= cp) && (0x0481 >= cp)) || + ((0x048a <= cp) && (0x04ff >= cp))) { cp |= 0x1; } else if (((0x0139 <= cp) && (0x0148 >= cp)) || ((0x0179 <= cp) && (0x017e >= cp)) || @@ -1118,62 +1367,147 @@ utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { cp &= ~0x1; } else { switch (cp) { - default: break; - case 0x0178: cp = 0x00ff; break; - case 0x0243: cp = 0x0180; break; - case 0x018e: cp = 0x01dd; break; - case 0x023d: cp = 0x019a; break; - case 0x0220: cp = 0x019e; break; - case 0x01b7: cp = 0x0292; break; - case 0x01c4: cp = 0x01c6; break; - case 0x01c7: cp = 0x01c9; break; - case 0x01ca: cp = 0x01cc; break; - case 0x01f1: cp = 0x01f3; break; - case 0x01f7: cp = 0x01bf; break; - case 0x0187: cp = 0x0188; break; - case 0x018b: cp = 0x018c; break; - case 0x0191: cp = 0x0192; break; - case 0x0198: cp = 0x0199; break; - case 0x01a7: cp = 0x01a8; break; - case 0x01ac: cp = 0x01ad; break; - case 0x01af: cp = 0x01b0; break; - case 0x01b8: cp = 0x01b9; break; - case 0x01bc: cp = 0x01bd; break; - case 0x01f4: cp = 0x01f5; break; - case 0x023b: cp = 0x023c; break; - case 0x0241: cp = 0x0242; break; - case 0x03fd: cp = 0x037b; break; - case 0x03fe: cp = 0x037c; break; - case 0x03ff: cp = 0x037d; break; - case 0x037f: cp = 0x03f3; break; - case 0x0386: cp = 0x03ac; break; - case 0x0388: cp = 0x03ad; break; - case 0x0389: cp = 0x03ae; break; - case 0x038a: cp = 0x03af; break; - case 0x038c: cp = 0x03cc; break; - case 0x038e: cp = 0x03cd; break; - case 0x038f: cp = 0x03ce; break; - case 0x0370: cp = 0x0371; break; - case 0x0372: cp = 0x0373; break; - case 0x0376: cp = 0x0377; break; - case 0x03f4: cp = 0x03d1; break; - case 0x03cf: cp = 0x03d7; break; - case 0x03f9: cp = 0x03f2; break; - case 0x03f7: cp = 0x03f8; break; - case 0x03fa: cp = 0x03fb; break; - }; + default: + break; + case 0x0178: + cp = 0x00ff; + break; + case 0x0243: + cp = 0x0180; + break; + case 0x018e: + cp = 0x01dd; + break; + case 0x023d: + cp = 0x019a; + break; + case 0x0220: + cp = 0x019e; + break; + case 0x01b7: + cp = 0x0292; + break; + case 0x01c4: + cp = 0x01c6; + break; + case 0x01c7: + cp = 0x01c9; + break; + case 0x01ca: + cp = 0x01cc; + break; + case 0x01f1: + cp = 0x01f3; + break; + case 0x01f7: + cp = 0x01bf; + break; + case 0x0187: + cp = 0x0188; + break; + case 0x018b: + cp = 0x018c; + break; + case 0x0191: + cp = 0x0192; + break; + case 0x0198: + cp = 0x0199; + break; + case 0x01a7: + cp = 0x01a8; + break; + case 0x01ac: + cp = 0x01ad; + break; + case 0x01b8: + cp = 0x01b9; + break; + case 0x01bc: + cp = 0x01bd; + break; + case 0x01f4: + cp = 0x01f5; + break; + case 0x023b: + cp = 0x023c; + break; + case 0x0241: + cp = 0x0242; + break; + case 0x03fd: + cp = 0x037b; + break; + case 0x03fe: + cp = 0x037c; + break; + case 0x03ff: + cp = 0x037d; + break; + case 0x037f: + cp = 0x03f3; + break; + case 0x0386: + cp = 0x03ac; + break; + case 0x0388: + cp = 0x03ad; + break; + case 0x0389: + cp = 0x03ae; + break; + case 0x038a: + cp = 0x03af; + break; + case 0x038c: + cp = 0x03cc; + break; + case 0x038e: + cp = 0x03cd; + break; + case 0x038f: + cp = 0x03ce; + break; + case 0x0370: + cp = 0x0371; + break; + case 0x0372: + cp = 0x0373; + break; + case 0x0376: + cp = 0x0377; + break; + case 0x03f4: + cp = 0x03b8; + break; + case 0x03cf: + cp = 0x03d7; + break; + case 0x03f9: + cp = 0x03f2; + break; + case 0x03f7: + cp = 0x03f8; + break; + case 0x03fa: + cp = 0x03fb; + break; + } } return cp; } -utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { +utf8_constexpr14_impl utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { if (((0x0061 <= cp) && (0x007a >= cp)) || ((0x00e0 <= cp) && (0x00f6 >= cp)) || ((0x00f8 <= cp) && (0x00fe >= cp)) || ((0x03b1 <= cp) && (0x03c1 >= cp)) || - ((0x03c3 <= cp) && (0x03cb >= cp))) { + ((0x03c3 <= cp) && (0x03cb >= cp)) || + ((0x0430 <= cp) && (0x044f >= cp))) { cp -= 32; + } else if ((0x0450 <= cp) && (0x045f >= cp)) { + cp -= 80; } else if (((0x0100 <= cp) && (0x012f >= cp)) || ((0x0132 <= cp) && (0x0137 >= cp)) || ((0x014a <= cp) && (0x0177 >= cp)) || @@ -1183,7 +1517,9 @@ utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { ((0x01f8 <= cp) && (0x021f >= cp)) || ((0x0222 <= cp) && (0x0233 >= cp)) || ((0x0246 <= cp) && (0x024f >= cp)) || - ((0x03d8 <= cp) && (0x03ef >= cp))) { + ((0x03d8 <= cp) && (0x03ef >= cp)) || + ((0x0460 <= cp) && (0x0481 >= cp)) || + ((0x048a <= cp) && (0x04ff >= cp))) { cp &= ~0x1; } else if (((0x0139 <= cp) && (0x0148 >= cp)) || ((0x0179 <= cp) && (0x017e >= cp)) || @@ -1194,64 +1530,175 @@ utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { cp |= 0x1; } else { switch (cp) { - default: break; - case 0x00ff: cp = 0x0178; break; - case 0x0180: cp = 0x0243; break; - case 0x01dd: cp = 0x018e; break; - case 0x019a: cp = 0x023d; break; - case 0x019e: cp = 0x0220; break; - case 0x0292: cp = 0x01b7; break; - case 0x01c6: cp = 0x01c4; break; - case 0x01c9: cp = 0x01c7; break; - case 0x01cc: cp = 0x01ca; break; - case 0x01f3: cp = 0x01f1; break; - case 0x01bf: cp = 0x01f7; break; - case 0x0188: cp = 0x0187; break; - case 0x018c: cp = 0x018b; break; - case 0x0192: cp = 0x0191; break; - case 0x0199: cp = 0x0198; break; - case 0x01a8: cp = 0x01a7; break; - case 0x01ad: cp = 0x01ac; break; - case 0x01b0: cp = 0x01af; break; - case 0x01b9: cp = 0x01b8; break; - case 0x01bd: cp = 0x01bc; break; - case 0x01f5: cp = 0x01f4; break; - case 0x023c: cp = 0x023b; break; - case 0x0242: cp = 0x0241; break; - case 0x037b: cp = 0x03fd; break; - case 0x037c: cp = 0x03fe; break; - case 0x037d: cp = 0x03ff; break; - case 0x03f3: cp = 0x037f; break; - case 0x03ac: cp = 0x0386; break; - case 0x03ad: cp = 0x0388; break; - case 0x03ae: cp = 0x0389; break; - case 0x03af: cp = 0x038a; break; - case 0x03cc: cp = 0x038c; break; - case 0x03cd: cp = 0x038e; break; - case 0x03ce: cp = 0x038f; break; - case 0x0371: cp = 0x0370; break; - case 0x0373: cp = 0x0372; break; - case 0x0377: cp = 0x0376; break; - case 0x03d1: cp = 0x03f4; break; - case 0x03d7: cp = 0x03cf; break; - case 0x03f2: cp = 0x03f9; break; - case 0x03f8: cp = 0x03f7; break; - case 0x03fb: cp = 0x03fa; break; - }; + default: + break; + case 0x00ff: + cp = 0x0178; + break; + case 0x0180: + cp = 0x0243; + break; + case 0x01dd: + cp = 0x018e; + break; + case 0x019a: + cp = 0x023d; + break; + case 0x019e: + cp = 0x0220; + break; + case 0x0292: + cp = 0x01b7; + break; + case 0x01c6: + cp = 0x01c4; + break; + case 0x01c9: + cp = 0x01c7; + break; + case 0x01cc: + cp = 0x01ca; + break; + case 0x01f3: + cp = 0x01f1; + break; + case 0x01bf: + cp = 0x01f7; + break; + case 0x0188: + cp = 0x0187; + break; + case 0x018c: + cp = 0x018b; + break; + case 0x0192: + cp = 0x0191; + break; + case 0x0199: + cp = 0x0198; + break; + case 0x01a8: + cp = 0x01a7; + break; + case 0x01ad: + cp = 0x01ac; + break; + case 0x01b9: + cp = 0x01b8; + break; + case 0x01bd: + cp = 0x01bc; + break; + case 0x01f5: + cp = 0x01f4; + break; + case 0x023c: + cp = 0x023b; + break; + case 0x0242: + cp = 0x0241; + break; + case 0x037b: + cp = 0x03fd; + break; + case 0x037c: + cp = 0x03fe; + break; + case 0x037d: + cp = 0x03ff; + break; + case 0x03f3: + cp = 0x037f; + break; + case 0x03ac: + cp = 0x0386; + break; + case 0x03ad: + cp = 0x0388; + break; + case 0x03ae: + cp = 0x0389; + break; + case 0x03af: + cp = 0x038a; + break; + case 0x03cc: + cp = 0x038c; + break; + case 0x03cd: + cp = 0x038e; + break; + case 0x03ce: + cp = 0x038f; + break; + case 0x0371: + cp = 0x0370; + break; + case 0x0373: + cp = 0x0372; + break; + case 0x0377: + cp = 0x0376; + break; + case 0x03d1: + cp = 0x0398; + break; + case 0x03d7: + cp = 0x03cf; + break; + case 0x03f2: + cp = 0x03f9; + break; + case 0x03f8: + cp = 0x03f7; + break; + case 0x03fb: + cp = 0x03fa; + break; + } } return cp; } +utf8_constexpr14_impl utf8_int8_t * +utf8rcodepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint) { + const utf8_int8_t *s = (const utf8_int8_t *)str; + + if (0xf0 == (0xf8 & s[0])) { + /* 4 byte utf8 codepoint */ + *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | + ((0x3f & s[2]) << 6) | (0x3f & s[3]); + } else if (0xe0 == (0xf0 & s[0])) { + /* 3 byte utf8 codepoint */ + *out_codepoint = + ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); + } else if (0xc0 == (0xe0 & s[0])) { + /* 2 byte utf8 codepoint */ + *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); + } else { + /* 1 byte utf8 codepoint otherwise */ + *out_codepoint = s[0]; + } + + do { + s--; + } while ((0 != (0x80 & s[0])) && (0x80 == (0xc0 & s[0]))); + + return (utf8_int8_t *)s; +} + #undef utf8_restrict +#undef utf8_constexpr14 #undef utf8_null #ifdef __cplusplus -} // extern "C" +} /* extern "C" */ #endif #if defined(__clang__) #pragma clang diagnostic pop #endif -#endif // SHEREDOM_UTF8_H_INCLUDED +#endif /* SHEREDOM_UTF8_H_INCLUDED */ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8e38c7d4e66..ad1a5deb659 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,6 +4,7 @@ file(GLOB SRC_EXAMPLES *.c *.h) add_executable(lg2 ${SRC_EXAMPLES}) set_target_properties(lg2 PROPERTIES C_STANDARD 90) +set_target_properties(lg2 PROPERTIES C_EXTENSIONS OFF) # Ensure that we do not use deprecated functions internally add_definitions(-DGIT_DEPRECATE_HARD) diff --git a/fuzzers/CMakeLists.txt b/fuzzers/CMakeLists.txt index 01f0f51997f..2961b92c5bb 100644 --- a/fuzzers/CMakeLists.txt +++ b/fuzzers/CMakeLists.txt @@ -21,7 +21,7 @@ foreach(fuzz_target_src ${SRC_FUZZERS}) add_executable(${fuzz_target_name} ${${fuzz_target_name}_SOURCES}) set_target_properties(${fuzz_target_name} PROPERTIES C_STANDARD 90) - + set_target_properties(${fuzz_target_name} PROPERTIES C_EXTENSIONS OFF) target_include_directories(${fuzz_target_name} PRIVATE ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) target_include_directories(${fuzz_target_name} SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) diff --git a/include/git2/stdint.h b/include/git2/stdint.h index 6950427d2d0..4b235c73f87 100644 --- a/include/git2/stdint.h +++ b/include/git2/stdint.h @@ -1,37 +1,37 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2008 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifdef _MSC_VER // [ - -#ifndef _MSC_STDINT_H_ // [ +/* ISO C9x compliant stdint.h for Microsoft Visual Studio + * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 + * + * Copyright (c) 2006-2008 Alexander Chemeris + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#ifdef _MSC_VER /* [ */ + +#ifndef _MSC_STDINT_H_ /* [ */ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 @@ -40,10 +40,11 @@ #include -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap include with 'extern "C++" {}' -// or compiler give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when + * compiling for ARM we should wrap include with 'extern "C++" {}' + * or compiler give many errors like this: + * error C2733: second C linkage of overloaded function 'wmemchr' not allowed +*/ #ifdef __cplusplus extern "C" { #endif @@ -52,7 +53,7 @@ extern "C" { } #endif -// Define _W64 macros to mark types changing their size, like intptr_t. +/* Define _W64 macros to mark types changing their size, like intptr_t. */ #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 @@ -62,13 +63,14 @@ extern "C" { #endif -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. +/* 7.18.1 Integer types + * + * 7.18.1.1 Exact-width integer types + * + * Visual Studio 6 and Embedded Visual C++ 4 doesn't + * realize that, e.g. char has the same size as __int8 + * so we give up on __intX for them. + */ #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; @@ -88,7 +90,7 @@ typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; -// 7.18.1.2 Minimum-width integer types +/* 7.18.1.2 Minimum-width integer types */ typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; @@ -98,7 +100,7 @@ typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; -// 7.18.1.3 Fastest minimum-width integer types +/* 7.18.1.3 Fastest minimum-width integer types */ typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; @@ -108,25 +110,25 @@ typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ +/* 7.18.1.4 Integer types capable of holding object pointers */ +#ifdef _WIN64 /* [ */ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ +#else /* _WIN64 ][ */ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] +#endif /* _WIN64 ] */ -// 7.18.1.5 Greatest-width integer types +/* 7.18.1.5 Greatest-width integer types */ typedef int64_t intmax_t; typedef uint64_t uintmax_t; -// 7.18.2 Limits of specified-width integer types +/* 7.18.2 Limits of specified-width integer types */ -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) /* [ See footnote 220 at page 257 and footnote 221 at page 259 */ -// 7.18.2.1 Limits of exact-width integer types +/* 7.18.2.1 Limits of exact-width integer types */ #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) @@ -140,7 +142,7 @@ typedef uint64_t uintmax_t; #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX -// 7.18.2.2 Limits of minimum-width integer types +/* 7.18.2.2 Limits of minimum-width integer types */ #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN @@ -154,7 +156,7 @@ typedef uint64_t uintmax_t; #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX -// 7.18.2.3 Limits of fastest minimum-width integer types +/* 7.18.2.3 Limits of fastest minimum-width integer types */ #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN @@ -168,62 +170,62 @@ typedef uint64_t uintmax_t; #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ +/* 7.18.2.4 Limits of integer types capable of holding object pointers */ +#ifdef _WIN64 /* [ */ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ +#else /* _WIN64 ][ */ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] +#endif /* _WIN64 ] */ -// 7.18.2.5 Limits of greatest-width integer types +/* 7.18.2.5 Limits of greatest-width integer types */ #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX -// 7.18.3 Limits of other integer types +/* 7.18.3 Limits of other integer types */ -#ifdef _WIN64 // [ +#ifdef _WIN64 /* [ */ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ +#else /* _WIN64 ][ */ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] +#endif /* _WIN64 ] */ #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ +#ifndef SIZE_MAX /* [ */ +# ifdef _WIN64 /* [ */ # define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ +# else /* _WIN64 ][ */ # define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] +# endif /* _WIN64 ] */ +#endif /* SIZE_MAX ] */ -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ +/* WCHAR_MIN and WCHAR_MAX are also defined in */ +#ifndef WCHAR_MIN /* [ */ # define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ +#endif /* WCHAR_MIN ] */ +#ifndef WCHAR_MAX /* [ */ # define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] +#endif /* WCHAR_MAX ] */ #define WINT_MIN 0 #define WINT_MAX _UI16_MAX -#endif // __STDC_LIMIT_MACROS ] +#endif /* __STDC_LIMIT_MACROS ] */ -// 7.18.4 Limits of other integer types +/* 7.18.4 Limits of other integer types -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) /* [ See footnote 224 at page 260 */ -// 7.18.4.1 Macros for minimum-width integer constants +/* 7.18.4.1 Macros for minimum-width integer constants */ #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 @@ -235,13 +237,13 @@ typedef uint64_t uintmax_t; #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 -// 7.18.4.2 Macros for greatest-width integer constants +/* 7.18.4.2 Macros for greatest-width integer constants */ #define INTMAX_C INT64_C #define UINTMAX_C UINT64_C -#endif // __STDC_CONSTANT_MACROS ] +#endif /* __STDC_CONSTANT_MACROS ] */ -#endif // _MSC_STDINT_H_ ] +#endif /* _MSC_STDINT_H_ ] */ -#endif // _MSC_VER ] \ No newline at end of file +#endif /* _MSC_VER ] */ diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 97797e33bd9..8069d156014 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(git2_cli ${CLI_SRC_C} ${CLI_SRC_OS} ${CLI_OBJECTS} target_link_libraries(git2_cli ${CLI_LIBGIT2_LIBRARY} ${LIBGIT2_SYSTEM_LIBS}) set_target_properties(git2_cli PROPERTIES C_STANDARD 90) +set_target_properties(git2_cli PROPERTIES C_EXTENSIONS OFF) set_target_properties(git2_cli PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR}) set_target_properties(git2_cli PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index bc7cb5b3597..7c7cc4ea102 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -61,6 +61,7 @@ target_link_libraries(libgit2package ${LIBGIT2_SYSTEM_LIBS}) target_include_directories(libgit2package SYSTEM PRIVATE ${LIBGIT2_INCLUDES}) set_target_properties(libgit2package PROPERTIES C_STANDARD 90) +set_target_properties(libgit2package PROPERTIES C_EXTENSIONS OFF) set_target_properties(libgit2package PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set_target_properties(libgit2package PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set_target_properties(libgit2package PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) diff --git a/tests/libgit2/CMakeLists.txt b/tests/libgit2/CMakeLists.txt index af70f55a78b..0202b8c79b4 100644 --- a/tests/libgit2/CMakeLists.txt +++ b/tests/libgit2/CMakeLists.txt @@ -41,8 +41,8 @@ set_source_files_properties( add_executable(libgit2_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) set_target_properties(libgit2_tests PROPERTIES C_STANDARD 90) +set_target_properties(libgit2_tests PROPERTIES C_EXTENSIONS OFF) set_target_properties(libgit2_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) - target_include_directories(libgit2_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) target_include_directories(libgit2_tests SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) target_link_libraries(libgit2_tests ${LIBGIT2_SYSTEM_LIBS}) diff --git a/tests/libgit2/grafts/shallow.c b/tests/libgit2/grafts/shallow.c index 289d1b19105..349e9e9b2fd 100644 --- a/tests/libgit2/grafts/shallow.c +++ b/tests/libgit2/grafts/shallow.c @@ -110,8 +110,8 @@ void test_grafts_shallow__revwalk_behavior(void) cl_git_pass(git_revwalk_new(&w, g_repo)); cl_git_pass(git_revwalk_push_head(w)); - cl_git_pass(git_revwalk_next(&oid_1, w)); // a65fedf39aefe402d3bb6e24df4d4f5fe4547750 - cl_git_pass(git_revwalk_next(&oid_2, w)); // be3563ae3f795b2b4353bcce3a527ad0a4f7f644 + cl_git_pass(git_revwalk_next(&oid_1, w)); /* a65fedf39aefe402d3bb6e24df4d4f5fe4547750 */ + cl_git_pass(git_revwalk_next(&oid_2, w)); /* be3563ae3f795b2b4353bcce3a527ad0a4f7f644 */ cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid_3, w)); cl_assert_equal_s(git_oid_tostr_s(&oid_1), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); diff --git a/tests/libgit2/index/tests256.c b/tests/libgit2/index/tests256.c index fed8bfb9358..97246ce4d5a 100644 --- a/tests/libgit2/index/tests256.c +++ b/tests/libgit2/index/tests256.c @@ -678,7 +678,7 @@ void test_index_tests256__write_tree_invalid_unowned_index(void) cl_git_pass(git_index__new(&idx, GIT_OID_SHA256)); - // TODO: this one is failing + /* TODO: this one is failing */ cl_git_pass(git_oid__fromstr(&entry.id, "a8c2e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); entry.path = "foo"; entry.mode = GIT_FILEMODE_BLOB; diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index 232590ffdfc..ad57493b514 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -40,6 +40,7 @@ set_source_files_properties( add_executable(util_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) set_target_properties(util_tests PROPERTIES C_STANDARD 90) +set_target_properties(util_tests PROPERTIES C_EXTENSIONS OFF) set_target_properties(util_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR}) target_include_directories(util_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) From 41a41b4f4a0ab37ec32a4a07147127038ba7e38a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Oct 2024 16:18:17 +0100 Subject: [PATCH 650/816] cmake: make C_STANDARD and C_EXTENSIONS configurable Users can now set up cmake with -DC_STANDARD=... or -DC_EXTENSIONS=... We default to C90 with C_EXTENSIONS=OFF, but callers can override if they desire. --- CMakeLists.txt | 3 ++- cmake/SetCStandard.cmake | 24 ++++++++++++++++++++++++ examples/CMakeLists.txt | 3 +-- fuzzers/CMakeLists.txt | 3 +-- src/cli/CMakeLists.txt | 3 +-- src/libgit2/CMakeLists.txt | 3 +-- src/util/CMakeLists.txt | 3 +-- tests/headertest/CMakeLists.txt | 4 ++-- tests/libgit2/CMakeLists.txt | 3 +-- tests/util/CMakeLists.txt | 3 +-- 10 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 cmake/SetCStandard.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 578ec177729..daa893e6471 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,8 @@ endif() # Modules +include(FeatureSummary) +include(SetCStandard) include(CheckLibraryExists) include(CheckFunctionExists) include(CheckSymbolExists) @@ -102,7 +104,6 @@ include(FindStatNsec) include(Findfutimens) include(GNUInstallDirs) include(IdeSplitSources) -include(FeatureSummary) include(EnableWarnings) include(DefaultCFlags) include(ExperimentalFeatures) diff --git a/cmake/SetCStandard.cmake b/cmake/SetCStandard.cmake new file mode 100644 index 00000000000..f4fde658a92 --- /dev/null +++ b/cmake/SetCStandard.cmake @@ -0,0 +1,24 @@ +if("${C_STANDARD}" STREQUAL "") + set(C_STANDARD "90") +endif() +if("${C_EXTENSIONS}" STREQUAL "") + set(C_EXTENSIONS OFF) +endif() + +if(${C_STANDARD} MATCHES "^[Cc].*") + string(REGEX REPLACE "^[Cc]" "" C_STANDARD ${C_STANDARD}) +endif() + +if(${C_STANDARD} MATCHES ".*-strict$") + string(REGEX REPLACE "-strict$" "" C_STANDARD ${C_STANDARD}) + set(C_EXTENSIONS OFF) + + add_feature_info("C Standard" ON "C${C_STANDARD} (strict)") +else() + add_feature_info("C Standard" ON "C${C_STANDARD}") +endif() + +function(set_c_standard project) + set_target_properties(${project} PROPERTIES C_STANDARD ${C_STANDARD}) + set_target_properties(${project} PROPERTIES C_EXTENSIONS ${C_EXTENSIONS}) +endfunction() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ad1a5deb659..e8472424712 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,8 +3,7 @@ file(GLOB SRC_EXAMPLES *.c *.h) add_executable(lg2 ${SRC_EXAMPLES}) -set_target_properties(lg2 PROPERTIES C_STANDARD 90) -set_target_properties(lg2 PROPERTIES C_EXTENSIONS OFF) +set_c_standard(lg2) # Ensure that we do not use deprecated functions internally add_definitions(-DGIT_DEPRECATE_HARD) diff --git a/fuzzers/CMakeLists.txt b/fuzzers/CMakeLists.txt index 2961b92c5bb..32b91e4468a 100644 --- a/fuzzers/CMakeLists.txt +++ b/fuzzers/CMakeLists.txt @@ -20,8 +20,7 @@ foreach(fuzz_target_src ${SRC_FUZZERS}) endif() add_executable(${fuzz_target_name} ${${fuzz_target_name}_SOURCES}) - set_target_properties(${fuzz_target_name} PROPERTIES C_STANDARD 90) - set_target_properties(${fuzz_target_name} PROPERTIES C_EXTENSIONS OFF) + set_c_standard(${fuzz_target_name}) target_include_directories(${fuzz_target_name} PRIVATE ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) target_include_directories(${fuzz_target_name} SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 8069d156014..85544514202 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -40,8 +40,7 @@ add_executable(git2_cli ${CLI_SRC_C} ${CLI_SRC_OS} ${CLI_OBJECTS} ${LIBGIT2_DEPENDENCY_OBJECTS}) target_link_libraries(git2_cli ${CLI_LIBGIT2_LIBRARY} ${LIBGIT2_SYSTEM_LIBS}) -set_target_properties(git2_cli PROPERTIES C_STANDARD 90) -set_target_properties(git2_cli PROPERTIES C_EXTENSIONS OFF) +set_c_standard(git2_cli) set_target_properties(git2_cli PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR}) set_target_properties(git2_cli PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index 7c7cc4ea102..66b8394a3fb 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -2,8 +2,7 @@ # git library functionality. add_library(libgit2 OBJECT) -set_target_properties(libgit2 PROPERTIES C_STANDARD 90) -set_target_properties(libgit2 PROPERTIES C_EXTENSIONS OFF) +set_c_standard(libgit2) include(PkgBuildConfig) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index ee35eb9610e..c0ee7447275 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -1,8 +1,7 @@ # util: a shared library for common utility functions for libgit2 projects add_library(util OBJECT) -set_target_properties(util PROPERTIES C_STANDARD 90) -set_target_properties(util PROPERTIES C_EXTENSIONS OFF) +set_c_standard(util) configure_file(git2_features.h.in git2_features.h) diff --git a/tests/headertest/CMakeLists.txt b/tests/headertest/CMakeLists.txt index c70ce1ae19c..db294b7daca 100644 --- a/tests/headertest/CMakeLists.txt +++ b/tests/headertest/CMakeLists.txt @@ -3,8 +3,8 @@ # even when they have aggressive C90 warnings enabled. add_executable(headertest headertest.c) -set_target_properties(headertest PROPERTIES C_STANDARD 90) -set_target_properties(headertest PROPERTIES C_EXTENSIONS OFF) +set_c_standard(headertest) + target_include_directories(headertest PRIVATE ${LIBGIT2_INCLUDES}) if (MSVC) diff --git a/tests/libgit2/CMakeLists.txt b/tests/libgit2/CMakeLists.txt index 0202b8c79b4..1eb109fb597 100644 --- a/tests/libgit2/CMakeLists.txt +++ b/tests/libgit2/CMakeLists.txt @@ -39,9 +39,8 @@ set_source_files_properties( PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) add_executable(libgit2_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) +set_c_standard(libgit2_tests) -set_target_properties(libgit2_tests PROPERTIES C_STANDARD 90) -set_target_properties(libgit2_tests PROPERTIES C_EXTENSIONS OFF) set_target_properties(libgit2_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) target_include_directories(libgit2_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) target_include_directories(libgit2_tests SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index ad57493b514..1b5799495a0 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -38,9 +38,8 @@ set_source_files_properties( PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) add_executable(util_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) +set_c_standard(util_tests) -set_target_properties(util_tests PROPERTIES C_STANDARD 90) -set_target_properties(util_tests PROPERTIES C_EXTENSIONS OFF) set_target_properties(util_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR}) target_include_directories(util_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) From 4768d8a8ad31f42886f61aa572dd490c7c36e723 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Oct 2024 21:40:00 +0100 Subject: [PATCH 651/816] ci: don't use extensions on msan build The memory sanitizer builds are special snowflakes; let them be c90 with extensions. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ad1eded47e3..46dfe602fb9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -132,7 +132,7 @@ jobs: env: CC: clang CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DC_EXTENSIONS=ON -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true From d6a11073d42fe4038d688da3af7d75d1443dd097 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Oct 2024 22:44:07 +0100 Subject: [PATCH 652/816] cmake: document C standard options --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9776620154a..bfca5c88854 100644 --- a/README.md +++ b/README.md @@ -373,11 +373,13 @@ following: Compiler and linker options --------------------------- -CMake lets you specify a few variables to control the behavior of the -compiler and linker. These flags are rarely used but can be useful for -64-bit to 32-bit cross-compilation. +There are several options that control the behavior of the compiler and +linker. These flags may be useful for cross-compilation or specialized +setups. - `CMAKE_C_FLAGS`: Set your own compiler flags +- `C_STANDARD`: the C standard to compile against; defaults to `C90` +- `C_EXTENSIONS`: whether compiler extensions are supported; defaults to `OFF` - `CMAKE_FIND_ROOT_PATH`: Override the search path for libraries - `ZLIB_LIBRARY`, `OPENSSL_SSL_LIBRARY` AND `OPENSSL_CRYPTO_LIBRARY`: Tell CMake where to find those specific libraries From 6c70f24d89b445b3592bec35f8458c4e038ec9e7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 18 Oct 2024 21:57:23 +0100 Subject: [PATCH 653/816] Update ntlmclient dependency --- deps/ntlmclient/CMakeLists.txt | 1 + deps/ntlmclient/crypt_openssl.c | 8 +++---- deps/ntlmclient/ntlm.c | 38 +++++++++++++++---------------- deps/ntlmclient/unicode_builtin.c | 5 ++-- deps/ntlmclient/unicode_iconv.c | 3 ++- deps/ntlmclient/utf8.h | 18 +++++++++++---- deps/ntlmclient/util.h | 11 +++++++++ 7 files changed, 53 insertions(+), 31 deletions(-) diff --git a/deps/ntlmclient/CMakeLists.txt b/deps/ntlmclient/CMakeLists.txt index f1f5de162a0..420d1006cea 100644 --- a/deps/ntlmclient/CMakeLists.txt +++ b/deps/ntlmclient/CMakeLists.txt @@ -37,3 +37,4 @@ else() endif() add_library(ntlmclient OBJECT ${SRC_NTLMCLIENT} ${SRC_NTLMCLIENT_UNICODE} ${SRC_NTLMCLIENT_CRYPTO}) +set_target_properties(ntlmclient PROPERTIES C_STANDARD 90) diff --git a/deps/ntlmclient/crypt_openssl.c b/deps/ntlmclient/crypt_openssl.c index c4be129d39e..3bec2725999 100644 --- a/deps/ntlmclient/crypt_openssl.c +++ b/deps/ntlmclient/crypt_openssl.c @@ -26,18 +26,18 @@ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(CRYPT_OPENSSL_DYNAMIC) -static inline HMAC_CTX *HMAC_CTX_new(void) +NTLM_INLINE(HMAC_CTX *) HMAC_CTX_new(void) { return calloc(1, sizeof(HMAC_CTX)); } -static inline int HMAC_CTX_reset(HMAC_CTX *ctx) +NTLM_INLINE(int) HMAC_CTX_reset(HMAC_CTX *ctx) { ntlm_memzero(ctx, sizeof(HMAC_CTX)); return 1; } -static inline void HMAC_CTX_free(HMAC_CTX *ctx) +NTLM_INLINE(void) HMAC_CTX_free(HMAC_CTX *ctx) { free(ctx); } @@ -48,7 +48,7 @@ static inline void HMAC_CTX_free(HMAC_CTX *ctx) (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x03050000fL) || \ defined(CRYPT_OPENSSL_DYNAMIC) -static inline void HMAC_CTX_cleanup(HMAC_CTX *ctx) +NTLM_INLINE(void) HMAC_CTX_cleanup(HMAC_CTX *ctx) { NTLM_UNUSED(ctx); } diff --git a/deps/ntlmclient/ntlm.c b/deps/ntlmclient/ntlm.c index 6094a4a3484..28dff670e16 100644 --- a/deps/ntlmclient/ntlm.c +++ b/deps/ntlmclient/ntlm.c @@ -43,7 +43,7 @@ static bool supports_unicode(ntlm_client *ntlm) false : true; } -static inline bool increment_size(size_t *out, size_t incr) +NTLM_INLINE(bool) increment_size(size_t *out, size_t incr) { if (SIZE_MAX - *out < incr) { *out = (size_t)-1; @@ -272,7 +272,7 @@ int ntlm_client_set_timestamp(ntlm_client *ntlm, uint64_t timestamp) return 0; } -static inline bool write_buf( +NTLM_INLINE(bool) write_buf( ntlm_client *ntlm, ntlm_buf *out, const unsigned char *buf, @@ -291,7 +291,7 @@ static inline bool write_buf( return true; } -static inline bool write_byte( +NTLM_INLINE(bool) write_byte( ntlm_client *ntlm, ntlm_buf *out, uint8_t value) @@ -305,7 +305,7 @@ static inline bool write_byte( return true; } -static inline bool write_int16( +NTLM_INLINE(bool) write_int16( ntlm_client *ntlm, ntlm_buf *out, uint16_t value) @@ -320,7 +320,7 @@ static inline bool write_int16( return true; } -static inline bool write_int32( +NTLM_INLINE(bool) write_int32( ntlm_client *ntlm, ntlm_buf *out, uint32_t value) @@ -337,7 +337,7 @@ static inline bool write_int32( return true; } -static inline bool write_version( +NTLM_INLINE(bool) write_version( ntlm_client *ntlm, ntlm_buf *out, ntlm_version *version) @@ -348,7 +348,7 @@ static inline bool write_version( write_int32(ntlm, out, version->reserved); } -static inline bool write_bufinfo( +NTLM_INLINE(bool) write_bufinfo( ntlm_client *ntlm, ntlm_buf *out, size_t len, @@ -369,7 +369,7 @@ static inline bool write_bufinfo( write_int32(ntlm, out, (uint32_t)offset); } -static inline bool read_buf( +NTLM_INLINE(bool) read_buf( unsigned char *out, ntlm_client *ntlm, ntlm_buf *message, @@ -386,7 +386,7 @@ static inline bool read_buf( return true; } -static inline bool read_byte( +NTLM_INLINE(bool) read_byte( uint8_t *out, ntlm_client *ntlm, ntlm_buf *message) @@ -400,7 +400,7 @@ static inline bool read_byte( return true; } -static inline bool read_int16( +NTLM_INLINE(bool) read_int16( uint16_t *out, ntlm_client *ntlm, ntlm_buf *message) @@ -418,7 +418,7 @@ static inline bool read_int16( return true; } -static inline bool read_int32( +NTLM_INLINE(bool) read_int32( uint32_t *out, ntlm_client *ntlm, ntlm_buf *message) @@ -438,7 +438,7 @@ static inline bool read_int32( return true; } -static inline bool read_int64( +NTLM_INLINE(bool) read_int64( uint64_t *out, ntlm_client *ntlm, ntlm_buf *message) @@ -462,7 +462,7 @@ static inline bool read_int64( return true; } -static inline bool read_version( +NTLM_INLINE(bool) read_version( ntlm_version *out, ntlm_client *ntlm, ntlm_buf *message) @@ -473,7 +473,7 @@ static inline bool read_version( read_int32(&out->reserved, ntlm, message); } -static inline bool read_bufinfo( +NTLM_INLINE(bool) read_bufinfo( uint16_t *out_len, uint32_t *out_offset, ntlm_client *ntlm, @@ -486,7 +486,7 @@ static inline bool read_bufinfo( read_int32(out_offset, ntlm, message); } -static inline bool read_string_unicode( +NTLM_INLINE(bool) read_string_unicode( char **out, ntlm_client *ntlm, ntlm_buf *message, @@ -504,7 +504,7 @@ static inline bool read_string_unicode( return ret; } -static inline bool read_string_ascii( +NTLM_INLINE(bool) read_string_ascii( char **out, ntlm_client *ntlm, ntlm_buf *message, @@ -526,7 +526,7 @@ static inline bool read_string_ascii( return true; } -static inline bool read_string( +NTLM_INLINE(bool) read_string( char **out, ntlm_client *ntlm, ntlm_buf *message, @@ -539,7 +539,7 @@ static inline bool read_string( return read_string_ascii(out, ntlm, message, string_len); } -static inline bool read_target_info( +NTLM_INLINE(bool) read_target_info( char **server_out, char **domain_out, char **server_dns_out, @@ -965,7 +965,7 @@ static void des_key_from_password( generate_odd_parity(out); } -static inline bool generate_lm_hash( +NTLM_INLINE(bool) generate_lm_hash( ntlm_des_block out[2], ntlm_client *ntlm, const char *password) diff --git a/deps/ntlmclient/unicode_builtin.c b/deps/ntlmclient/unicode_builtin.c index 6d398b7c9f8..cb98f70b3db 100644 --- a/deps/ntlmclient/unicode_builtin.c +++ b/deps/ntlmclient/unicode_builtin.c @@ -12,6 +12,7 @@ #include "ntlm.h" #include "unicode.h" #include "compat.h" +#include "util.h" typedef unsigned int UTF32; /* at least 32 bits */ typedef unsigned short UTF16; /* at least 16 bits */ @@ -180,7 +181,7 @@ static ConversionResult ConvertUTF16toUTF8 ( * definition of UTF-8 goes up to 4-byte sequences. */ -static inline bool isLegalUTF8(const UTF8 *source, int length) { +NTLM_INLINE(bool) isLegalUTF8(const UTF8 *source, int length) { UTF8 a; const UTF8 *srcptr = source+length; switch (length) { @@ -288,7 +289,7 @@ typedef enum { unicode_builtin_utf16_to_8 } unicode_builtin_encoding_direction; -static inline bool unicode_builtin_encoding_convert( +NTLM_INLINE(bool) unicode_builtin_encoding_convert( char **converted, size_t *converted_len, ntlm_client *ntlm, diff --git a/deps/ntlmclient/unicode_iconv.c b/deps/ntlmclient/unicode_iconv.c index e14da21f545..ac53638bf86 100644 --- a/deps/ntlmclient/unicode_iconv.c +++ b/deps/ntlmclient/unicode_iconv.c @@ -14,6 +14,7 @@ #include "ntlmclient.h" #include "unicode.h" #include "ntlm.h" +#include "util.h" #include "compat.h" typedef enum { @@ -40,7 +41,7 @@ bool ntlm_unicode_init(ntlm_client *ntlm) return true; } -static inline bool unicode_iconv_encoding_convert( +NTLM_INLINE(bool) unicode_iconv_encoding_convert( char **converted, size_t *converted_len, ntlm_client *ntlm, diff --git a/deps/ntlmclient/utf8.h b/deps/ntlmclient/utf8.h index 5f02b555549..495e259db30 100644 --- a/deps/ntlmclient/utf8.h +++ b/deps/ntlmclient/utf8.h @@ -43,6 +43,14 @@ #pragma warning(disable : 4820) #endif +#if defined(__cplusplus) +#if defined(_MSC_VER) +#define utf8_cplusplus _MSVC_LANG +#else +#define utf8_cplusplus __cplusplus +#endif +#endif + #include #include @@ -67,7 +75,7 @@ typedef int32_t utf8_int32_t; #endif #endif -#ifdef __cplusplus +#ifdef utf8_cplusplus extern "C" { #endif @@ -96,13 +104,13 @@ extern "C" { #error Non clang, non gcc, non MSVC, non tcc compiler found! #endif -#ifdef __cplusplus +#ifdef utf8_cplusplus #define utf8_null NULL #else #define utf8_null 0 #endif -#if (defined(__cplusplus) && __cplusplus >= 201402L) +#if defined(utf8_cplusplus) && utf8_cplusplus >= 201402L && (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1910)) #define utf8_constexpr14 constexpr #define utf8_constexpr14_impl constexpr #else @@ -111,7 +119,7 @@ extern "C" { #define utf8_constexpr14_impl #endif -#if defined(__cplusplus) && __cplusplus >= 202002L +#if defined(utf8_cplusplus) && utf8_cplusplus >= 202002L using utf8_int8_t = char8_t; /* Introduced in C++20 */ #else typedef char utf8_int8_t; @@ -1693,7 +1701,7 @@ utf8rcodepoint(const utf8_int8_t *utf8_restrict str, #undef utf8_constexpr14 #undef utf8_null -#ifdef __cplusplus +#ifdef utf8_cplusplus } /* extern "C" */ #endif diff --git a/deps/ntlmclient/util.h b/deps/ntlmclient/util.h index d4bb472ccc4..48e0169932f 100644 --- a/deps/ntlmclient/util.h +++ b/deps/ntlmclient/util.h @@ -9,6 +9,17 @@ #ifndef PRIVATE_UTIL_H__ #define PRIVATE_UTIL_H__ +#include +#include + +#if defined(_MSC_VER) +# define NTLM_INLINE(type) static __inline type +#elif defined(__GNUC__) +# define NTLM_INLINE(type) static __inline__ type +#else +# define NTLM_INLINE(type) static type +#endif + extern void ntlm_memzero(void *data, size_t size); extern uint64_t ntlm_htonll(uint64_t value); From d090433ef12e67230364df8c3f3dfaeab9510113 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 19 Oct 2024 13:18:04 +0100 Subject: [PATCH 654/816] cmake: use CMAKE_C_STANDARD and CMAKE_C_EXTENSIONS cmake already provides a standard way for callers to override the C_STANDARD and C_EXTENSIONS properties. Support and document those. --- CMakeLists.txt | 3 ++- README.md | 4 ++-- cmake/SetCStandard.cmake | 24 ------------------------ deps/ntlmclient/CMakeLists.txt | 1 - examples/CMakeLists.txt | 1 - fuzzers/CMakeLists.txt | 1 - src/cli/CMakeLists.txt | 1 - src/libgit2/CMakeLists.txt | 1 - src/util/CMakeLists.txt | 1 - tests/headertest/CMakeLists.txt | 1 - tests/libgit2/CMakeLists.txt | 1 - tests/util/CMakeLists.txt | 1 - 12 files changed, 4 insertions(+), 36 deletions(-) delete mode 100644 cmake/SetCStandard.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index daa893e6471..e260bdbb59c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,8 @@ option(SONAME "Set the (SO)VERSION of the target" option(DEPRECATE_HARD "Do not include deprecated functions in the library" OFF) # Compilation options + set(CMAKE_C_STANDARD "90" CACHE STRING "The C standard to compile against") +option(CMAKE_C_EXTENSIONS "Whether compiler extensions are supported" OFF) option(ENABLE_WERROR "Enable compilation with -Werror" OFF) if(UNIX) @@ -91,7 +93,6 @@ endif() # Modules include(FeatureSummary) -include(SetCStandard) include(CheckLibraryExists) include(CheckFunctionExists) include(CheckSymbolExists) diff --git a/README.md b/README.md index bfca5c88854..55b3c536cb0 100644 --- a/README.md +++ b/README.md @@ -378,8 +378,8 @@ linker. These flags may be useful for cross-compilation or specialized setups. - `CMAKE_C_FLAGS`: Set your own compiler flags -- `C_STANDARD`: the C standard to compile against; defaults to `C90` -- `C_EXTENSIONS`: whether compiler extensions are supported; defaults to `OFF` +- `CMAKE_C_STANDARD`: the C standard to compile against; defaults to `C90` +- `CMAKE_C_EXTENSIONS`: whether compiler extensions are supported; defaults to `OFF` - `CMAKE_FIND_ROOT_PATH`: Override the search path for libraries - `ZLIB_LIBRARY`, `OPENSSL_SSL_LIBRARY` AND `OPENSSL_CRYPTO_LIBRARY`: Tell CMake where to find those specific libraries diff --git a/cmake/SetCStandard.cmake b/cmake/SetCStandard.cmake deleted file mode 100644 index f4fde658a92..00000000000 --- a/cmake/SetCStandard.cmake +++ /dev/null @@ -1,24 +0,0 @@ -if("${C_STANDARD}" STREQUAL "") - set(C_STANDARD "90") -endif() -if("${C_EXTENSIONS}" STREQUAL "") - set(C_EXTENSIONS OFF) -endif() - -if(${C_STANDARD} MATCHES "^[Cc].*") - string(REGEX REPLACE "^[Cc]" "" C_STANDARD ${C_STANDARD}) -endif() - -if(${C_STANDARD} MATCHES ".*-strict$") - string(REGEX REPLACE "-strict$" "" C_STANDARD ${C_STANDARD}) - set(C_EXTENSIONS OFF) - - add_feature_info("C Standard" ON "C${C_STANDARD} (strict)") -else() - add_feature_info("C Standard" ON "C${C_STANDARD}") -endif() - -function(set_c_standard project) - set_target_properties(${project} PROPERTIES C_STANDARD ${C_STANDARD}) - set_target_properties(${project} PROPERTIES C_EXTENSIONS ${C_EXTENSIONS}) -endfunction() diff --git a/deps/ntlmclient/CMakeLists.txt b/deps/ntlmclient/CMakeLists.txt index 420d1006cea..f1f5de162a0 100644 --- a/deps/ntlmclient/CMakeLists.txt +++ b/deps/ntlmclient/CMakeLists.txt @@ -37,4 +37,3 @@ else() endif() add_library(ntlmclient OBJECT ${SRC_NTLMCLIENT} ${SRC_NTLMCLIENT_UNICODE} ${SRC_NTLMCLIENT_CRYPTO}) -set_target_properties(ntlmclient PROPERTIES C_STANDARD 90) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e8472424712..986daae59df 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,7 +3,6 @@ file(GLOB SRC_EXAMPLES *.c *.h) add_executable(lg2 ${SRC_EXAMPLES}) -set_c_standard(lg2) # Ensure that we do not use deprecated functions internally add_definitions(-DGIT_DEPRECATE_HARD) diff --git a/fuzzers/CMakeLists.txt b/fuzzers/CMakeLists.txt index 32b91e4468a..4063def331a 100644 --- a/fuzzers/CMakeLists.txt +++ b/fuzzers/CMakeLists.txt @@ -20,7 +20,6 @@ foreach(fuzz_target_src ${SRC_FUZZERS}) endif() add_executable(${fuzz_target_name} ${${fuzz_target_name}_SOURCES}) - set_c_standard(${fuzz_target_name}) target_include_directories(${fuzz_target_name} PRIVATE ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) target_include_directories(${fuzz_target_name} SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 85544514202..d121c588a6c 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -40,7 +40,6 @@ add_executable(git2_cli ${CLI_SRC_C} ${CLI_SRC_OS} ${CLI_OBJECTS} ${LIBGIT2_DEPENDENCY_OBJECTS}) target_link_libraries(git2_cli ${CLI_LIBGIT2_LIBRARY} ${LIBGIT2_SYSTEM_LIBS}) -set_c_standard(git2_cli) set_target_properties(git2_cli PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR}) set_target_properties(git2_cli PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index 66b8394a3fb..1480dda0b9e 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -2,7 +2,6 @@ # git library functionality. add_library(libgit2 OBJECT) -set_c_standard(libgit2) include(PkgBuildConfig) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index c0ee7447275..dce8dee9584 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -1,7 +1,6 @@ # util: a shared library for common utility functions for libgit2 projects add_library(util OBJECT) -set_c_standard(util) configure_file(git2_features.h.in git2_features.h) diff --git a/tests/headertest/CMakeLists.txt b/tests/headertest/CMakeLists.txt index db294b7daca..b352458d513 100644 --- a/tests/headertest/CMakeLists.txt +++ b/tests/headertest/CMakeLists.txt @@ -3,7 +3,6 @@ # even when they have aggressive C90 warnings enabled. add_executable(headertest headertest.c) -set_c_standard(headertest) target_include_directories(headertest PRIVATE ${LIBGIT2_INCLUDES}) diff --git a/tests/libgit2/CMakeLists.txt b/tests/libgit2/CMakeLists.txt index 1eb109fb597..a660259b8dc 100644 --- a/tests/libgit2/CMakeLists.txt +++ b/tests/libgit2/CMakeLists.txt @@ -39,7 +39,6 @@ set_source_files_properties( PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) add_executable(libgit2_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) -set_c_standard(libgit2_tests) set_target_properties(libgit2_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) target_include_directories(libgit2_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index 1b5799495a0..aab429ab161 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -38,7 +38,6 @@ set_source_files_properties( PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) add_executable(util_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) -set_c_standard(util_tests) set_target_properties(util_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR}) From 821d41a907ea27f74af47ee5df21c6fbc4ff2878 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 19 Oct 2024 13:19:12 +0100 Subject: [PATCH 655/816] ci: set CMAKE_C_EXTENSIONS for msan builds The memory sanitizer builds require c90 with extension _on_; enable that. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 46dfe602fb9..cb362eaf118 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -132,7 +132,7 @@ jobs: env: CC: clang CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DC_EXTENSIONS=ON -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DCMAKE_C_EXTENSIONS=ON -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true From 9c3fb6f85b25d8d8a43737a8f752f667b56b6fb0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 6 Sep 2021 17:53:28 -0400 Subject: [PATCH 656/816] tests: init clone options the proper way --- tests/libgit2/online/fetchhead.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/libgit2/online/fetchhead.c b/tests/libgit2/online/fetchhead.c index 1b66c528e97..60a2b625d32 100644 --- a/tests/libgit2/online/fetchhead.c +++ b/tests/libgit2/online/fetchhead.c @@ -12,12 +12,9 @@ static git_clone_options g_options; void test_online_fetchhead__initialize(void) { - git_fetch_options dummy_fetch = GIT_FETCH_OPTIONS_INIT; g_repo = NULL; - memset(&g_options, 0, sizeof(git_clone_options)); - g_options.version = GIT_CLONE_OPTIONS_VERSION; - g_options.fetch_opts = dummy_fetch; + git_clone_options_init(&g_options, GIT_CLONE_OPTIONS_VERSION); } void test_online_fetchhead__cleanup(void) From 7db332022b234dbb40ff03528e9b75eaacf6bd0c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 19 Oct 2024 14:29:57 +0100 Subject: [PATCH 657/816] llhttp: use c-style comments --- deps/llhttp/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/llhttp/api.c b/deps/llhttp/api.c index 8c2ce3dc5c4..eddb478315a 100644 --- a/deps/llhttp/api.c +++ b/deps/llhttp/api.c @@ -93,7 +93,7 @@ void llhttp_free(llhttp_t* parser) { free(parser); } -#endif // defined(__wasm__) +#endif /* defined(__wasm__) */ /* Some getters required to get stuff from the parser */ From 0013a6f9b2e5426e57b49bd53a85775dda78aa26 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 19 Oct 2024 18:19:38 +0100 Subject: [PATCH 658/816] cmake: default to c99 on android --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e260bdbb59c..f99a69c4378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,12 @@ option(SONAME "Set the (SO)VERSION of the target" option(DEPRECATE_HARD "Do not include deprecated functions in the library" OFF) # Compilation options +# Default to c99 on Android Studio for compatibility; c90 everywhere else +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") + set(CMAKE_C_STANDARD "99" CACHE STRING "The C standard to compile against") +else() set(CMAKE_C_STANDARD "90" CACHE STRING "The C standard to compile against") +endif() option(CMAKE_C_EXTENSIONS "Whether compiler extensions are supported" OFF) option(ENABLE_WERROR "Enable compilation with -Werror" OFF) From 933b62eedf127f31f2371e37a711f11b4896c239 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 6 Sep 2021 08:25:22 -0400 Subject: [PATCH 659/816] checkout: make safe checkout the default Make `GIT_CHECKOUT_SAFE` the default. `NONE` is never what the user wants _by default_; people expect checkout to, well, check things out. Instead, it should be an opt-in "dry run" mode. This removes some odd code in internal callers of `checkout` that takes a `git_checkout_options` and updates the mode to `SAFE`. This is now unnecessary since everything has better defaults. --- include/git2/checkout.h | 56 +++++++++++---------- include/git2/clone.h | 11 ++-- include/git2/rebase.h | 7 ++- include/git2/stash.h | 2 - include/git2/submodule.h | 11 ++-- src/libgit2/apply.c | 1 - src/libgit2/checkout.c | 36 ++++++++----- src/libgit2/checkout.h | 2 - src/libgit2/cherrypick.c | 3 +- src/libgit2/clone.c | 1 + src/libgit2/merge.c | 3 +- src/libgit2/revert.c | 3 +- tests/libgit2/checkout/binaryunicode.c | 2 - tests/libgit2/checkout/conflict.c | 17 +------ tests/libgit2/checkout/head.c | 3 -- tests/libgit2/checkout/icase.c | 17 +++---- tests/libgit2/checkout/index.c | 36 ++++++------- tests/libgit2/checkout/tree.c | 27 +++------- tests/libgit2/cherrypick/workdir.c | 2 +- tests/libgit2/clone/nonetwork.c | 1 - tests/libgit2/merge/workdir/dirty.c | 1 - tests/libgit2/merge/workdir/renames.c | 2 +- tests/libgit2/merge/workdir/simple.c | 4 +- tests/libgit2/online/clone.c | 2 - tests/libgit2/perf/helper__perf__do_merge.c | 3 +- tests/libgit2/revert/workdir.c | 2 +- 26 files changed, 107 insertions(+), 148 deletions(-) diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 9f834111a67..45eba5fb6ff 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -31,17 +31,11 @@ GIT_BEGIN_DECL * check out, the "baseline" tree of what was checked out previously, the * working directory for actual files, and the index for staged changes. * - * You give checkout one of three strategies for update: + * You give checkout one of two strategies for update: * - * - `GIT_CHECKOUT_NONE` is a dry-run strategy that checks for conflicts, - * etc., but doesn't make any actual changes. - * - * - `GIT_CHECKOUT_FORCE` is at the opposite extreme, taking any action to - * make the working directory match the target (including potentially - * discarding modified files). - * - * - `GIT_CHECKOUT_SAFE` is between these two options, it will only make - * modifications that will not lose changes. + * - `GIT_CHECKOUT_SAFE` is the default, and similar to git's default, + * which will make modifications that will not lose changes in the + * working directory. * * | target == baseline | target != baseline | * ---------------------|-----------------------|----------------------| @@ -55,6 +49,10 @@ GIT_BEGIN_DECL * baseline present | | | * ---------------------|-----------------------|----------------------| * + * - `GIT_CHECKOUT_FORCE` will take any action to make the working + * directory match the target (including potentially discarding + * modified files). + * * To emulate `git checkout`, use `GIT_CHECKOUT_SAFE` with a checkout * notification callback (see below) that displays information about dirty * files. The default behavior will cancel checkout on conflicts. @@ -69,6 +67,9 @@ GIT_BEGIN_DECL * * There are some additional flags to modify the behavior of checkout: * + * - `GIT_CHECKOUT_DRY_RUN` is a dry-run strategy that checks for conflicts, + * etc., but doesn't make any actual changes. + * * - GIT_CHECKOUT_ALLOW_CONFLICTS makes SAFE mode apply safe file updates * even if there are conflicts (instead of cancelling the checkout). * @@ -104,27 +105,20 @@ GIT_BEGIN_DECL * and write through existing symbolic links. */ typedef enum { - GIT_CHECKOUT_NONE = 0, /**< default is a dry run, no actual updates */ - /** * Allow safe updates that cannot overwrite uncommitted data. - * If the uncommitted changes don't conflict with the checked out files, - * the checkout will still proceed, leaving the changes intact. - * - * Mutually exclusive with GIT_CHECKOUT_FORCE. - * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE. + * If the uncommitted changes don't conflict with the checked + * out files, the checkout will still proceed, leaving the + * changes intact. */ - GIT_CHECKOUT_SAFE = (1u << 0), + GIT_CHECKOUT_SAFE = 0, /** - * Allow all updates to force working directory to look like index. - * - * Mutually exclusive with GIT_CHECKOUT_SAFE. - * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE. + * Allow all updates to force working directory to look like + * the index, potentially losing data in the process. */ GIT_CHECKOUT_FORCE = (1u << 1), - /** Allow checkout to recreate missing files */ GIT_CHECKOUT_RECREATE_MISSING = (1u << 2), @@ -178,14 +172,23 @@ typedef enum { GIT_CHECKOUT_DONT_WRITE_INDEX = (1u << 23), /** - * Show what would be done by a checkout. Stop after sending - * notifications; don't update the working directory or index. + * Perform a "dry run", reporting what _would_ be done but + * without actually making changes in the working directory + * or the index. */ GIT_CHECKOUT_DRY_RUN = (1u << 24), /** Include common ancestor data in zdiff3 format for conflicts */ GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3 = (1u << 25), + /** + * Do not do a checkout and do not fire callbacks; this is primarily + * useful only for internal functions that will perform the + * checkout themselves but need to pass checkout options into + * another function, for example, `git_clone`. + */ + GIT_CHECKOUT_NONE = (1u << 30), + /** * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED */ @@ -194,7 +197,6 @@ typedef enum { GIT_CHECKOUT_UPDATE_SUBMODULES = (1u << 16), /** Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) */ GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED = (1u << 17) - } git_checkout_strategy_t; /** @@ -345,7 +347,7 @@ typedef struct git_checkout_options { } git_checkout_options; #define GIT_CHECKOUT_OPTIONS_VERSION 1 -#define GIT_CHECKOUT_OPTIONS_INIT {GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE} +#define GIT_CHECKOUT_OPTIONS_INIT {GIT_CHECKOUT_OPTIONS_VERSION} /** * Initialize git_checkout_options structure diff --git a/include/git2/clone.h b/include/git2/clone.h index 3481f254c9d..0e3012eea6a 100644 --- a/include/git2/clone.h +++ b/include/git2/clone.h @@ -105,8 +105,8 @@ typedef struct git_clone_options { /** * These options are passed to the checkout step. To disable - * checkout, set the `checkout_strategy` to - * `GIT_CHECKOUT_NONE`. + * checkout, set the `checkout_strategy` to `GIT_CHECKOUT_NONE` + * or `GIT_CHECKOUT_DRY_RUN`. */ git_checkout_options checkout_opts; @@ -164,9 +164,10 @@ typedef struct git_clone_options { } git_clone_options; #define GIT_CLONE_OPTIONS_VERSION 1 -#define GIT_CLONE_OPTIONS_INIT { GIT_CLONE_OPTIONS_VERSION, \ - { GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE }, \ - GIT_FETCH_OPTIONS_INIT } +#define GIT_CLONE_OPTIONS_INIT \ + { GIT_CLONE_OPTIONS_VERSION, \ + GIT_CHECKOUT_OPTIONS_INIT, \ + GIT_FETCH_OPTIONS_INIT } /** * Initialize git_clone_options structure diff --git a/include/git2/rebase.h b/include/git2/rebase.h index b1ac71f94ee..a53e68d9cf9 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -67,10 +67,9 @@ typedef struct { /** * Options to control how files are written during `git_rebase_init`, - * `git_rebase_next` and `git_rebase_abort`. Note that a minimum - * strategy of `GIT_CHECKOUT_SAFE` is defaulted in `init` and `next`, - * and a minimum strategy of `GIT_CHECKOUT_FORCE` is defaulted in - * `abort` to match git semantics. + * `git_rebase_next` and `git_rebase_abort`. Note that during + * `abort`, these options will add an implied `GIT_CHECKOUT_FORCE` + * to match git semantics. */ git_checkout_options checkout_options; diff --git a/include/git2/stash.h b/include/git2/stash.h index dcfc013dc4e..b43ae6b24b6 100644 --- a/include/git2/stash.h +++ b/include/git2/stash.h @@ -225,8 +225,6 @@ GIT_EXTERN(int) git_stash_apply_options_init( * GIT_EMERGECONFLICT and both the working directory and index will be left * unmodified. * - * Note that a minimum checkout strategy of `GIT_CHECKOUT_SAFE` is implied. - * * @param repo The owning repository. * @param index The position within the stash list. 0 points to the * most recent stashed state. diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 2082966f6bb..25d6687a9c9 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -130,10 +130,8 @@ typedef struct git_submodule_update_options { /** * These options are passed to the checkout step. To disable - * checkout, set the `checkout_strategy` to - * `GIT_CHECKOUT_NONE`. Generally you will want the use - * GIT_CHECKOUT_SAFE to update files in the working - * directory. + * checkout, set the `checkout_strategy` to `GIT_CHECKOUT_NONE` + * or `GIT_CHECKOUT_DRY_RUN`. */ git_checkout_options checkout_opts; @@ -155,8 +153,9 @@ typedef struct git_submodule_update_options { #define GIT_SUBMODULE_UPDATE_OPTIONS_VERSION 1 #define GIT_SUBMODULE_UPDATE_OPTIONS_INIT \ { GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \ - { GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE }, \ - GIT_FETCH_OPTIONS_INIT, 1 } + GIT_CHECKOUT_OPTIONS_INIT, \ + GIT_FETCH_OPTIONS_INIT, \ + 1 } /** * Initialize git_submodule_update_options structure diff --git a/src/libgit2/apply.c b/src/libgit2/apply.c index c5c99c3ecbb..07e502db259 100644 --- a/src/libgit2/apply.c +++ b/src/libgit2/apply.c @@ -713,7 +713,6 @@ static int git_apply__to_workdir( goto done; } - checkout_opts.checkout_strategy |= GIT_CHECKOUT_SAFE; checkout_opts.checkout_strategy |= GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH; checkout_opts.checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX; diff --git a/src/libgit2/checkout.c b/src/libgit2/checkout.c index 4628f33b2c6..f4b1ea96f84 100644 --- a/src/libgit2/checkout.c +++ b/src/libgit2/checkout.c @@ -294,6 +294,9 @@ static int checkout_action_no_wd( *action = CHECKOUT_ACTION__NONE; + if ((data->strategy & GIT_CHECKOUT_NONE)) + return 0; + switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 12 */ error = checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL); @@ -302,17 +305,17 @@ static int checkout_action_no_wd( *action = CHECKOUT_ACTION_IF(RECREATE_MISSING, UPDATE_BLOB, NONE); break; case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */ - *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION__UPDATE_BLOB; break; case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */ *action = CHECKOUT_ACTION_IF(RECREATE_MISSING, UPDATE_BLOB, CONFLICT); break; case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/ if (delta->new_file.mode == GIT_FILEMODE_TREE) - *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION__UPDATE_BLOB; break; case GIT_DELTA_DELETED: /* case 8 or 25 */ - *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); + *action = CHECKOUT_ACTION__REMOVE; break; default: /* impossible */ break; @@ -494,6 +497,9 @@ static int checkout_action_with_wd( { *action = CHECKOUT_ACTION__NONE; + if ((data->strategy & GIT_CHECKOUT_NONE)) + return 0; + switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */ if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) { @@ -512,14 +518,14 @@ static int checkout_action_with_wd( if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); else - *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); + *action = CHECKOUT_ACTION__REMOVE; break; case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */ if (wd->mode != GIT_FILEMODE_COMMIT && checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); else - *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION__UPDATE_BLOB; break; case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */ if (delta->old_file.mode == GIT_FILEMODE_TREE) { @@ -527,13 +533,13 @@ static int checkout_action_with_wd( /* either deleting items in old tree will delete the wd dir, * or we'll get a conflict when we attempt blob update... */ - *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION__UPDATE_BLOB; else if (wd->mode == GIT_FILEMODE_COMMIT) { /* workdir is possibly a "phantom" submodule - treat as a * tree if the only submodule info came from the config */ if (submodule_is_config_only(data, wd->path)) - *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION__UPDATE_BLOB; else *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); } else @@ -542,7 +548,7 @@ static int checkout_action_with_wd( else if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); else - *action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE); + *action = CHECKOUT_ACTION__REMOVE_AND_UPDATE; /* don't update if the typechange is to a tree */ if (delta->new_file.mode == GIT_FILEMODE_TREE) @@ -563,6 +569,9 @@ static int checkout_action_with_wd_blocker( { *action = CHECKOUT_ACTION__NONE; + if ((data->strategy & GIT_CHECKOUT_NONE)) + return 0; + switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* should show delta as dirty / deleted */ @@ -597,6 +606,9 @@ static int checkout_action_with_wd_dir( { *action = CHECKOUT_ACTION__NONE; + if ((data->strategy & GIT_CHECKOUT_NONE)) + return 0; + switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */ GIT_ERROR_CHECK_ERROR( @@ -627,7 +639,7 @@ static int checkout_action_with_wd_dir( * directory if is it left empty, so we can defer removing the * dir and it will succeed if no children are left. */ - *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION__UPDATE_BLOB; } else if (delta->new_file.mode != GIT_FILEMODE_TREE) /* For typechange to dir, dir is already created so no action */ @@ -2433,14 +2445,12 @@ static int checkout_data_init( /* if you are forcing, allow all safe updates, plus recreate missing */ if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0) - data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE | - GIT_CHECKOUT_RECREATE_MISSING; + data->opts.checkout_strategy |= GIT_CHECKOUT_RECREATE_MISSING; /* if the repository does not actually have an index file, then this * is an initial checkout (perhaps from clone), so we allow safe updates */ - if (!data->index->on_disk && - (data->opts.checkout_strategy & GIT_CHECKOUT_SAFE) != 0) + if (!data->index->on_disk) data->opts.checkout_strategy |= GIT_CHECKOUT_RECREATE_MISSING; data->strategy = data->opts.checkout_strategy; diff --git a/src/libgit2/checkout.h b/src/libgit2/checkout.h index 517fbf3b15e..e613325c7e8 100644 --- a/src/libgit2/checkout.h +++ b/src/libgit2/checkout.h @@ -12,8 +12,6 @@ #include "git2/checkout.h" #include "iterator.h" -#define GIT_CHECKOUT__NOTIFY_CONFLICT_TREE (1u << 12) - /** * Update the working directory to match the target iterator. The * expected baseline value can be passed in via the checkout options diff --git a/src/libgit2/cherrypick.c b/src/libgit2/cherrypick.c index 3ef42d5e78e..561370169fc 100644 --- a/src/libgit2/cherrypick.c +++ b/src/libgit2/cherrypick.c @@ -73,8 +73,7 @@ static int cherrypick_normalize_opts( const char *their_label) { int error = 0; - unsigned int default_checkout_strategy = GIT_CHECKOUT_SAFE | - GIT_CHECKOUT_ALLOW_CONFLICTS; + unsigned int default_checkout_strategy = GIT_CHECKOUT_ALLOW_CONFLICTS; GIT_UNUSED(repo); diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index d62c77ac554..c5ad247b117 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -16,6 +16,7 @@ #include "git2/commit.h" #include "git2/tree.h" +#include "checkout.h" #include "remote.h" #include "futils.h" #include "refs.h" diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 5f90a8bf87e..25834c69fed 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -3352,8 +3352,7 @@ int git_merge( goto done; checkout_strategy = given_checkout_opts ? - given_checkout_opts->checkout_strategy : - GIT_CHECKOUT_SAFE; + given_checkout_opts->checkout_strategy : 0; if ((error = git_indexwriter_init_for_operation(&indexwriter, repo, &checkout_strategy)) < 0) diff --git a/src/libgit2/revert.c b/src/libgit2/revert.c index 4a31ad40a1a..2fb53f8f541 100644 --- a/src/libgit2/revert.c +++ b/src/libgit2/revert.c @@ -74,8 +74,7 @@ static int revert_normalize_opts( const char *their_label) { int error = 0; - unsigned int default_checkout_strategy = GIT_CHECKOUT_SAFE | - GIT_CHECKOUT_ALLOW_CONFLICTS; + unsigned int default_checkout_strategy = GIT_CHECKOUT_ALLOW_CONFLICTS; GIT_UNUSED(repo); diff --git a/tests/libgit2/checkout/binaryunicode.c b/tests/libgit2/checkout/binaryunicode.c index b8c6c079e1f..e4cab66a350 100644 --- a/tests/libgit2/checkout/binaryunicode.c +++ b/tests/libgit2/checkout/binaryunicode.c @@ -28,8 +28,6 @@ static void execute_test(void) cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_git_pass(git_commit_tree(&tree, commit)); - opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_checkout_tree(g_repo, (git_object *)tree, &opts)); git_tree_free(tree); diff --git a/tests/libgit2/checkout/conflict.c b/tests/libgit2/checkout/conflict.c index d6cb6fff231..ab4d0aba4d4 100644 --- a/tests/libgit2/checkout/conflict.c +++ b/tests/libgit2/checkout/conflict.c @@ -308,8 +308,6 @@ void test_checkout_conflict__directory_file(void) { 0100644, CONFLICTING_THEIRS_OID, 3, "df-4/file" }, }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; - create_index(checkout_index_entries, 12); cl_git_pass(git_index_write(g_index)); @@ -347,7 +345,6 @@ void test_checkout_conflict__directory_file_with_custom_labels(void) { 0100644, CONFLICTING_THEIRS_OID, 3, "df-4/file" }, }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; opts.our_label = "HEAD"; opts.their_label = "branch"; @@ -388,8 +385,6 @@ void test_checkout_conflict__link_file(void) { 0100644, CONFLICTING_THEIRS_OID, 3, "link-4" }, }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; - create_index(checkout_index_entries, 12); cl_git_pass(git_index_write(g_index)); @@ -415,8 +410,6 @@ void test_checkout_conflict__links(void) { 0120000, LINK_THEIRS_OID, 3, "link-2" }, }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; - create_index(checkout_index_entries, 5); cl_git_pass(git_index_write(g_index)); @@ -436,8 +429,6 @@ void test_checkout_conflict__add_add(void) { 0100644, CONFLICTING_THEIRS_OID, 3, "conflicting.txt" }, }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; - create_index(checkout_index_entries, 2); cl_git_pass(git_index_write(g_index)); @@ -477,8 +468,6 @@ void test_checkout_conflict__mode_change(void) { 0100755, CONFLICTING_THEIRS_OID, 3, "executable-6" }, }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; - create_index(checkout_index_entries, 18); cl_git_pass(git_index_write(g_index)); @@ -608,8 +597,6 @@ void test_checkout_conflict__renames(void) } }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; - create_index(checkout_index_entries, 41); create_index_names(checkout_name_entries, 9); cl_git_pass(git_index_write(g_index)); @@ -793,7 +780,7 @@ void test_checkout_conflict__rename_keep_ours(void) } }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; + opts.checkout_strategy |= GIT_CHECKOUT_USE_OURS; create_index(checkout_index_entries, 41); create_index_names(checkout_name_entries, 9); @@ -926,8 +913,6 @@ void test_checkout_conflict__name_mangled_file_exists_in_workdir(void) } }; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; - create_index(checkout_index_entries, 24); create_index_names(checkout_name_entries, 6); cl_git_pass(git_index_write(g_index)); diff --git a/tests/libgit2/checkout/head.c b/tests/libgit2/checkout/head.c index 3b0bf472996..f67770e1fed 100644 --- a/tests/libgit2/checkout/head.c +++ b/tests/libgit2/checkout/head.c @@ -228,7 +228,6 @@ void test_checkout_head__workdir_filemode_is_simplified(void) cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff")); opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; cl_git_pass(git_checkout_tree(g_repo, branch, NULL)); git_object_free(branch); @@ -256,7 +255,6 @@ void test_checkout_head__obeys_filemode_true(void) cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff")); opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; cl_git_fail_with(GIT_ECONFLICT, git_checkout_tree(g_repo, branch, NULL)); git_object_free(branch); @@ -284,7 +282,6 @@ void test_checkout_head__obeys_filemode_false(void) cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff")); opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE; - opts.checkout_strategy |= GIT_CHECKOUT_SAFE; cl_git_pass(git_checkout_tree(g_repo, branch, NULL)); git_object_free(branch); diff --git a/tests/libgit2/checkout/icase.c b/tests/libgit2/checkout/icase.c index 3769a9f9b7e..4ff8fb28b0b 100644 --- a/tests/libgit2/checkout/icase.c +++ b/tests/libgit2/checkout/icase.c @@ -34,7 +34,6 @@ void test_checkout_icase__initialize(void) cl_git_pass(git_object_lookup(&obj, repo, &id, GIT_OBJECT_ANY)); git_checkout_options_init(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION); - checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE; } void test_checkout_icase__cleanup(void) @@ -106,7 +105,7 @@ static int symlink_or_fake(git_repository *repo, const char *a, const char *b) void test_checkout_icase__refuses_to_overwrite_files_for_files(void) { - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + checkout_opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_write2file("testrepo/BRANCH_FILE.txt", "neue file\n", 10, \ O_WRONLY | O_CREAT | O_TRUNC, 0644); @@ -128,7 +127,7 @@ void test_checkout_icase__overwrites_files_for_files_when_forced(void) void test_checkout_icase__refuses_to_overwrite_links_for_files(void) { - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + checkout_opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_must_pass(symlink_or_fake(repo, "../tmp", "testrepo/BRANCH_FILE.txt")); @@ -152,7 +151,7 @@ void test_checkout_icase__overwrites_links_for_files_when_forced(void) void test_checkout_icase__overwrites_empty_folders_for_files(void) { - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + checkout_opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_must_pass(p_mkdir("testrepo/NEW.txt", 0777)); @@ -164,7 +163,7 @@ void test_checkout_icase__overwrites_empty_folders_for_files(void) void test_checkout_icase__refuses_to_overwrite_populated_folders_for_files(void) { - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + checkout_opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_must_pass(p_mkdir("testrepo/BRANCH_FILE.txt", 0777)); cl_git_write2file("testrepo/BRANCH_FILE.txt/foobar", "neue file\n", 10, \ @@ -192,7 +191,7 @@ void test_checkout_icase__overwrites_folders_for_files_when_forced(void) void test_checkout_icase__refuses_to_overwrite_files_for_folders(void) { - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + checkout_opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_write2file("testrepo/A", "neue file\n", 10, \ O_WRONLY | O_CREAT | O_TRUNC, 0644); @@ -216,7 +215,7 @@ void test_checkout_icase__overwrites_files_for_folders_when_forced(void) void test_checkout_icase__refuses_to_overwrite_links_for_folders(void) { - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + checkout_opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_must_pass(symlink_or_fake(repo, "..", "testrepo/A")); @@ -244,8 +243,6 @@ void test_checkout_icase__ignores_unstaged_casechange(void) git_commit *orig, *br2; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup_resolved(&orig_ref, repo, "HEAD", 100)); cl_git_pass(git_commit_lookup(&orig, repo, git_reference_target(orig_ref))); cl_git_pass(git_reset(repo, (git_object *)orig, GIT_RESET_HARD, NULL)); @@ -270,8 +267,6 @@ void test_checkout_icase__conflicts_with_casechanged_subtrees(void) git_oid oid; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup_resolved(&orig_ref, repo, "HEAD", 100)); cl_git_pass(git_object_lookup(&orig, repo, git_reference_target(orig_ref), GIT_OBJECT_COMMIT)); cl_git_pass(git_reset(repo, (git_object *)orig, GIT_RESET_HARD, NULL)); diff --git a/tests/libgit2/checkout/index.c b/tests/libgit2/checkout/index.c index 3dfdaa630ae..03d5d392b54 100644 --- a/tests/libgit2/checkout/index.c +++ b/tests/libgit2/checkout/index.c @@ -61,7 +61,7 @@ void test_checkout_index__can_create_missing_files(void) cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/branch_file.txt")); cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/new.txt")); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -81,7 +81,6 @@ void test_checkout_index__can_remove_untracked_files(void) cl_assert_equal_i(true, git_fs_path_isdir("./testrepo/dir/subdir/subsubdir")); opts.checkout_strategy = - GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING | GIT_CHECKOUT_REMOVE_UNTRACKED; @@ -157,7 +156,7 @@ void test_checkout_index__honor_the_specified_pathspecs(void) cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/branch_file.txt")); cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/new.txt")); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -176,7 +175,7 @@ void test_checkout_index__honor_the_gitattributes_directives(void) cl_git_mkfile("./testrepo/.gitattributes", attributes); cl_repo_set_bool(g_repo, "core.autocrlf", false); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -194,7 +193,7 @@ void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void) cl_git_pass(p_unlink("./testrepo/.gitattributes")); cl_repo_set_bool(g_repo, "core.autocrlf", true); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -288,7 +287,7 @@ void test_checkout_index__coresymlinks_set_to_true_fails_when_unsupported(void) cl_repo_set_bool(g_repo, "core.symlinks", true); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_fail(git_checkout_index(g_repo, NULL, &opts)); } @@ -304,7 +303,7 @@ void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) cl_repo_set_bool(g_repo, "core.symlinks", true); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -321,7 +320,7 @@ void test_checkout_index__honor_coresymlinks_setting_set_to_false(void) cl_repo_set_bool(g_repo, "core.symlinks", false); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -337,7 +336,7 @@ void test_checkout_index__donot_overwrite_modified_file_by_default(void) /* set this up to not return an error code on conflicts, but it * still will not have permission to overwrite anything... */ - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS; + opts.checkout_strategy = GIT_CHECKOUT_ALLOW_CONFLICTS; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -363,7 +362,7 @@ void test_checkout_index__options_disable_filters(void) cl_git_mkfile("./testrepo/.gitattributes", "*.txt text eol=crlf\n"); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; opts.disable_filters = false; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -394,7 +393,7 @@ void test_checkout_index__options_dir_modes(void) reset_index_to_treeish((git_object *)commit); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; opts.dir_mode = 0701; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -421,7 +420,7 @@ void test_checkout_index__options_override_file_modes(void) if (!cl_is_chmod_supported()) return; - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; opts.file_mode = 0700; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); @@ -486,7 +485,7 @@ void test_checkout_index__can_notify_of_skipped_files(void) data.file = "new.txt"; data.sha = "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"; - opts.checkout_strategy = GIT_CHECKOUT_SAFE | + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING | GIT_CHECKOUT_ALLOW_CONFLICTS; opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; @@ -526,7 +525,6 @@ void test_checkout_index__wont_notify_of_expected_line_ending_changes(void) cl_git_mkfile("./testrepo/new.txt", "my new file\r\n"); opts.checkout_strategy = - GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING | GIT_CHECKOUT_ALLOW_CONFLICTS; opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; @@ -548,7 +546,7 @@ void test_checkout_index__calls_progress_callback(void) git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; int calls = 0; - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; opts.progress_cb = checkout_progress_counter; opts.progress_payload = &calls; @@ -583,7 +581,6 @@ void test_checkout_index__can_overcome_name_clashes(void) cl_assert(git_fs_path_isfile("./testrepo/path0/file0")); opts.checkout_strategy = - GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING | GIT_CHECKOUT_ALLOW_CONFLICTS; cl_git_pass(git_checkout_index(g_repo, index, &opts)); @@ -635,7 +632,6 @@ void test_checkout_index__can_update_prefixed_files(void) cl_git_pass(p_mkdir("./testrepo/branch_file.txt.after", 0777)); opts.checkout_strategy = - GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING | GIT_CHECKOUT_REMOVE_UNTRACKED; @@ -686,7 +682,7 @@ void test_checkout_index__target_directory(void) checkout_counts cts; memset(&cts, 0, sizeof(cts)); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; opts.target_directory = "alternative"; cl_assert(!git_fs_path_isdir("alternative")); @@ -731,7 +727,7 @@ void test_checkout_index__target_directory_from_bare(void) cl_git_pass(git_index_write(index)); git_index_free(index); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; @@ -770,7 +766,7 @@ void test_checkout_index__can_get_repo_from_index(void) cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/branch_file.txt")); cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/new.txt")); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_repository_index(&index, g_repo)); diff --git a/tests/libgit2/checkout/tree.c b/tests/libgit2/checkout/tree.c index 65df00cd87b..b9f51f7b977 100644 --- a/tests/libgit2/checkout/tree.c +++ b/tests/libgit2/checkout/tree.c @@ -186,8 +186,6 @@ void test_checkout_tree__can_switch_branches(void) git_object_free(obj); /* do second checkout safe because we should be clean after first */ - opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/subtrees")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); @@ -213,7 +211,7 @@ void test_checkout_tree__can_remove_untracked(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_REMOVE_UNTRACKED; + opts.checkout_strategy = GIT_CHECKOUT_REMOVE_UNTRACKED; cl_git_mkfile("testrepo/untracked_file", "as you wish"); cl_assert(git_fs_path_isfile("testrepo/untracked_file")); @@ -228,7 +226,7 @@ void test_checkout_tree__can_remove_ignored(void) git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; int ignored = 0; - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_REMOVE_IGNORED; + opts.checkout_strategy = GIT_CHECKOUT_REMOVE_IGNORED; cl_git_mkfile("testrepo/ignored_file", "as you wish"); @@ -313,7 +311,7 @@ void test_checkout_tree__conflict_on_ignored_when_not_overwriting(void) int error; cl_git_fail(error = checkout_tree_with_blob_ignored_in_workdir( - GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DONT_OVERWRITE_IGNORED, false)); + GIT_CHECKOUT_DONT_OVERWRITE_IGNORED, false)); cl_assert_equal_i(GIT_ECONFLICT, error); } @@ -334,7 +332,7 @@ void test_checkout_tree__conflict_on_ignored_folder_when_not_overwriting(void) int error; cl_git_fail(error = checkout_tree_with_blob_ignored_in_workdir( - GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DONT_OVERWRITE_IGNORED, true)); + GIT_CHECKOUT_DONT_OVERWRITE_IGNORED, true)); cl_assert_equal_i(GIT_ECONFLICT, error); } @@ -370,7 +368,7 @@ void test_checkout_tree__can_update_only(void) /* now checkout branch but with update only */ - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; + opts.checkout_strategy = GIT_CHECKOUT_UPDATE_ONLY; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); @@ -417,7 +415,6 @@ void test_checkout_tree__can_checkout_with_pattern(void) /* now to a narrow patterned checkout */ - g_opts.checkout_strategy = GIT_CHECKOUT_SAFE; g_opts.paths.strings = entries; g_opts.paths.count = 1; @@ -489,7 +486,6 @@ void test_checkout_tree__can_disable_pattern_match(void) /* now to a narrow patterned checkout, but disable pattern */ g_opts.checkout_strategy = - GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH; g_opts.paths.strings = entries; g_opts.paths.count = 1; @@ -606,8 +602,6 @@ void test_checkout_tree__donot_update_deleted_file_by_default(void) git_index *index = NULL; checkout_counts ct; - opts.checkout_strategy = GIT_CHECKOUT_SAFE; - memset(&ct, 0, sizeof(ct)); opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.notify_cb = checkout_count_callback; @@ -883,8 +877,7 @@ void test_checkout_tree__target_directory_from_bare(void) g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert(git_repository_is_bare(g_repo)); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | - GIT_CHECKOUT_RECREATE_MISSING; + opts.checkout_strategy = GIT_CHECKOUT_RECREATE_MISSING; opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.notify_cb = checkout_count_callback; @@ -963,8 +956,6 @@ void test_checkout_tree__fails_when_conflicts_exist_in_index(void) git_oid oid; git_object *obj = NULL; - opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_name_to_id(&oid, g_repo, "HEAD")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); @@ -1622,8 +1613,6 @@ void test_checkout_tree__retains_external_index_changes(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; - opts.checkout_strategy = GIT_CHECKOUT_SAFE; - modify_index_and_checkout_tree(&opts); assert_status_entrycount(g_repo, 1); } @@ -1632,7 +1621,7 @@ void test_checkout_tree__no_index_refresh(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_NO_REFRESH; + opts.checkout_strategy = GIT_CHECKOUT_NO_REFRESH; modify_index_and_checkout_tree(&opts); assert_status_entrycount(g_repo, 0); @@ -1659,7 +1648,7 @@ void test_checkout_tree__dry_run(void) /* now checkout branch but with dry run enabled */ memset(&ct, 0, sizeof(ct)); - opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DRY_RUN; + opts.checkout_strategy = GIT_CHECKOUT_DRY_RUN; opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.notify_cb = checkout_count_callback; opts.notify_payload = &ct; diff --git a/tests/libgit2/cherrypick/workdir.c b/tests/libgit2/cherrypick/workdir.c index c16b7814ac0..21e0b1447ee 100644 --- a/tests/libgit2/cherrypick/workdir.c +++ b/tests/libgit2/cherrypick/workdir.c @@ -257,7 +257,7 @@ void test_cherrypick_workdir__conflict_use_ours(void) }; /* leave the index in a conflicted state, but checkout "ours" to the workdir */ - opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; + opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_USE_OURS; git_oid__fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8", GIT_OID_SHA1); diff --git a/tests/libgit2/clone/nonetwork.c b/tests/libgit2/clone/nonetwork.c index 5316003f82a..e784ec20f4e 100644 --- a/tests/libgit2/clone/nonetwork.c +++ b/tests/libgit2/clone/nonetwork.c @@ -24,7 +24,6 @@ void test_clone_nonetwork__initialize(void) memset(&g_options, 0, sizeof(git_clone_options)); g_options.version = GIT_CLONE_OPTIONS_VERSION; g_options.checkout_opts = dummy_opts; - g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; g_options.fetch_opts = dummy_fetch; } diff --git a/tests/libgit2/merge/workdir/dirty.c b/tests/libgit2/merge/workdir/dirty.c index 36b42a10353..570e7c759e5 100644 --- a/tests/libgit2/merge/workdir/dirty.c +++ b/tests/libgit2/merge/workdir/dirty.c @@ -97,7 +97,6 @@ static int merge_branch(void) cl_git_pass(git_oid__fromstr(&their_oids[0], MERGE_BRANCH_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_oids[0])); - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; error = git_merge(repo, (const git_annotated_commit **)&their_head, 1, &merge_opts, &checkout_opts); git_annotated_commit_free(their_head); diff --git a/tests/libgit2/merge/workdir/renames.c b/tests/libgit2/merge/workdir/renames.c index 1b5128cf1b7..90f4b6910e1 100644 --- a/tests/libgit2/merge/workdir/renames.c +++ b/tests/libgit2/merge/workdir/renames.c @@ -100,7 +100,7 @@ void test_merge_workdir_renames__ours(void) merge_opts.flags |= GIT_MERGE_FIND_RENAMES; merge_opts.rename_threshold = 50; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; + checkout_opts.checkout_strategy = GIT_CHECKOUT_USE_OURS; cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR BRANCH_RENAME_OURS, GIT_REFS_HEADS_DIR BRANCH_RENAME_THEIRS, &merge_opts, &checkout_opts)); cl_git_pass(git_repository_index(&index, repo)); diff --git a/tests/libgit2/merge/workdir/simple.c b/tests/libgit2/merge/workdir/simple.c index e9cffeea822..17faabff06c 100644 --- a/tests/libgit2/merge/workdir/simple.c +++ b/tests/libgit2/merge/workdir/simple.c @@ -103,7 +103,7 @@ static void merge_simple_branch(int merge_file_favor, int addl_checkout_strategy cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = merge_file_favor; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS | + checkout_opts.checkout_strategy = GIT_CHECKOUT_ALLOW_CONFLICTS | addl_checkout_strategy; cl_git_pass(git_merge(repo, (const git_annotated_commit **)their_heads, 1, &merge_opts, &checkout_opts)); @@ -577,7 +577,7 @@ void test_merge_workdir_simple__checkout_ours(void) REMOVED_IN_MASTER_REUC_ENTRY }; - merge_simple_branch(0, GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS); + merge_simple_branch(0, GIT_CHECKOUT_USE_OURS); cl_assert(merge_test_index(repo_index, merge_index_entries, 8)); cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3)); diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 207dd839172..3753814f753 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -73,7 +73,6 @@ void test_online_clone__initialize(void) memset(&g_options, 0, sizeof(git_clone_options)); g_options.version = GIT_CLONE_OPTIONS_VERSION; g_options.checkout_opts = dummy_opts; - g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; g_options.fetch_opts = dummy_fetch; g_options.fetch_opts.callbacks.certificate_check = ssl_cert; @@ -249,7 +248,6 @@ void test_online_clone__can_checkout_a_cloned_repo(void) bool checkout_progress_cb_was_called = false, fetch_progress_cb_was_called = false; - g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; g_options.checkout_opts.progress_cb = &checkout_progress; g_options.checkout_opts.progress_payload = &checkout_progress_cb_was_called; g_options.fetch_opts.callbacks.transfer_progress = &fetch_progress; diff --git a/tests/libgit2/perf/helper__perf__do_merge.c b/tests/libgit2/perf/helper__perf__do_merge.c index eb10524ecc4..6f53af63cde 100644 --- a/tests/libgit2/perf/helper__perf__do_merge.c +++ b/tests/libgit2/perf/helper__perf__do_merge.c @@ -26,13 +26,12 @@ void perf__do_merge(const char *fixture, perf__timer__start(&t_total); - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; clone_opts.checkout_opts = checkout_opts; perf__timer__start(&t_clone); cl_git_pass(git_clone(&g_repo, fixture, test_name, &clone_opts)); perf__timer__stop(&t_clone); - + git_oid__fromstr(&oid_a, id_a, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit_a, g_repo, &oid_a)); cl_git_pass(git_branch_create(&ref_branch_a, g_repo, diff --git a/tests/libgit2/revert/workdir.c b/tests/libgit2/revert/workdir.c index 3e790b77f78..8d1246efe0d 100644 --- a/tests/libgit2/revert/workdir.c +++ b/tests/libgit2/revert/workdir.c @@ -374,7 +374,7 @@ void test_revert_workdir__conflict_use_ours(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; - opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; + opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_USE_OURS; git_oid__fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); From 69555048fd471934296e9fe7d8711170429cc904 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 1 Mar 2022 09:56:08 -0500 Subject: [PATCH 660/816] clone: refactor to pass clone options around Instead of dealing with the clone options sub-options (fetch, checkout, etc) individually, treat them as a cohesive whole when passing them throughout the system. Additionally, move some functions around within the file to avoid unnecessary decls at the top of the file. And change a function signature to avoid conflating truth with error. --- include/git2/checkout.h | 2 +- src/libgit2/clone.c | 306 ++++++++++++++++++------------------ src/libgit2/clone.h | 5 +- tests/libgit2/clone/local.c | 88 ++++++++--- 4 files changed, 229 insertions(+), 172 deletions(-) diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 45eba5fb6ff..3705a8d7bb3 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -189,7 +189,7 @@ typedef enum { */ GIT_CHECKOUT_NONE = (1u << 30), - /** + /* * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED */ diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index c5ad247b117..237efc0ba7d 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -25,8 +25,6 @@ #include "odb.h" #include "net.h" -static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link); - static int create_branch( git_reference **branch, git_repository *repo, @@ -367,12 +365,13 @@ static int should_checkout( bool *out, git_repository *repo, bool is_bare, - const git_checkout_options *opts) + const git_clone_options *opts) { int error; - if (!opts || is_bare || opts->checkout_strategy == GIT_CHECKOUT_NONE) { - *out = 0; + if (!opts || is_bare || + opts->checkout_opts.checkout_strategy == GIT_CHECKOUT_NONE) { + *out = false; return 0; } @@ -383,13 +382,17 @@ static int should_checkout( return 0; } -static int checkout_branch(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, const char *reflog_message) +static int checkout_branch( + git_repository *repo, + git_remote *remote, + const git_clone_options *opts, + const char *reflog_message) { bool checkout; int error; - if (branch) - error = update_head_to_branch(repo, remote, branch, reflog_message); + if (opts->checkout_branch) + error = update_head_to_branch(repo, remote, opts->checkout_branch, reflog_message); /* Point HEAD to the same ref as the remote's head */ else error = update_head_to_remote(repo, remote, reflog_message); @@ -397,11 +400,11 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c if (error < 0) return error; - if ((error = should_checkout(&checkout, repo, git_repository_is_bare(repo), co_opts)) < 0) + if ((error = should_checkout(&checkout, repo, git_repository_is_bare(repo), opts)) < 0) return error; if (checkout) - error = git_checkout_head(repo, co_opts); + error = git_checkout_head(repo, &opts->checkout_opts); return error; } @@ -409,16 +412,13 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c static int clone_into( git_repository *repo, git_remote *_remote, - const git_fetch_options *opts, - const git_checkout_options *co_opts, - const char *branch) + const git_clone_options *opts) { - int error; git_str reflog_message = GIT_STR_INIT; git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; - git_fetch_options fetch_opts; git_remote *remote; git_oid_t oid_type; + int error; GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(_remote); @@ -431,13 +431,7 @@ static int clone_into( if ((error = git_remote_dup(&remote, _remote)) < 0) return error; - memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); - fetch_opts.update_fetchhead = 0; - - if (!opts->depth) - fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; - - if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0) + if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &opts->fetch_opts)) < 0) goto cleanup; git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); @@ -455,10 +449,10 @@ static int clone_into( (error = git_repository__set_objectformat(repo, oid_type)) < 0) goto cleanup; - if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0) + if ((error = git_remote_fetch(remote, NULL, &opts->fetch_opts, git_str_cstr(&reflog_message))) != 0) goto cleanup; - error = checkout_branch(repo, remote, co_opts, branch, git_str_cstr(&reflog_message)); + error = checkout_branch(repo, remote, opts, git_str_cstr(&reflog_message)); cleanup: git_remote_free(remote); @@ -468,36 +462,142 @@ static int clone_into( return error; } -int git_clone__should_clone_local(const char *url_or_path, git_clone_local_t local) +static bool can_link(const char *src, const char *dst, int link) +{ +#ifdef GIT_WIN32 + GIT_UNUSED(src); + GIT_UNUSED(dst); + GIT_UNUSED(link); + return false; +#else + + struct stat st_src, st_dst; + + if (!link) + return false; + + if (p_stat(src, &st_src) < 0) + return false; + + if (p_stat(dst, &st_dst) < 0) + return false; + + return st_src.st_dev == st_dst.st_dev; +#endif +} + +static int clone_local_into( + git_repository *repo, + git_remote *remote, + const git_clone_options *opts) +{ + int error, flags; + git_repository *src; + git_str src_odb = GIT_STR_INIT, dst_odb = GIT_STR_INIT, src_path = GIT_STR_INIT; + git_str reflog_message = GIT_STR_INIT; + bool link = (opts && opts->local != GIT_CLONE_LOCAL_NO_LINKS); + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(remote); + + if (!git_repository_is_empty(repo)) { + git_error_set(GIT_ERROR_INVALID, "the repository is not empty"); + return -1; + } + + /* + * Let's figure out what path we should use for the source + * repo, if it's not rooted, the path should be relative to + * the repository's worktree/gitdir. + */ + if ((error = git_fs_path_from_url_or_path(&src_path, git_remote_url(remote))) < 0) + return error; + + /* Copy .git/objects/ from the source to the target */ + if ((error = git_repository_open(&src, git_str_cstr(&src_path))) < 0) { + git_str_dispose(&src_path); + return error; + } + + if (git_repository__item_path(&src_odb, src, GIT_REPOSITORY_ITEM_OBJECTS) < 0 || + git_repository__item_path(&dst_odb, repo, GIT_REPOSITORY_ITEM_OBJECTS) < 0) { + error = -1; + goto cleanup; + } + + flags = 0; + if (can_link(git_repository_path(src), git_repository_path(repo), link)) + flags |= GIT_CPDIR_LINK_FILES; + + error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), + flags, GIT_OBJECT_DIR_MODE); + + /* + * can_link() doesn't catch all variations, so if we hit an + * error and did want to link, let's try again without trying + * to link. + */ + if (error < 0 && link) { + flags &= ~GIT_CPDIR_LINK_FILES; + error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), + flags, GIT_OBJECT_DIR_MODE); + } + + if (error < 0) + goto cleanup; + + git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); + + if ((error = git_remote_fetch(remote, NULL, &opts->fetch_opts, git_str_cstr(&reflog_message))) != 0) + goto cleanup; + + error = checkout_branch(repo, remote, opts, git_str_cstr(&reflog_message)); + +cleanup: + git_str_dispose(&reflog_message); + git_str_dispose(&src_path); + git_str_dispose(&src_odb); + git_str_dispose(&dst_odb); + git_repository_free(src); + return error; +} + +int git_clone__should_clone_local( + bool *out, + const char *url_or_path, + git_clone_local_t local) { git_str fromurl = GIT_STR_INIT; - bool is_local; + + *out = false; if (local == GIT_CLONE_NO_LOCAL) return 0; if (git_net_str_is_url(url_or_path)) { - /* If GIT_CLONE_LOCAL_AUTO is specified, any url should be treated as remote */ + /* If GIT_CLONE_LOCAL_AUTO is specified, any url should + * be treated as remote */ if (local == GIT_CLONE_LOCAL_AUTO || !git_fs_path_is_local_file_url(url_or_path)) return 0; - if (git_fs_path_fromurl(&fromurl, url_or_path) == 0) - is_local = git_fs_path_isdir(git_str_cstr(&fromurl)); - else - is_local = -1; + if (git_fs_path_fromurl(&fromurl, url_or_path) < 0) + return -1; + + *out = git_fs_path_isdir(git_str_cstr(&fromurl)); git_str_dispose(&fromurl); } else { - is_local = git_fs_path_isdir(url_or_path); + *out = git_fs_path_isdir(url_or_path); } - return is_local; + + return 0; } -static int git__clone( +static int clone_repo( git_repository **out, const char *url, const char *local_path, - const git_clone_options *_options, + const git_clone_options *given_opts, int use_existing) { int error = 0; @@ -511,11 +611,17 @@ static int git__clone( GIT_ASSERT_ARG(url); GIT_ASSERT_ARG(local_path); - if (_options) - memcpy(&options, _options, sizeof(git_clone_options)); + if (given_opts) + memcpy(&options, given_opts, sizeof(git_clone_options)); GIT_ERROR_CHECK_VERSION(&options, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); + /* enforce some behavior on fetch */ + options.fetch_opts.update_fetchhead = 0; + + if (!options.fetch_opts.depth) + options.fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; + /* Only clone to a new directory or an empty directory */ if (git_fs_path_exists(local_path) && !use_existing && !git_fs_path_is_empty_dir(local_path)) { git_error_set(GIT_ERROR_INVALID, @@ -536,19 +642,17 @@ static int git__clone( return error; if (!(error = create_and_configure_origin(&origin, repo, url, &options))) { - int clone_local = git_clone__should_clone_local(url, options.local); - int link = options.local != GIT_CLONE_LOCAL_NO_LINKS; - - if (clone_local == 1) - error = clone_local_into( - repo, origin, &options.fetch_opts, &options.checkout_opts, - options.checkout_branch, link); - else if (clone_local == 0) - error = clone_into( - repo, origin, &options.fetch_opts, &options.checkout_opts, - options.checkout_branch); + bool clone_local; + + if ((error = git_clone__should_clone_local(&clone_local, url, options.local)) < 0) { + git_remote_free(origin); + return error; + } + + if (clone_local) + error = clone_local_into(repo, origin, &options); else - error = -1; + error = clone_into(repo, origin, &options); git_remote_free(origin); } @@ -573,18 +677,18 @@ int git_clone( git_repository **out, const char *url, const char *local_path, - const git_clone_options *_options) + const git_clone_options *options) { - return git__clone(out, url, local_path, _options, 0); + return clone_repo(out, url, local_path, options, 0); } int git_clone__submodule( git_repository **out, const char *url, const char *local_path, - const git_clone_options *_options) + const git_clone_options *options) { - return git__clone(out, url, local_path, _options, 1); + return clone_repo(out, url, local_path, options, 1); } int git_clone_options_init(git_clone_options *opts, unsigned int version) @@ -600,99 +704,3 @@ int git_clone_init_options(git_clone_options *opts, unsigned int version) return git_clone_options_init(opts, version); } #endif - -static bool can_link(const char *src, const char *dst, int link) -{ -#ifdef GIT_WIN32 - GIT_UNUSED(src); - GIT_UNUSED(dst); - GIT_UNUSED(link); - return false; -#else - - struct stat st_src, st_dst; - - if (!link) - return false; - - if (p_stat(src, &st_src) < 0) - return false; - - if (p_stat(dst, &st_dst) < 0) - return false; - - return st_src.st_dev == st_dst.st_dev; -#endif -} - -static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link) -{ - int error, flags; - git_repository *src; - git_str src_odb = GIT_STR_INIT, dst_odb = GIT_STR_INIT, src_path = GIT_STR_INIT; - git_str reflog_message = GIT_STR_INIT; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(remote); - - if (!git_repository_is_empty(repo)) { - git_error_set(GIT_ERROR_INVALID, "the repository is not empty"); - return -1; - } - - /* - * Let's figure out what path we should use for the source - * repo, if it's not rooted, the path should be relative to - * the repository's worktree/gitdir. - */ - if ((error = git_fs_path_from_url_or_path(&src_path, git_remote_url(remote))) < 0) - return error; - - /* Copy .git/objects/ from the source to the target */ - if ((error = git_repository_open(&src, git_str_cstr(&src_path))) < 0) { - git_str_dispose(&src_path); - return error; - } - - if (git_repository__item_path(&src_odb, src, GIT_REPOSITORY_ITEM_OBJECTS) < 0 || - git_repository__item_path(&dst_odb, repo, GIT_REPOSITORY_ITEM_OBJECTS) < 0) { - error = -1; - goto cleanup; - } - - flags = 0; - if (can_link(git_repository_path(src), git_repository_path(repo), link)) - flags |= GIT_CPDIR_LINK_FILES; - - error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), - flags, GIT_OBJECT_DIR_MODE); - - /* - * can_link() doesn't catch all variations, so if we hit an - * error and did want to link, let's try again without trying - * to link. - */ - if (error < 0 && link) { - flags &= ~GIT_CPDIR_LINK_FILES; - error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), - flags, GIT_OBJECT_DIR_MODE); - } - - if (error < 0) - goto cleanup; - - git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); - - if ((error = git_remote_fetch(remote, NULL, fetch_opts, git_str_cstr(&reflog_message))) != 0) - goto cleanup; - - error = checkout_branch(repo, remote, co_opts, branch, git_str_cstr(&reflog_message)); - -cleanup: - git_str_dispose(&reflog_message); - git_str_dispose(&src_path); - git_str_dispose(&src_odb); - git_str_dispose(&dst_odb); - git_repository_free(src); - return error; -} diff --git a/src/libgit2/clone.h b/src/libgit2/clone.h index 7d73cabd53c..fde796f91bd 100644 --- a/src/libgit2/clone.h +++ b/src/libgit2/clone.h @@ -15,6 +15,9 @@ extern int git_clone__submodule(git_repository **out, const char *url, const char *local_path, const git_clone_options *_options); -extern int git_clone__should_clone_local(const char *url, git_clone_local_t local); +extern int git_clone__should_clone_local( + bool *out, + const char *url, + git_clone_local_t local); #endif diff --git a/tests/libgit2/clone/local.c b/tests/libgit2/clone/local.c index d35fe86b27e..a15e4581705 100644 --- a/tests/libgit2/clone/local.c +++ b/tests/libgit2/clone/local.c @@ -54,41 +54,87 @@ static int unc_path(git_str *buf, const char *host, const char *path) void test_clone_local__should_clone_local(void) { git_str buf = GIT_STR_INIT; + bool local; /* we use a fixture path because it needs to exist for us to want to clone */ const char *path = cl_fixture("testrepo.git"); + /* empty string */ cl_git_pass(file_url(&buf, "", path)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO)); - cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL)); - cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL)); + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_AUTO)); + cl_assert_equal_i(false, local); + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_AUTO)); + cl_assert_equal_i(false, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL)); + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_NO_LOCAL)); + cl_assert_equal_i(false, local); + + /* localhost is special */ cl_git_pass(file_url(&buf, "localhost", path)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO)); - cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL)); - cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL)); + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_AUTO)); + cl_assert_equal_i(false, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL)); + cl_assert_equal_i(true, local); + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_NO_LOCAL)); + cl_assert_equal_i(false, local); + + /* a remote host */ cl_git_pass(file_url(&buf, "other-host.mycompany.com", path)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL)); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_AUTO)); + cl_assert_equal_i(false, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL)); + cl_assert_equal_i(false, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); + cl_assert_equal_i(false, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_NO_LOCAL)); + cl_assert_equal_i(false, local); /* Ensure that file:/// urls are percent decoded: .git == %2e%67%69%74 */ cl_git_pass(file_url(&buf, "", path)); git_str_shorten(&buf, 4); cl_git_pass(git_str_puts(&buf, "%2e%67%69%74")); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_AUTO)); - cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL)); - cl_assert_equal_i(1, git_clone__should_clone_local(buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); - cl_assert_equal_i(0, git_clone__should_clone_local(buf.ptr, GIT_CLONE_NO_LOCAL)); - - cl_assert_equal_i(1, git_clone__should_clone_local(path, GIT_CLONE_LOCAL_AUTO)); - cl_assert_equal_i(1, git_clone__should_clone_local(path, GIT_CLONE_LOCAL)); - cl_assert_equal_i(1, git_clone__should_clone_local(path, GIT_CLONE_LOCAL_NO_LINKS)); - cl_assert_equal_i(0, git_clone__should_clone_local(path, GIT_CLONE_NO_LOCAL)); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_AUTO)); + cl_assert_equal_i(false, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL)); + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_LOCAL_NO_LINKS)); + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, buf.ptr, GIT_CLONE_NO_LOCAL)); + cl_assert_equal_i(false, local); + + /* a local path on disk */ + cl_git_pass(git_clone__should_clone_local(&local, path, GIT_CLONE_LOCAL_AUTO)); + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, path, GIT_CLONE_LOCAL)); + + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, path, GIT_CLONE_LOCAL_NO_LINKS)); + cl_assert_equal_i(true, local); + + cl_git_pass(git_clone__should_clone_local(&local, path, GIT_CLONE_NO_LOCAL)); + cl_assert_equal_i(false, local); git_str_dispose(&buf); } From c1b2b25ebc9602b94592a0beecbdbeb002b0263e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 19 Oct 2024 23:42:26 +0100 Subject: [PATCH 661/816] remote: add update_refs callback Add an `update_refs` callback that includes the refspec; `update_tips` is retained for backward compatibility. --- examples/fetch.c | 12 ++-- include/git2/remote.h | 35 +++++++++-- src/libgit2/push.c | 23 +++++-- src/libgit2/remote.c | 53 +++++++++++++---- tests/libgit2/network/fetchlocal.c | 96 +++++++++++++++++++++++++++--- tests/libgit2/online/clone.c | 6 +- tests/libgit2/online/fetch.c | 14 +++-- tests/libgit2/online/push_util.c | 4 +- tests/libgit2/online/push_util.h | 4 +- tests/libgit2/submodule/update.c | 15 ++--- 10 files changed, 212 insertions(+), 50 deletions(-) diff --git a/examples/fetch.c b/examples/fetch.c index bbd882cfb59..a8b3527a8cb 100644 --- a/examples/fetch.c +++ b/examples/fetch.c @@ -13,20 +13,24 @@ static int progress_cb(const char *str, int len, void *data) * updated. The message we output depends on whether it's a new one or * an update. */ -static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) +static int update_cb(const char *refname, const git_oid *a, const git_oid *b, git_refspec *spec, void *data) { char a_str[GIT_OID_SHA1_HEXSIZE+1], b_str[GIT_OID_SHA1_HEXSIZE+1]; + git_buf remote_name; (void)data; + if (git_refspec_rtransform(&remote_name, spec, refname) < 0) + return -1; + git_oid_fmt(b_str, b); b_str[GIT_OID_SHA1_HEXSIZE] = '\0'; if (git_oid_is_zero(a)) { - printf("[new] %.20s %s\n", b_str, refname); + printf("[new] %.20s %s -> %s\n", b_str, remote_name.ptr, refname); } else { git_oid_fmt(a_str, a); a_str[GIT_OID_SHA1_HEXSIZE] = '\0'; - printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname); + printf("[updated] %.10s..%.10s %s -> %s\n", a_str, b_str, remote_name.ptr, refname); } return 0; @@ -72,7 +76,7 @@ int lg2_fetch(git_repository *repo, int argc, char **argv) goto on_error; /* Set up the callbacks (only update_tips for now) */ - fetch_opts.callbacks.update_tips = &update_cb; + fetch_opts.callbacks.update_refs = &update_cb; fetch_opts.callbacks.sideband_progress = &progress_cb; fetch_opts.callbacks.transfer_progress = transfer_progress_cb; fetch_opts.callbacks.credentials = cred_acquire_cb; diff --git a/include/git2/remote.h b/include/git2/remote.h index 5505f6c358d..662fc935243 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -83,7 +83,7 @@ typedef enum { /* Write the fetch results to FETCH_HEAD. */ GIT_REMOTE_UPDATE_FETCHHEAD = (1 << 0), - /* Report unchanged tips in the update_tips callback. */ + /* Report unchanged tips in the update_refs callback. */ GIT_REMOTE_UPDATE_REPORT_UNCHANGED = (1 << 1) } git_remote_update_flags; @@ -568,7 +568,8 @@ struct git_remote_callbacks { * Completion is called when different parts of the download * process are done (currently unused). */ - int GIT_CALLBACK(completion)(git_remote_completion_t type, void *data); + int GIT_CALLBACK(completion)(git_remote_completion_t type, + void *data); /** * This will be called if the remote host requires @@ -594,11 +595,22 @@ struct git_remote_callbacks { */ git_indexer_progress_cb transfer_progress; +#ifdef GIT_DEPRECATE_HARD + void *reserved_update_tips; +#else /** - * Each time a reference is updated locally, this function - * will be called with information about it. + * Deprecated callback for reference updates, callers should + * set `update_refs` instead. This is retained for backward + * compatibility; if you specify both `update_refs` and + * `update_tips`, then only the `update_refs` function will + * be called. + * + * @deprecated the `update_refs` callback in this structure + * should be preferred */ - int GIT_CALLBACK(update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data); + int GIT_CALLBACK(update_tips)(const char *refname, + const git_oid *a, const git_oid *b, void *data); +#endif /** * Function to call with progress information during pack @@ -655,6 +667,19 @@ struct git_remote_callbacks { */ git_url_resolve_cb resolve_url; #endif + + /** + * Each time a reference is updated locally, this function + * will be called with information about it. This should be + * preferred over the `update_tips` callback in this + * structure. + */ + int GIT_CALLBACK(update_refs)( + const char *refname, + const git_oid *a, + const git_oid *b, + git_refspec *spec, + void *data); }; #define GIT_REMOTE_CALLBACKS_VERSION 1 diff --git a/src/libgit2/push.c b/src/libgit2/push.c index 882092039f9..b0e84173c74 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -221,12 +221,25 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks) fire_callback = 0; } - if (fire_callback && callbacks && callbacks->update_tips) { - error = callbacks->update_tips(git_str_cstr(&remote_ref_name), - &push_spec->roid, &push_spec->loid, callbacks->payload); + if (!fire_callback || !callbacks) + continue; - if (error < 0) - goto on_error; + if (callbacks->update_refs) + error = callbacks->update_refs( + git_str_cstr(&remote_ref_name), + &push_spec->roid, &push_spec->loid, + &push_spec->refspec, callbacks->payload); +#ifndef GIT_DEPRECATE_HARD + else if (callbacks->update_tips) + error = callbacks->update_tips( + git_str_cstr(&remote_ref_name), + &push_spec->roid, &push_spec->loid, + callbacks->payload); +#endif + + if (error < 0) { + git_error_set_after_callback_function(error, "git_remote_push"); + goto on_error; } } diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 070b7df0665..5e59ce894c2 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1724,14 +1724,23 @@ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks) git_oid_cpy(&id, git_reference_target(ref)); error = git_reference_delete(ref); git_reference_free(ref); + if (error < 0) goto cleanup; - if (callbacks && callbacks->update_tips) - error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload); + if (callbacks && callbacks->update_refs) + error = callbacks->update_refs(refname, &id, + &zero_id, NULL, callbacks->payload); +#ifndef GIT_DEPRECATE_HARD + else if (callbacks && callbacks->update_tips) + error = callbacks->update_tips(refname, &id, + &zero_id, callbacks->payload); +#endif - if (error < 0) + if (error < 0) { + git_error_set_after_callback_function(error, "git_remote_fetch"); goto cleanup; + } } cleanup: @@ -1744,6 +1753,7 @@ static int update_ref( const git_remote *remote, const char *ref_name, git_oid *id, + git_refspec *spec, const char *msg, const git_remote_callbacks *callbacks) { @@ -1772,9 +1782,19 @@ static int update_ref( if (error < 0) return error; - if (callbacks && callbacks->update_tips && - (error = callbacks->update_tips(ref_name, &old_id, id, callbacks->payload)) < 0) + if (callbacks && callbacks->update_refs) + error = callbacks->update_refs(ref_name, &old_id, + id, spec, callbacks->payload); +#ifndef GIT_DEPRECATE_HARD + else if (callbacks && callbacks->update_tips) + error = callbacks->update_tips(ref_name, &old_id, + id, callbacks->payload); +#endif + + if (error < 0) { + git_error_set_after_callback_function(error, "git_remote_fetch"); return error; + } return 0; } @@ -1880,9 +1900,20 @@ static int update_one_tip( } } - if (callbacks && callbacks->update_tips != NULL && - (updated || (update_flags & GIT_REMOTE_UPDATE_REPORT_UNCHANGED)) && - (error = callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload)) < 0) + if (!callbacks || + (!updated && (update_flags & GIT_REMOTE_UPDATE_REPORT_UNCHANGED) == 0)) + goto done; + + if (callbacks && callbacks->update_refs) + error = callbacks->update_refs(refname.ptr, &old, + &head->oid, spec, callbacks->payload); +#ifndef GIT_DEPRECATE_HARD + else if (callbacks && callbacks->update_tips) + error = callbacks->update_tips(refname.ptr, &old, + &head->oid, callbacks->payload); +#endif + + if (error < 0) git_error_set_after_callback_function(error, "git_remote_fetch"); done: @@ -1932,7 +1963,7 @@ static int update_tips_for_spec( goto on_error; if (spec->dst && - (error = update_ref(remote, spec->dst, &id, log_message, callbacks)) < 0) + (error = update_ref(remote, spec->dst, &id, spec, log_message, callbacks)) < 0) goto on_error; git_oid_cpy(&oid_head.oid, &id); @@ -2044,7 +2075,7 @@ static int opportunistic_updates( git_str_clear(&refname); if ((error = git_refspec__transform(&refname, spec, head->name)) < 0 || - (error = update_ref(remote, refname.ptr, &head->oid, msg, callbacks)) < 0) + (error = update_ref(remote, refname.ptr, &head->oid, spec, msg, callbacks)) < 0) goto cleanup; } @@ -2995,7 +3026,7 @@ int git_remote_upload( if (connect_opts.callbacks.push_update_reference) { const int cb_error = git_push_status_foreach(push, connect_opts.callbacks.push_update_reference, connect_opts.callbacks.payload); - if (!error) + if (!error) error = cb_error; } diff --git a/tests/libgit2/network/fetchlocal.c b/tests/libgit2/network/fetchlocal.c index dc37c38ab6b..fef7ed5288a 100644 --- a/tests/libgit2/network/fetchlocal.c +++ b/tests/libgit2/network/fetchlocal.c @@ -108,14 +108,15 @@ void test_network_fetchlocal__prune(void) git_repository_free(repo); } -static int update_tips_fail_on_call(const char *ref, const git_oid *old, const git_oid *new, void *data) +static int update_refs_fail_on_call(const char *ref, const git_oid *old, const git_oid *new, git_refspec *refspec, void *data) { GIT_UNUSED(ref); GIT_UNUSED(old); GIT_UNUSED(new); + GIT_UNUSED(refspec); GIT_UNUSED(data); - cl_fail("update tips called"); + cl_fail("update refs called"); return 0; } @@ -175,7 +176,7 @@ void test_network_fetchlocal__prune_overlapping(void) git_remote_free(origin); cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); - options.callbacks.update_tips = update_tips_fail_on_call; + options.callbacks.update_refs = update_refs_fail_on_call; cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); assert_ref_exists(repo, "refs/remotes/origin/master"); @@ -190,7 +191,7 @@ void test_network_fetchlocal__prune_overlapping(void) git_remote_free(origin); cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); - options.callbacks.update_tips = update_tips_fail_on_call; + options.callbacks.update_refs = update_refs_fail_on_call; cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); git_config_free(config); @@ -510,20 +511,21 @@ void test_network_fetchlocal__prune_load_fetch_prune_config(void) git_repository_free(repo); } -static int update_tips_error(const char *ref, const git_oid *old, const git_oid *new, void *data) +static int update_refs_error(const char *ref, const git_oid *old, const git_oid *new, git_refspec *refspec, void *data) { int *callcount = (int *) data; GIT_UNUSED(ref); GIT_UNUSED(old); GIT_UNUSED(new); + GIT_UNUSED(refspec); (*callcount)++; return -1; } -void test_network_fetchlocal__update_tips_error_is_propagated(void) +void test_network_fetchlocal__update_refs_error_is_propagated(void) { git_repository *repo; git_reference_iterator *iterator; @@ -537,7 +539,7 @@ void test_network_fetchlocal__update_tips_error_is_propagated(void) cl_git_pass(git_remote_create_with_fetchspec(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"), "+refs/heads/*:refs/remotes/update-tips/*")); - options.callbacks.update_tips = update_tips_error; + options.callbacks.update_refs = update_refs_error; options.callbacks.payload = &callcount; cl_git_fail(git_remote_fetch(remote, NULL, &options, NULL)); @@ -550,3 +552,83 @@ void test_network_fetchlocal__update_tips_error_is_propagated(void) git_remote_free(remote); git_repository_free(repo); } + +#ifndef GIT_DEPRECATE_HARD +static int update_tips(const char *ref, const git_oid *old, const git_oid *new, void *data) +{ + int *called = (int *) data; + + GIT_UNUSED(ref); + GIT_UNUSED(old); + GIT_UNUSED(new); + + (*called) += 1; + + return 0; +} + +static int update_refs(const char *ref, const git_oid *old, const git_oid *new, git_refspec *spec, void *data) +{ + int *called = (int *) data; + + GIT_UNUSED(ref); + GIT_UNUSED(old); + GIT_UNUSED(new); + GIT_UNUSED(spec); + + (*called) += 0x10000; + + return 0; +} +#endif + +void test_network_fetchlocal__update_tips_backcompat(void) +{ +#ifndef GIT_DEPRECATE_HARD + git_repository *repo; + git_remote *remote; + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + int callcount = 0; + + cl_git_pass(git_repository_init(&repo, "foo.git", true)); + cl_set_cleanup(cleanup_local_repo, "foo.git"); + + cl_git_pass(git_remote_create_with_fetchspec(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"), "+refs/heads/*:refs/remotes/update-tips/*")); + + options.callbacks.update_tips = update_tips; + options.callbacks.payload = &callcount; + + cl_git_pass(git_remote_fetch(remote, NULL, &options, NULL)); + cl_assert_equal_i(0, (callcount & 0xffff0000)); + cl_assert((callcount & 0x0000ffff) > 0); + + git_remote_free(remote); + git_repository_free(repo); +#endif +} + +void test_network_fetchlocal__update_refs_is_preferred(void) +{ +#ifndef GIT_DEPRECATE_HARD + git_repository *repo; + git_remote *remote; + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + int callcount = 0; + + cl_git_pass(git_repository_init(&repo, "foo.git", true)); + cl_set_cleanup(cleanup_local_repo, "foo.git"); + + cl_git_pass(git_remote_create_with_fetchspec(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"), "+refs/heads/*:refs/remotes/update-tips/*")); + + options.callbacks.update_tips = update_tips; + options.callbacks.update_refs = update_refs; + options.callbacks.payload = &callcount; + + cl_git_pass(git_remote_fetch(remote, NULL, &options, NULL)); + cl_assert_equal_i(0, (callcount & 0x0000ffff)); + cl_assert((callcount & 0xffff0000) > 0); + + git_remote_free(remote); + git_repository_free(repo); +#endif +} diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 207dd839172..e9ed2eeb93c 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -319,10 +319,10 @@ void test_online_clone__clone_mirror(void) cl_fixture_cleanup("./foo.git"); } -static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *payload) +static int update_refs(const char *refname, const git_oid *a, const git_oid *b, git_refspec *spec, void *payload) { int *callcount = (int*)payload; - GIT_UNUSED(refname); GIT_UNUSED(a); GIT_UNUSED(b); + GIT_UNUSED(refname); GIT_UNUSED(a); GIT_UNUSED(b); GIT_UNUSED(spec); *callcount = *callcount + 1; return 0; } @@ -331,7 +331,7 @@ void test_online_clone__custom_remote_callbacks(void) { int callcount = 0; - g_options.fetch_opts.callbacks.update_tips = update_tips; + g_options.fetch_opts.callbacks.update_refs = update_refs; g_options.fetch_opts.callbacks.payload = &callcount; cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); diff --git a/tests/libgit2/online/fetch.c b/tests/libgit2/online/fetch.c index 08a14c6317d..75ec0cde5d4 100644 --- a/tests/libgit2/online/fetch.c +++ b/tests/libgit2/online/fetch.c @@ -39,9 +39,13 @@ void test_online_fetch__cleanup(void) git__free(_remote_redirect_subsequent); } -static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *data) +static int update_refs(const char *refname, const git_oid *a, const git_oid *b, git_refspec *spec, void *data) { - GIT_UNUSED(refname); GIT_UNUSED(a); GIT_UNUSED(b); GIT_UNUSED(data); + GIT_UNUSED(refname); + GIT_UNUSED(a); + GIT_UNUSED(b); + GIT_UNUSED(spec); + GIT_UNUSED(data); ++counter; @@ -62,7 +66,7 @@ static void do_fetch(const char *url, git_remote_autotag_option_t flag, int n) size_t bytes_received = 0; options.callbacks.transfer_progress = progress; - options.callbacks.update_tips = update_tips; + options.callbacks.update_refs = update_refs; options.callbacks.payload = &bytes_received; options.download_tags = flag; counter = 0; @@ -163,7 +167,7 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date options.callbacks.transfer_progress = &transferProgressCallback; options.callbacks.payload = &invoked; - options.callbacks.update_tips = update_tips; + options.callbacks.update_refs = update_refs; cl_git_pass(git_remote_download(remote, NULL, &options)); cl_assert_equal_i(false, invoked); @@ -201,7 +205,7 @@ void test_online_fetch__report_unchanged_tips(void) options.callbacks.transfer_progress = &transferProgressCallback; options.callbacks.payload = &invoked; - options.callbacks.update_tips = update_tips; + options.callbacks.update_refs = update_refs; cl_git_pass(git_remote_download(remote, NULL, &options)); cl_assert_equal_i(false, invoked); diff --git a/tests/libgit2/online/push_util.c b/tests/libgit2/online/push_util.c index 372eec8aab2..88651672d0a 100644 --- a/tests/libgit2/online/push_util.c +++ b/tests/libgit2/online/push_util.c @@ -35,11 +35,13 @@ void record_callbacks_data_clear(record_callbacks_data *data) data->transfer_progress_calls = 0; } -int record_update_tips_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) +int record_update_refs_cb(const char *refname, const git_oid *a, const git_oid *b, git_refspec *spec, void *data) { updated_tip *t; record_callbacks_data *record_data = (record_callbacks_data *)data; + GIT_UNUSED(spec); + cl_assert(t = git__calloc(1, sizeof(*t))); cl_assert(t->name = git__strdup(refname)); diff --git a/tests/libgit2/online/push_util.h b/tests/libgit2/online/push_util.h index 5f669feaf0c..07b46bf4454 100644 --- a/tests/libgit2/online/push_util.h +++ b/tests/libgit2/online/push_util.h @@ -12,7 +12,7 @@ extern const git_oid OID_ZERO; * @param data pointer to a record_callbacks_data instance */ #define RECORD_CALLBACKS_INIT(data) \ - { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, NULL, data, NULL } + { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, data, NULL, record_update_refs_cb } typedef struct { char *name; @@ -50,7 +50,7 @@ void record_callbacks_data_clear(record_callbacks_data *data); * * @param data (git_vector *) of updated_tip instances */ -int record_update_tips_cb(const char *refname, const git_oid *a, const git_oid *b, void *data); +int record_update_refs_cb(const char *refname, const git_oid *a, const git_oid *b, git_refspec *spec, void *data); /** * Create a set of refspecs that deletes each of the inputs diff --git a/tests/libgit2/submodule/update.c b/tests/libgit2/submodule/update.c index 052a4a1fedd..674d1a4fe29 100644 --- a/tests/libgit2/submodule/update.c +++ b/tests/libgit2/submodule/update.c @@ -30,7 +30,7 @@ void test_submodule_update__uninitialized_submodule_no_init(void) } struct update_submodule_cb_payload { - int update_tips_called; + int update_refs_called; int checkout_progress_called; int checkout_notify_called; }; @@ -71,15 +71,16 @@ static int checkout_notify_cb( return 0; } -static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *data) +static int update_refs(const char *refname, const git_oid *a, const git_oid *b, git_refspec *spec, void *data) { struct update_submodule_cb_payload *update_payload = data; GIT_UNUSED(refname); GIT_UNUSED(a); GIT_UNUSED(b); + GIT_UNUSED(spec); - update_payload->update_tips_called = 1; + update_payload->update_refs_called = 1; return 1; } @@ -96,7 +97,7 @@ void test_submodule_update__update_submodule(void) update_options.checkout_opts.progress_cb = checkout_progress_cb; update_options.checkout_opts.progress_payload = &update_payload; - update_options.fetch_opts.callbacks.update_tips = update_tips; + update_options.fetch_opts.callbacks.update_refs = update_refs; update_options.fetch_opts.callbacks.payload = &update_payload; /* get the submodule */ @@ -126,7 +127,7 @@ void test_submodule_update__update_submodule(void) /* verify that the expected callbacks have been called. */ cl_assert_equal_i(1, update_payload.checkout_progress_called); - cl_assert_equal_i(1, update_payload.update_tips_called); + cl_assert_equal_i(1, update_payload.update_refs_called); git_submodule_free(sm); } @@ -143,7 +144,7 @@ void test_submodule_update__update_submodule_with_path(void) update_options.checkout_opts.progress_cb = checkout_progress_cb; update_options.checkout_opts.progress_payload = &update_payload; - update_options.fetch_opts.callbacks.update_tips = update_tips; + update_options.fetch_opts.callbacks.update_refs = update_refs; update_options.fetch_opts.callbacks.payload = &update_payload; /* get the submodule */ @@ -173,7 +174,7 @@ void test_submodule_update__update_submodule_with_path(void) /* verify that the expected callbacks have been called. */ cl_assert_equal_i(1, update_payload.checkout_progress_called); - cl_assert_equal_i(1, update_payload.update_tips_called); + cl_assert_equal_i(1, update_payload.update_refs_called); git_submodule_free(sm); } From 97734321e69ba0ca2794ac4ec6e1fdcdc09f8139 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 20 Oct 2024 00:43:45 +0100 Subject: [PATCH 662/816] cmake: set Python policy to avoid warning cmake warns us that we are using a deprecated python module; explicitly accept that deprecation until they remove it entirely. --- tests/libgit2/CMakeLists.txt | 4 ++++ tests/util/CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/libgit2/CMakeLists.txt b/tests/libgit2/CMakeLists.txt index 1eb109fb597..fb0958eeb9f 100644 --- a/tests/libgit2/CMakeLists.txt +++ b/tests/libgit2/CMakeLists.txt @@ -1,5 +1,9 @@ # tests: the unit and integration tests for libgit2 +if(NOT "${CMAKE_VERSION}" VERSION_LESS 3.27) + cmake_policy(SET CMP0148 OLD) +endif() + set(Python_ADDITIONAL_VERSIONS 3 2.7) find_package(PythonInterp) diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index 1b5799495a0..3c32071fb1a 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -1,5 +1,9 @@ # util: the unit tests for libgit2's utility library +if(NOT "${CMAKE_VERSION}" VERSION_LESS 3.27) + cmake_policy(SET CMP0148 OLD) +endif() + set(Python_ADDITIONAL_VERSIONS 3 2.7) find_package(PythonInterp) From 500796a3586ec0f1e903313436d9f08a83400f81 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 20 Oct 2024 09:49:45 +0100 Subject: [PATCH 663/816] ci: don't run Windows SHA256 gitdaemon tests The Windows SHA256 gitdaemon seems to crash; remove from CI while we troubleshoot. --- .github/workflows/experimental.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml index 60baeb3367a..07442bddecb 100644 --- a/.github/workflows/experimental.yml +++ b/.github/workflows/experimental.yml @@ -55,6 +55,8 @@ jobs: CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + # TODO: this is a temporary removal + SKIP_GITDAEMON_TESTS: true fail-fast: false env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} From 0e08b58aede475f439cad34ca028ad73f924d0c8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 09:47:53 +0100 Subject: [PATCH 664/816] ci: don't run Windows SHA256 gitdaemon tests --- .github/workflows/nightly.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 81db85ac410..e647aaae9e7 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -373,6 +373,8 @@ jobs: CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + # TODO: this is a temporary removal + SKIP_GITDAEMON_TESTS: true - name: "Linux (SHA256, Xenial, Clang, OpenSSL-FIPS)" id: linux-sha256-fips container: From e1d44d9834168c0d1cf694bd3f3a7cdff67d8c8d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 14:53:20 +0100 Subject: [PATCH 665/816] cli: optionally show hidden options in usage Callers may wish to show all the options, even hidden ones, when showing usage. In particular, showing generic help for the CLI should show global options (those that are generally "hidden"). But showing help for a particular command should keep them hidden. Instrument a mechanism to deal with this. --- src/cli/cmd_blame.c | 2 +- src/cli/cmd_cat_file.c | 2 +- src/cli/cmd_clone.c | 2 +- src/cli/cmd_config.c | 2 +- src/cli/cmd_hash_object.c | 2 +- src/cli/cmd_help.c | 4 ++-- src/cli/cmd_index_pack.c | 2 +- src/cli/main.c | 2 +- src/cli/opt_usage.c | 38 +++++++++++++++++++++++++++++--------- src/cli/opt_usage.h | 7 ++++++- 10 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/cli/cmd_blame.c b/src/cli/cmd_blame.c index 3e2f5744ca9..6b720f3502b 100644 --- a/src/cli/cmd_blame.c +++ b/src/cli/cmd_blame.c @@ -40,7 +40,7 @@ static const cli_opt_spec opts[] = { static void print_help(void) { - cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); printf("\n"); printf("Show the origin of each line of a file.\n"); diff --git a/src/cli/cmd_cat_file.c b/src/cli/cmd_cat_file.c index 90ee6033e8c..4d648d77557 100644 --- a/src/cli/cmd_cat_file.c +++ b/src/cli/cmd_cat_file.c @@ -43,7 +43,7 @@ static const cli_opt_spec opts[] = { static void print_help(void) { - cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); printf("\n"); printf("Display the content for the given object in the repository.\n"); diff --git a/src/cli/cmd_clone.c b/src/cli/cmd_clone.c index 7d9736fc72a..afa71eee1f8 100644 --- a/src/cli/cmd_clone.c +++ b/src/cli/cmd_clone.c @@ -46,7 +46,7 @@ static const cli_opt_spec opts[] = { static void print_help(void) { - cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); printf("\n"); printf("Clone a repository into a new directory.\n"); diff --git a/src/cli/cmd_config.c b/src/cli/cmd_config.c index 6b9d373cee6..2d9ec93a20a 100644 --- a/src/cli/cmd_config.c +++ b/src/cli/cmd_config.c @@ -68,7 +68,7 @@ static const cli_opt_spec opts[] = { static void print_help(void) { - cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); printf("\n"); printf("Query and set configuration options.\n"); diff --git a/src/cli/cmd_hash_object.c b/src/cli/cmd_hash_object.c index 741debbeb2f..1eee001f7ac 100644 --- a/src/cli/cmd_hash_object.c +++ b/src/cli/cmd_hash_object.c @@ -36,7 +36,7 @@ static const cli_opt_spec opts[] = { static void print_help(void) { - cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); printf("\n"); printf("Compute the object ID for a given file and optionally write that file\nto the object database.\n"); diff --git a/src/cli/cmd_help.c b/src/cli/cmd_help.c index 5e877e06dbf..ce356597057 100644 --- a/src/cli/cmd_help.c +++ b/src/cli/cmd_help.c @@ -25,7 +25,7 @@ static const cli_opt_spec opts[] = { static int print_help(void) { - cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, CLI_OPT_USAGE_SHOW_HIDDEN); printf("\n"); printf("Display help information about %s. If a command is specified, help\n", PROGRAM_NAME); @@ -39,7 +39,7 @@ static int print_commands(void) { const cli_cmd_spec *cmd; - cli_opt_usage_fprint(stdout, PROGRAM_NAME, NULL, cli_common_opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, NULL, cli_common_opts, CLI_OPT_USAGE_SHOW_HIDDEN); printf("\n"); printf("These are the %s commands available:\n\n", PROGRAM_NAME); diff --git a/src/cli/cmd_index_pack.c b/src/cli/cmd_index_pack.c index 09685c5d4db..c72dd4dcc0c 100644 --- a/src/cli/cmd_index_pack.c +++ b/src/cli/cmd_index_pack.c @@ -38,7 +38,7 @@ static const cli_opt_spec opts[] = { static void print_help(void) { - cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); printf("\n"); printf("Indexes a packfile and writes the index to disk.\n"); diff --git a/src/cli/main.c b/src/cli/main.c index 715feab8998..b516604819f 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -82,7 +82,7 @@ int main(int argc, char **argv) while (cli_opt_parser_next(&opt, &optparser)) { if (!opt.spec) { cli_opt_status_fprint(stderr, PROGRAM_NAME, &opt); - cli_opt_usage_fprint(stderr, PROGRAM_NAME, NULL, cli_common_opts); + cli_opt_usage_fprint(stderr, PROGRAM_NAME, NULL, cli_common_opts, CLI_OPT_USAGE_SHOW_HIDDEN); ret = CLI_EXIT_USAGE; goto done; } diff --git a/src/cli/opt_usage.c b/src/cli/opt_usage.c index 8374f5151a7..ecb4f146198 100644 --- a/src/cli/opt_usage.c +++ b/src/cli/opt_usage.c @@ -46,7 +46,8 @@ int cli_opt_usage_fprint( FILE *file, const char *command, const char *subcommand, - const cli_opt_spec specs[]) + const cli_opt_spec specs[], + unsigned int print_flags) { git_str usage = GIT_BUF_INIT, opt = GIT_BUF_INIT; const cli_opt_spec *spec; @@ -73,7 +74,8 @@ int cli_opt_usage_fprint( next_choice = !!((spec + 1)->usage & CLI_OPT_USAGE_CHOICE); - if (spec->usage & CLI_OPT_USAGE_HIDDEN) + if ((spec->usage & CLI_OPT_USAGE_HIDDEN) && + !(print_flags & CLI_OPT_USAGE_SHOW_HIDDEN)) continue; if (choice) @@ -140,7 +142,7 @@ int cli_opt_usage_error( const cli_opt *invalid_opt) { cli_opt_status_fprint(stderr, PROGRAM_NAME, invalid_opt); - cli_opt_usage_fprint(stderr, PROGRAM_NAME, subcommand, specs); + cli_opt_usage_fprint(stderr, PROGRAM_NAME, subcommand, specs, 0); return CLI_EXIT_USAGE; } @@ -150,12 +152,19 @@ int cli_opt_help_fprint( { git_str help = GIT_BUF_INIT; const cli_opt_spec *spec; + bool required; int error = 0; /* Display required arguments first */ for (spec = specs; spec->type; ++spec) { - if (! (spec->usage & CLI_OPT_USAGE_REQUIRED) || - (spec->usage & CLI_OPT_USAGE_HIDDEN)) + if ((spec->usage & CLI_OPT_USAGE_HIDDEN) || + (spec->type == CLI_OPT_TYPE_LITERAL)) + continue; + + required = ((spec->usage & CLI_OPT_USAGE_REQUIRED) || + ((spec->usage & CLI_OPT_USAGE_CHOICE) && required)); + + if (!required) continue; git_str_printf(&help, " "); @@ -163,13 +172,22 @@ int cli_opt_help_fprint( if ((error = print_spec_name(&help, spec)) < 0) goto done; - git_str_printf(&help, ": %s\n", spec->help); + if (spec->help) + git_str_printf(&help, ": %s", spec->help); + + git_str_printf(&help, "\n"); } /* Display the remaining arguments */ for (spec = specs; spec->type; ++spec) { - if ((spec->usage & CLI_OPT_USAGE_REQUIRED) || - (spec->usage & CLI_OPT_USAGE_HIDDEN)) + if ((spec->usage & CLI_OPT_USAGE_HIDDEN) || + (spec->type == CLI_OPT_TYPE_LITERAL)) + continue; + + required = ((spec->usage & CLI_OPT_USAGE_REQUIRED) || + ((spec->usage & CLI_OPT_USAGE_CHOICE) && required)); + + if (required) continue; git_str_printf(&help, " "); @@ -177,8 +195,10 @@ int cli_opt_help_fprint( if ((error = print_spec_name(&help, spec)) < 0) goto done; - git_str_printf(&help, ": %s\n", spec->help); + if (spec->help) + git_str_printf(&help, ": %s", spec->help); + git_str_printf(&help, "\n"); } if (git_str_oom(&help) || diff --git a/src/cli/opt_usage.h b/src/cli/opt_usage.h index c752494e1aa..b9b75b84b35 100644 --- a/src/cli/opt_usage.h +++ b/src/cli/opt_usage.h @@ -8,6 +8,10 @@ #ifndef CLI_opt_usage_h__ #define CLI_opt_usage_h__ +typedef enum { + CLI_OPT_USAGE_SHOW_HIDDEN = (1 << 0), +} cli_opt_usage_flags; + /** * Prints usage information to the given file handle. * @@ -21,7 +25,8 @@ int cli_opt_usage_fprint( FILE *file, const char *command, const char *subcommand, - const cli_opt_spec specs[]); + const cli_opt_spec specs[], + unsigned int print_flags); int cli_opt_usage_error( const char *subcommand, From fe66d93b0ecf65c011503c694a1284f76f54a953 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 14:55:13 +0100 Subject: [PATCH 666/816] cli: reorder arguments for help invocation When the `help` command is invoked (because no command was specified) we may need to clean up the arguments, in particular, to avoid passing `--help` (so that the help command isn't confused, and assumes that it's being invoked as `help --help`). --- src/cli/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cli/main.c b/src/cli/main.c index b516604819f..15333a45a08 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -64,6 +64,17 @@ static void reorder_args(char **argv, size_t first) argv[1] = tmp; } +/* + * When invoked without a command, or just with `--help`, we invoke + * the help command; but we want to preserve only arguments that would + * be useful for that. + */ +static void help_args(int *argc, char **argv) +{ + argv[0] = "help"; + *argc = 1; +} + int main(int argc, char **argv) { const cli_cmd_spec *cmd; @@ -103,6 +114,7 @@ int main(int argc, char **argv) } if (!command) { + help_args(&argc, argv); ret = cmd_help(argc, argv); goto done; } From da6b76d89e73a9b3e2aa43cf689ce332326f47bc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 14:57:55 +0100 Subject: [PATCH 667/816] cli: refactor common options Move the common option information to a global place, and reuse them. Common options will be global variables. Specify them as _hidden_ for all commands (the main command will pass the SHOW_HIDDEN flag to the usage printer, so that they're visible). --- src/cli/cmd_blame.c | 3 +-- src/cli/cmd_cat_file.c | 3 +-- src/cli/cmd_clone.c | 4 ++-- src/cli/cmd_config.c | 3 +-- src/cli/cmd_hash_object.c | 3 +-- src/cli/cmd_help.c | 3 +-- src/cli/cmd_index_pack.c | 8 +++----- src/cli/common.h | 36 +++++++++++------------------------- src/cli/main.c | 13 ++++++------- 9 files changed, 27 insertions(+), 49 deletions(-) diff --git a/src/cli/cmd_blame.c b/src/cli/cmd_blame.c index 6b720f3502b..180a948f987 100644 --- a/src/cli/cmd_blame.c +++ b/src/cli/cmd_blame.c @@ -22,7 +22,6 @@ static char *file; static int porcelain, line_porcelain; -static int show_help; static const cli_opt_spec opts[] = { CLI_COMMON_OPT, @@ -254,7 +253,7 @@ int cmd_blame(int argc, char **argv) if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); - if (show_help) { + if (cli_opt__show_help) { print_help(); return 0; } diff --git a/src/cli/cmd_cat_file.c b/src/cli/cmd_cat_file.c index 4d648d77557..95a0240cae8 100644 --- a/src/cli/cmd_cat_file.c +++ b/src/cli/cmd_cat_file.c @@ -19,7 +19,6 @@ typedef enum { DISPLAY_TYPE } display_t; -static int show_help; static int display = DISPLAY_CONTENT; static char *type_name, *object_spec; @@ -147,7 +146,7 @@ int cmd_cat_file(int argc, char **argv) if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); - if (show_help) { + if (cli_opt__show_help) { print_help(); return 0; } diff --git a/src/cli/cmd_clone.c b/src/cli/cmd_clone.c index afa71eee1f8..c18cb28d4e0 100644 --- a/src/cli/cmd_clone.c +++ b/src/cli/cmd_clone.c @@ -19,7 +19,7 @@ #define COMMAND_NAME "clone" static char *branch, *remote_path, *local_path, *depth; -static int show_help, quiet, checkout = 1, bare; +static int quiet, checkout = 1, bare; static bool local_path_exists; static cli_progress progress = CLI_PROGRESS_INIT; @@ -133,7 +133,7 @@ int cmd_clone(int argc, char **argv) if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); - if (show_help) { + if (cli_opt__show_help) { print_help(); return 0; } diff --git a/src/cli/cmd_config.c b/src/cli/cmd_config.c index 2d9ec93a20a..9056e81f0b7 100644 --- a/src/cli/cmd_config.c +++ b/src/cli/cmd_config.c @@ -23,7 +23,6 @@ typedef enum { static action_t action = ACTION_NONE; static int show_origin; static int show_scope; -static int show_help; static int null_separator; static int config_level; static char *config_filename; @@ -180,7 +179,7 @@ int cmd_config(int argc, char **argv) if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); - if (show_help) { + if (cli_opt__show_help) { print_help(); return 0; } diff --git a/src/cli/cmd_hash_object.c b/src/cli/cmd_hash_object.c index 1eee001f7ac..94e7eb91f0d 100644 --- a/src/cli/cmd_hash_object.c +++ b/src/cli/cmd_hash_object.c @@ -13,7 +13,6 @@ #define COMMAND_NAME "hash-object" -static int show_help; static char *type_name; static int write_object, read_stdin, literally; static char **filenames; @@ -103,7 +102,7 @@ int cmd_hash_object(int argc, char **argv) if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); - if (show_help) { + if (cli_opt__show_help) { print_help(); return 0; } diff --git a/src/cli/cmd_help.c b/src/cli/cmd_help.c index ce356597057..c01163d3c89 100644 --- a/src/cli/cmd_help.c +++ b/src/cli/cmd_help.c @@ -13,7 +13,6 @@ #define COMMAND_NAME "help" static char *command; -static int show_help; static const cli_opt_spec opts[] = { CLI_COMMON_OPT, @@ -62,7 +61,7 @@ int cmd_help(int argc, char **argv) return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); /* Show the meta-help */ - if (show_help) + if (cli_opt__show_help) return print_help(); /* We were not asked to show help for a specific command. */ diff --git a/src/cli/cmd_index_pack.c b/src/cli/cmd_index_pack.c index c72dd4dcc0c..b8e9749de6a 100644 --- a/src/cli/cmd_index_pack.c +++ b/src/cli/cmd_index_pack.c @@ -14,14 +14,12 @@ #define BUFFER_SIZE (1024 * 1024) -static int show_help, verbose, read_stdin; +static int verbose, read_stdin; static char *filename; static cli_progress progress = CLI_PROGRESS_INIT; static const cli_opt_spec opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, - "display help about the " COMMAND_NAME " command" }, + CLI_COMMON_OPT, { CLI_OPT_TYPE_SWITCH, "verbose", 'v', &verbose, 1, CLI_OPT_USAGE_DEFAULT, NULL, "display progress output" }, @@ -62,7 +60,7 @@ int cmd_index_pack(int argc, char **argv) if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); - if (show_help) { + if (cli_opt__show_help) { print_help(); return 0; } diff --git a/src/cli/common.h b/src/cli/common.h index 6392ae68580..bf7bc3833af 100644 --- a/src/cli/common.h +++ b/src/cli/common.h @@ -20,15 +20,20 @@ * Common command arguments. */ +extern int cli_opt__show_help; + #define CLI_COMMON_OPT_HELP \ - CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING + CLI_OPT_TYPE_SWITCH, "help", 0, &cli_opt__show_help, 1, \ + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, \ + NULL, "display help information" #define CLI_COMMON_OPT_CONFIG \ - CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ - CLI_OPT_USAGE_HIDDEN + CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ + CLI_OPT_USAGE_HIDDEN, \ + "key=value", "add configuration value" #define CLI_COMMON_OPT_CONFIG_ENV \ - CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ - CLI_OPT_USAGE_HIDDEN + CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ + CLI_OPT_USAGE_HIDDEN, \ + "key=value", "set configuration value to environment variable" #define CLI_COMMON_OPT \ { CLI_COMMON_OPT_HELP }, \ @@ -49,23 +54,4 @@ extern int cli_resolve_path( git_repository *repo, const char *given_path); -/* - * Common command arguments. - */ - -#define CLI_COMMON_OPT_HELP \ - CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ - CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING -#define CLI_COMMON_OPT_CONFIG \ - CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ - CLI_OPT_USAGE_HIDDEN -#define CLI_COMMON_OPT_CONFIG_ENV \ - CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ - CLI_OPT_USAGE_HIDDEN - -#define CLI_COMMON_OPT \ - { CLI_COMMON_OPT_HELP }, \ - { CLI_COMMON_OPT_CONFIG }, \ - { CLI_COMMON_OPT_CONFIG_ENV } - #endif /* CLI_common_h__ */ diff --git a/src/cli/main.c b/src/cli/main.c index 15333a45a08..e63fd96a599 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -10,18 +10,15 @@ #include "common.h" #include "cmd.h" -static int show_help = 0; +int cli_opt__show_help = 0; + static int show_version = 0; static char *command = NULL; static char **args = NULL; const cli_opt_spec cli_common_opts[] = { - { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, - CLI_OPT_USAGE_DEFAULT, NULL, "display help information" }, - { CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, - CLI_OPT_USAGE_DEFAULT, "key=value", "add configuration value" }, - { CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, - CLI_OPT_USAGE_DEFAULT, "key=value", "set configuration value to environment variable" }, + CLI_COMMON_OPT, + { CLI_OPT_TYPE_SWITCH, "version", 0, &show_version, 1, CLI_OPT_USAGE_DEFAULT, NULL, "display the version" }, { CLI_OPT_TYPE_ARG, "command", 0, &command, 0, @@ -71,6 +68,8 @@ static void reorder_args(char **argv, size_t first) */ static void help_args(int *argc, char **argv) { + cli_opt__show_help = 0; + argv[0] = "help"; *argc = 1; } From 3ba218c4d5f3bc9139a42356c70205bb07351982 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 14:59:17 +0100 Subject: [PATCH 668/816] cli: add a --no-pager option (currently a noop) Add a `--no-pager` option for git compatibility. --- src/cli/common.h | 8 +++++++- src/cli/main.c | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cli/common.h b/src/cli/common.h index bf7bc3833af..330f776c91e 100644 --- a/src/cli/common.h +++ b/src/cli/common.h @@ -21,6 +21,7 @@ */ extern int cli_opt__show_help; +extern int cli_opt__use_pager; #define CLI_COMMON_OPT_HELP \ CLI_OPT_TYPE_SWITCH, "help", 0, &cli_opt__show_help, 1, \ @@ -34,11 +35,16 @@ extern int cli_opt__show_help; CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ CLI_OPT_USAGE_HIDDEN, \ "key=value", "set configuration value to environment variable" +#define CLI_COMMON_OPT_NO_PAGER \ + CLI_OPT_TYPE_SWITCH, "no-pager", 0, &cli_opt__use_pager, 0, \ + CLI_OPT_USAGE_HIDDEN, \ + NULL, "don't paginate multi-page output" #define CLI_COMMON_OPT \ { CLI_COMMON_OPT_HELP }, \ { CLI_COMMON_OPT_CONFIG }, \ - { CLI_COMMON_OPT_CONFIG_ENV } + { CLI_COMMON_OPT_CONFIG_ENV }, \ + { CLI_COMMON_OPT_NO_PAGER } typedef struct { char **args; diff --git a/src/cli/main.c b/src/cli/main.c index e63fd96a599..1cc8dd3e20a 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -11,6 +11,7 @@ #include "cmd.h" int cli_opt__show_help = 0; +int cli_opt__use_pager = 1; static int show_version = 0; static char *command = NULL; From fddb0bb15376a33801d2823d8e19884b39ca2a26 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 29 Jun 2024 11:14:32 +0100 Subject: [PATCH 669/816] benchmarks: pass options on beyond -- --- tests/benchmarks/benchmark_helpers.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/benchmarks/benchmark_helpers.sh b/tests/benchmarks/benchmark_helpers.sh index 14dbb43c1c0..939c1a8f027 100644 --- a/tests/benchmarks/benchmark_helpers.sh +++ b/tests/benchmarks/benchmark_helpers.sh @@ -293,6 +293,9 @@ gitbench() { NEXT="prepare" elif [ "${a}" = "--chdir" ]; then NEXT="chdir" + elif [[ "${a}" == "--" ]]; then + shift + break elif [[ "${a}" == "--"* ]]; then echo "unknown argument: \"${a}\"" 1>&2 gitbench_usage 1>&2 From 0dfcb29da2b626882d37944b84b2631bfafca92f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 29 Jun 2024 11:14:48 +0100 Subject: [PATCH 670/816] benchmarks: clone git or kernel repositories Teach the benchmark script how to clone the git or kernel repositories, which is useful to have a larger corpus of test data. If a benchmark script wants to `clone git` or `clone linux`, then this will be done. Callers probably want to specify `BENCHMARK_GIT_REPOSITORY` to a previously cloned local repository so that the script does not download the repository repeatedly. --- tests/benchmarks/benchmark_helpers.sh | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/benchmarks/benchmark_helpers.sh b/tests/benchmarks/benchmark_helpers.sh index 939c1a8f027..c71d71cbf91 100644 --- a/tests/benchmarks/benchmark_helpers.sh +++ b/tests/benchmarks/benchmark_helpers.sh @@ -15,6 +15,11 @@ TEST_CLI="git" JSON= SHOW_OUTPUT= +REPOSITORY_DEFAULTS=$(cat <> "${SANDBOX_DIR}/prepare.sh" << EOF set -e + ${REPOSITORY_DEFAULTS} + SANDBOX_DIR="${SANDBOX_DIR}" RESOURCES_DIR="$(resources_dir)" @@ -218,6 +225,29 @@ create_preparescript() { fi } + clone_repo() { + REPO="\${1}" + + if [ "\${REPO}" = "" ]; then + echo "usage: clone_repo " 1>&2 + exit 1 + fi + + REPO_UPPER=\$(echo "\${1}" | tr '[:lower:]' '[:upper:]') + GIVEN_REPO_URL=\$(eval echo "\\\${BENCHMARK_\${REPO_UPPER}_REPOSITORY}") + DEFAULT_REPO_URL=\$(eval echo "\\\${DEFAULT_\${REPO_UPPER}_REPOSITORY}") + + if [ "\${DEFAULT_REPO_URL}" = "" ]; then + echo "\$0: unknown repository '\${REPO}'" 1>&2 + exit 1 + fi + + REPO_URL="\${GIVEN_REPO_URL:-\${DEFAULT_REPO_URL}}" + + rm -rf "\${SANDBOX_DIR:?}/\${REPO}" + git clone "\${REPO_URL}" "\${SANDBOX_DIR}/\${REPO}" + } + cd "\${SANDBOX_DIR}" EOF From 42bd9df2b463a724616a30b2669a154e367cf798 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 29 Jun 2024 11:35:01 +0100 Subject: [PATCH 671/816] benchmarks: pre-clone git and linux in ci --- .github/workflows/benchmark.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 8b513d94dc2..44b76b90261 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -62,6 +62,11 @@ jobs: run: source/ci/setup-${{ matrix.platform.setup-script }}-benchmark.sh shell: bash if: matrix.platform.setup-script != '' + - name: Clone resource repositories + run: | + mkdir resources + git clone --bare https://github.com/git/git resources/git + git clone --bare https://github.com/torvalds/linux resources/linux - name: Build run: | mkdir build && cd build @@ -69,6 +74,9 @@ jobs: shell: bash - name: Benchmark run: | + export BENCHMARK_GIT_REPOSITORY="$(pwd)/resources/git" + export BENCHMARK_LINUX_REPOSITORY="$(pwd)/resources/linux" + if [[ "$(uname -s)" == MINGW* ]]; then GIT2_CLI="$(cygpath -w $(pwd))\\build\\Release\\git2" else From 03d61cf3219b14bc74e6f3d56d2c103d7e0b756d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 29 Jun 2024 11:37:36 +0100 Subject: [PATCH 672/816] benchmarks: add blame benchmarks --- tests/benchmarks/blame__git_cached | 9 +++++++++ tests/benchmarks/blame__linux_cached | 9 +++++++++ tests/benchmarks/blame__simple_cached | 9 +++++++++ 3 files changed, 27 insertions(+) create mode 100755 tests/benchmarks/blame__git_cached create mode 100755 tests/benchmarks/blame__linux_cached create mode 100755 tests/benchmarks/blame__simple_cached diff --git a/tests/benchmarks/blame__git_cached b/tests/benchmarks/blame__git_cached new file mode 100755 index 00000000000..5a6e2b2748d --- /dev/null +++ b/tests/benchmarks/blame__git_cached @@ -0,0 +1,9 @@ +#!/bin/bash -e + +. "$(dirname "$0")/benchmark_helpers.sh" + +gitbench --prepare "clone_repo git && cd git && git reset --hard v2.45.0" \ + --warmup 5 \ + --chdir "git" \ + -- \ + --no-pager blame "git.c" diff --git a/tests/benchmarks/blame__linux_cached b/tests/benchmarks/blame__linux_cached new file mode 100755 index 00000000000..ff4902ae962 --- /dev/null +++ b/tests/benchmarks/blame__linux_cached @@ -0,0 +1,9 @@ +#!/bin/bash -e + +. "$(dirname "$0")/benchmark_helpers.sh" + +gitbench --prepare "clone_repo linux && cd linux && git reset --hard v6.9" \ + --warmup 5 \ + --chdir "linux" \ + -- \ + --no-pager blame "Makefile" diff --git a/tests/benchmarks/blame__simple_cached b/tests/benchmarks/blame__simple_cached new file mode 100755 index 00000000000..f13e2cb060f --- /dev/null +++ b/tests/benchmarks/blame__simple_cached @@ -0,0 +1,9 @@ +#!/bin/bash -e + +. "$(dirname "$0")/benchmark_helpers.sh" + +gitbench --prepare "sandbox_repo testrepo && cd testrepo && git reset --hard HEAD" \ + --warmup 5 \ + --chdir "testrepo" \ + -- \ + --no-pager blame "branch_file.txt" From d564cc1801e4b9729d2d5ea5237da1fc32c04bb4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 4 Jul 2024 07:15:27 +0100 Subject: [PATCH 673/816] benchmark: don't require a default It will never be a good user experience to clone the git or kernel repos from a remote; don't even have a default. --- tests/benchmarks/benchmark_helpers.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/benchmarks/benchmark_helpers.sh b/tests/benchmarks/benchmark_helpers.sh index c71d71cbf91..2efcf47058a 100644 --- a/tests/benchmarks/benchmark_helpers.sh +++ b/tests/benchmarks/benchmark_helpers.sh @@ -15,11 +15,6 @@ TEST_CLI="git" JSON= SHOW_OUTPUT= -REPOSITORY_DEFAULTS=$(cat <> "${SANDBOX_DIR}/prepare.sh" << EOF set -e - ${REPOSITORY_DEFAULTS} - SANDBOX_DIR="${SANDBOX_DIR}" RESOURCES_DIR="$(resources_dir)" @@ -234,16 +227,13 @@ create_preparescript() { fi REPO_UPPER=\$(echo "\${1}" | tr '[:lower:]' '[:upper:]') - GIVEN_REPO_URL=\$(eval echo "\\\${BENCHMARK_\${REPO_UPPER}_REPOSITORY}") - DEFAULT_REPO_URL=\$(eval echo "\\\${DEFAULT_\${REPO_UPPER}_REPOSITORY}") + REPO_URL=\$(eval echo "\\\${BENCHMARK_\${REPO_UPPER}_REPOSITORY}") - if [ "\${DEFAULT_REPO_URL}" = "" ]; then + if [ "\${REPO_URL}" = "" ]; then echo "\$0: unknown repository '\${REPO}'" 1>&2 exit 1 fi - REPO_URL="\${GIVEN_REPO_URL:-\${DEFAULT_REPO_URL}}" - rm -rf "\${SANDBOX_DIR:?}/\${REPO}" git clone "\${REPO_URL}" "\${SANDBOX_DIR}/\${REPO}" } From 4f40bd9f0964f60558300ccff428f1720a41bf3c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 4 Jul 2024 12:33:32 +0100 Subject: [PATCH 674/816] benchmark: show helpful errors w/o local repo When running without a local test repository, show a helpful error message. --- tests/benchmarks/benchmark_helpers.sh | 27 +++++++++++++++++++++++++++ tests/benchmarks/blame__git_cached | 2 ++ tests/benchmarks/blame__linux_cached | 2 ++ 3 files changed, 31 insertions(+) diff --git a/tests/benchmarks/benchmark_helpers.sh b/tests/benchmarks/benchmark_helpers.sh index 2efcf47058a..dd84b9cee80 100644 --- a/tests/benchmarks/benchmark_helpers.sh +++ b/tests/benchmarks/benchmark_helpers.sh @@ -21,6 +21,9 @@ else OUTPUT_STYLE="auto" fi +HELP_GIT_REMOTE="https://github.com/git/git" +HELP_LINUX_REMOTE="https://github.com/torvalds/linux" + # # parse the arguments to the outer script that's including us; these are arguments that # the `benchmark.sh` passes (or that a user could specify when running an individual test) @@ -384,3 +387,27 @@ gitbench() { hyperfine "${ARGUMENTS[@]}" rm -rf "${SANDBOX_DIR:?}" } + +# helper script to give useful error messages about configuration +needs_repo() { + REPO="${1}" + + if [ "${REPO}" = "" ]; then + echo "usage: needs_repo " 1>&2 + exit 1 + fi + + REPO_UPPER=$(echo "${1}" | tr '[:lower:]' '[:upper:]') + REPO_URL=$(eval echo "\${BENCHMARK_${REPO_UPPER}_REPOSITORY}") + REPO_REMOTE_URL=$(eval echo "\${HELP_${REPO_UPPER}_REMOTE}") + + if [ "${REPO_URL}" = "" ]; then + echo "$0: '${REPO}' repository not configured" 1>&2 + echo "" 1>&2 + echo "This benchmark needs an on-disk '${REPO}' repository. First, clone the" 1>&2 + echo "remote repository ('${REPO_REMOTE_URL}') locally then set," 1>&2 + echo "the 'BENCHMARK_${REPO_UPPER}_REPOSITORY' environment variable to the path that" 1>&2 + echo "contains the repository locally, then run this benchmark again." 1>&2 + exit 1 + fi +} diff --git a/tests/benchmarks/blame__git_cached b/tests/benchmarks/blame__git_cached index 5a6e2b2748d..1664f737b90 100755 --- a/tests/benchmarks/blame__git_cached +++ b/tests/benchmarks/blame__git_cached @@ -2,6 +2,8 @@ . "$(dirname "$0")/benchmark_helpers.sh" +needs_repo git + gitbench --prepare "clone_repo git && cd git && git reset --hard v2.45.0" \ --warmup 5 \ --chdir "git" \ diff --git a/tests/benchmarks/blame__linux_cached b/tests/benchmarks/blame__linux_cached index ff4902ae962..20c5db5bbe5 100755 --- a/tests/benchmarks/blame__linux_cached +++ b/tests/benchmarks/blame__linux_cached @@ -2,6 +2,8 @@ . "$(dirname "$0")/benchmark_helpers.sh" +needs_repo linux + gitbench --prepare "clone_repo linux && cd linux && git reset --hard v6.9" \ --warmup 5 \ --chdir "linux" \ From 90e659d0b950499984ef26fdfd45205a3113bdd8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 10:48:25 +0100 Subject: [PATCH 675/816] ci: only publish benchmarks nightly Allow for workflow_dispatch jobs to run, but don't publish their test results; this is useful for testing workflows themselves. --- .github/workflows/benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 44b76b90261..de12739b954 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -97,7 +97,7 @@ jobs: publish: name: Publish results needs: [ build ] - if: always() && github.repository == 'libgit2/libgit2' + if: always() && github.repository == 'libgit2/libgit2' && github.event_name == 'schedule' runs-on: ubuntu-latest steps: - name: Check out benchmark repository From df3d8a6799ffa61316a3c95815c4e333df3b7179 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 11:02:17 +0100 Subject: [PATCH 676/816] ci: allow inputs to benchmark --- .github/workflows/benchmark.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index de12739b954..cf0afe5f5b2 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -3,6 +3,12 @@ name: Benchmark on: workflow_dispatch: + inputs: + suite: + description: Benchmark suite to run + debug: + type: boolean + description: Debugging output schedule: - cron: '15 4 * * *' @@ -83,8 +89,19 @@ jobs: GIT2_CLI="$(pwd)/build/git2" fi + if [ "${{ github.event.inputs.suite }}" != "" ]; then + SUITE_FLAG="--suite ${{ github.event.inputs.suite }}" + fi + + if [ "${{ github.event.inputs.debug }}" = "true" ]; then + DEBUG_FLAG="--debug" + fi + mkdir benchmark && cd benchmark - ../source/tests/benchmarks/benchmark.sh --baseline-cli "git" --cli "${GIT2_CLI}" --name libgit2 --json benchmarks.json --zip benchmarks.zip + ../source/tests/benchmarks/benchmark.sh \ + ${SUITE_FLAG} ${DEBUG_FLAG} \ + --baseline-cli "git" --cli "${GIT2_CLI}" --name libgit2 \ + --json benchmarks.json --zip benchmarks.zip shell: bash - name: Upload results uses: actions/upload-artifact@v4 From d4222f83215c99fd083904bad482c8817752271a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 16:28:35 +0100 Subject: [PATCH 677/816] ci: don't run blame on torvalds/linux (yet) blame on torvalds/linux is too punishing for our current implementation; don't run it (yet). --- .github/workflows/benchmark.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index cf0afe5f5b2..3fb912d40d0 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -81,7 +81,9 @@ jobs: - name: Benchmark run: | export BENCHMARK_GIT_REPOSITORY="$(pwd)/resources/git" - export BENCHMARK_LINUX_REPOSITORY="$(pwd)/resources/linux" + # avoid linux temporarily; the linux blame benchmarks are simply + # too slow to use + # export BENCHMARK_LINUX_REPOSITORY="$(pwd)/resources/linux" if [[ "$(uname -s)" == MINGW* ]]; then GIT2_CLI="$(cygpath -w $(pwd))\\build\\Release\\git2" From e68d0b4b955cea0a5e9305731eeee693376e90e4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 21 Oct 2024 17:29:52 +0100 Subject: [PATCH 678/816] benchmark: skip (don't fail) needs_repo tests If a test needs a repo that isn't provide it, mark it as skipped and avoid failing the execution. --- tests/benchmarks/benchmark.sh | 14 ++++++++++++-- tests/benchmarks/benchmark_helpers.sh | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/benchmarks/benchmark.sh b/tests/benchmarks/benchmark.sh index 4cb2b2fbfd3..6830064e776 100755 --- a/tests/benchmarks/benchmark.sh +++ b/tests/benchmarks/benchmark.sh @@ -213,9 +213,19 @@ for TEST_PATH in "${BENCHMARK_DIR}"/*; do ERROR_FILE="${OUTPUT_DIR}/${TEST_FILE}.err" FAILED= - ${TEST_PATH} --cli "${TEST_CLI}" --baseline-cli "${BASELINE_CLI}" --json "${JSON_FILE}" ${SHOW_OUTPUT} >"${OUTPUT_FILE}" 2>"${ERROR_FILE}" || FAILED=1 + { + ${TEST_PATH} --cli "${TEST_CLI}" --baseline-cli "${BASELINE_CLI}" --json "${JSON_FILE}" ${SHOW_OUTPUT} >"${OUTPUT_FILE}" 2>"${ERROR_FILE}"; + FAILED=$? + } || true - if [ "${FAILED}" = "1" ]; then + if [ "${FAILED}" = "2" ]; then + if [ "${VERBOSE}" != "1" ]; then + echo "skipped!" + fi + + indent < "${ERROR_FILE}" + continue + elif [ "${FAILED}" != "0" ]; then if [ "${VERBOSE}" != "1" ]; then echo "failed!" fi diff --git a/tests/benchmarks/benchmark_helpers.sh b/tests/benchmarks/benchmark_helpers.sh index dd84b9cee80..5143a01fcfd 100644 --- a/tests/benchmarks/benchmark_helpers.sh +++ b/tests/benchmarks/benchmark_helpers.sh @@ -408,6 +408,6 @@ needs_repo() { echo "remote repository ('${REPO_REMOTE_URL}') locally then set," 1>&2 echo "the 'BENCHMARK_${REPO_UPPER}_REPOSITORY' environment variable to the path that" 1>&2 echo "contains the repository locally, then run this benchmark again." 1>&2 - exit 1 + exit 2 fi } From d1be60bbe8e23aa8a00c67bd73d2209421d65c13 Mon Sep 17 00:00:00 2001 From: Vladyslav Yeremeichuk Date: Mon, 21 Oct 2024 22:42:56 +0300 Subject: [PATCH 679/816] Add the ability to check if a mempack is empty Implement git_mempack_empty, which returns 1 if the mempack is empty and 0 otherwise. --- include/git2/sys/mempack.h | 8 ++++++++ src/libgit2/odb_mempack.c | 11 +++++++++++ tests/libgit2/odb/backend/mempack.c | 15 +++++++++++---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/include/git2/sys/mempack.h b/include/git2/sys/mempack.h index 96bd8a7e86e..f8dedee8255 100644 --- a/include/git2/sys/mempack.h +++ b/include/git2/sys/mempack.h @@ -101,6 +101,14 @@ GIT_EXTERN(int) git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_ba */ GIT_EXTERN(int) git_mempack_reset(git_odb_backend *backend); +/** + * Checks if mempack is empty + * + * @param backend The mempack backend + * @return 1 if the repository is empty, 0 if it isn't + */ +GIT_EXTERN(int) git_mempack_empty(git_odb_backend *backend); + GIT_END_DECL #endif diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c index c6210cec60b..732a30573cb 100644 --- a/src/libgit2/odb_mempack.c +++ b/src/libgit2/odb_mempack.c @@ -209,3 +209,14 @@ int git_mempack_new(git_odb_backend **out) *out = (git_odb_backend *)db; return 0; } + +int git_mempack_empty(git_odb_backend *_backend) +{ + struct memory_packer_db *db = (struct memory_packer_db *)_backend; + GIT_ASSERT_ARG(_backend); + + if (git_odb_mempack_oidmap_size(&db->objects) || db->commits.size) + return 0; + + return 1; +} diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c index c8a86a2ae95..66450a6c53c 100644 --- a/tests/libgit2/odb/backend/mempack.c +++ b/tests/libgit2/odb/backend/mempack.c @@ -8,14 +8,13 @@ static git_odb *_odb; static git_oid _oid; static git_odb_object *_obj; static git_repository *_repo; +static git_odb_backend *_backend; void test_odb_backend_mempack__initialize(void) { - git_odb_backend *backend; - - cl_git_pass(git_mempack_new(&backend)); + cl_git_pass(git_mempack_new(&_backend)); cl_git_pass(git_odb__new(&_odb, NULL)); - cl_git_pass(git_odb_add_backend(_odb, backend, 10)); + cl_git_pass(git_odb_add_backend(_odb, _backend, 10)); cl_git_pass(git_repository__wrap_odb(&_repo, _odb, GIT_OID_SHA1)); } @@ -33,6 +32,14 @@ void test_odb_backend_mempack__write_succeeds(void) cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); } +void test_odb_backend_mempack_empty(void) +{ + const char *data = "data"; + cl_assert_equal_sz(1, git_mempack_empty(_backend)); + cl_git_pass(git_odb_write(&_oid, _odb, data, strlen(data) + 1, GIT_OBJECT_BLOB)); + cl_assert_equal_sz(0, git_mempack_empty(_backend)); +} + void test_odb_backend_mempack__read_of_missing_object_fails(void) { cl_git_pass(git_oid__fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); From 0c675b8c842fa0c7fa0f8733e22d90efc060959a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 10:01:44 +0100 Subject: [PATCH 680/816] cmake: enforce USE_HTTP_PARSER validity When `-DUSE_HTTP_PARSER=...` is specified, ensure that the specified HTTP Parser is valid, do not fallback to builtin. Restore `-DUSE_HTTP_PARSER=system` for backcompatibility. --- CMakeLists.txt | 4 ++-- cmake/{FindHTTPParser.cmake => FindHTTP_Parser.cmake} | 0 cmake/SelectHTTPParser.cmake | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) rename cmake/{FindHTTPParser.cmake => FindHTTP_Parser.cmake} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f99a69c4378..8f524e6a13e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,8 +34,8 @@ option(USE_SSH "Enable SSH support. Can be set to a specific bac option(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON) option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS" ON) option(USE_SHA256 "Enable SHA256. Can be set to HTTPS/Builtin" ON) -option(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) - set(USE_HTTP_PARSER "" CACHE STRING "Specifies the HTTP Parser implementation; either system or builtin.") +option(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) + set(USE_HTTP_PARSER "" CACHE STRING "Specifies the HTTP Parser implementation. One of http-parser, llhttp, or builtin. (Defaults to builtin.)") # set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") set(REGEX_BACKEND "" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") option(USE_BUNDLED_ZLIB "Use the bundled version of zlib. Can be set to one of Bundled(ON)/Chromium. The Chromium option requires a x86_64 processor with SSE4.2 and CLMUL" OFF) diff --git a/cmake/FindHTTPParser.cmake b/cmake/FindHTTP_Parser.cmake similarity index 100% rename from cmake/FindHTTPParser.cmake rename to cmake/FindHTTP_Parser.cmake diff --git a/cmake/SelectHTTPParser.cmake b/cmake/SelectHTTPParser.cmake index 4fc1f6968e6..e547e2d0166 100644 --- a/cmake/SelectHTTPParser.cmake +++ b/cmake/SelectHTTPParser.cmake @@ -1,6 +1,6 @@ # Optional external dependency: http-parser -if(USE_HTTP_PARSER STREQUAL "http-parser") - find_package(HTTPParser) +if(USE_HTTP_PARSER STREQUAL "http-parser" OR USE_HTTP_PARSER STREQUAL "system") + find_package(HTTP_Parser) if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS}) @@ -23,10 +23,12 @@ elseif(USE_HTTP_PARSER STREQUAL "llhttp") else() message(FATAL_ERROR "llhttp support was requested but not found") endif() -else() +elseif(USE_HTTP_PARSER STREQUAL "" OR USE_HTTP_PARSER STREQUAL "builtin") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/llhttp" "${PROJECT_BINARY_DIR}/deps/llhttp") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/llhttp") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") set(GIT_HTTPPARSER_BUILTIN 1) add_feature_info(http-parser ON "using bundled parser") +else() + message(FATAL_ERROR "unknown http-parser: ${USE_HTTP_PARSER}") endif() From 2125e3c64d7a813ec17823871636c4be3579dde8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 10:17:08 +0100 Subject: [PATCH 681/816] cmake: enforce USE_SSH validity Validate the USE_SSH option fits into our valid options; don't assume a default. --- CMakeLists.txt | 2 +- cmake/SelectSSH.cmake | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f524e6a13e..560f82c07c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ option(USE_THREADS "Use threads for parallel processing when possibl option(USE_NSEC "Support nanosecond precision file mtimes and ctimes" ON) # Backend selection -option(USE_SSH "Enable SSH support. Can be set to a specific backend" OFF) + set(USE_SSH "" CACHE STRING "Enables SSH support. One of libssh2, exec, or OFF. (Defaults to OFF.)") option(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON) option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS" ON) option(USE_SHA256 "Enable SHA256. Can be set to HTTPS/Builtin" ON) diff --git a/cmake/SelectSSH.cmake b/cmake/SelectSSH.cmake index 079857f502b..b0d747114da 100644 --- a/cmake/SelectSSH.cmake +++ b/cmake/SelectSSH.cmake @@ -39,6 +39,8 @@ elseif(USE_SSH STREQUAL ON OR USE_SSH STREQUAL "libssh2") set(GIT_SSH 1) set(GIT_SSH_LIBSSH2 1) add_feature_info(SSH ON "using libssh2") -else() +elseif(USE_SSH STREQUAL OFF OR USE_SSH STREQUAL "") add_feature_info(SSH OFF "SSH transport support") +else() + message(FATAL_ERROR "unknown SSH option: ${USE_HTTP_PARSER}") endif() From d1d65787b4b31c958eadf7c58002e1948fd9b3c7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 10:29:44 +0100 Subject: [PATCH 682/816] cmake: enforce USE_HTTPS validity --- CMakeLists.txt | 4 ++-- cmake/SelectHTTPSBackend.cmake | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 560f82c07c8..44a0e1d357a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ option(USE_NSEC "Support nanosecond precision file mtimes and cti # Backend selection set(USE_SSH "" CACHE STRING "Enables SSH support. One of libssh2, exec, or OFF. (Defaults to OFF.)") -option(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON) + set(USE_HTTPS "" CACHE STRING "Enable HTTPS support. One of ON (to autodetect), OFF, or a specific backend: OpenSSL, OpenSSL-FIPS, OpenSSL-Dynamic, mbedTLS, SecureTransport, Schannel, or WinHTTP. (Defaults to ON.)") option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS" ON) option(USE_SHA256 "Enable SHA256. Can be set to HTTPS/Builtin" ON) option(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) @@ -64,7 +64,7 @@ option(ENABLE_WERROR "Enable compilation with -Werror" if(UNIX) # NTLM client requires crypto libraries from the system HTTPS stack - if(NOT USE_HTTPS) + if(USE_HTTPS STREQUAL "OFF") option(USE_NTLMCLIENT "Enable NTLM support on Unix." OFF) else() option(USE_NTLMCLIENT "Enable NTLM support on Unix." ON) diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index 61bc763fce5..0316b3a1c1a 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -8,9 +8,14 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "iOS") find_package(CoreFoundation) endif() +if(USE_HTTPS STREQUAL "") + set(USE_HTTPS ON) +endif() + +sanitizebool(USE_HTTPS) + if(USE_HTTPS) # Auto-select TLS backend - sanitizebool(USE_HTTPS) if(USE_HTTPS STREQUAL ON) if(SECURITY_FOUND) if(SECURITY_HAS_SSLCREATECONTEXT) @@ -136,12 +141,12 @@ if(USE_HTTPS) set(GIT_OPENSSL_DYNAMIC 1) list(APPEND LIBGIT2_SYSTEM_LIBS dl) else() - message(FATAL_ERROR "Asked for backend ${USE_HTTPS} but it wasn't found") + message(FATAL_ERROR "unknown HTTPS backend: ${USE_HTTPS}") endif() set(GIT_HTTPS 1) add_feature_info(HTTPS GIT_HTTPS "using ${USE_HTTPS}") else() set(GIT_HTTPS 0) - add_feature_info(HTTPS NO "") + add_feature_info(HTTPS NO "HTTPS support is disabled") endif() From e536b2c50cc64fb7f7c3a6e100f965672eb85e13 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 10:55:16 +0100 Subject: [PATCH 683/816] cmake: enforce USE_SHA1 and USE_SHA256 validity --- cmake/SelectHashes.cmake | 25 +++++++++++++++---------- src/util/CMakeLists.txt | 4 ++-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 06cfabc3cd0..92ec8d2e23c 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -2,13 +2,12 @@ include(SanitizeBool) -# USE_SHA1=CollisionDetection(ON)/HTTPS/Generic/OFF sanitizebool(USE_SHA1) sanitizebool(USE_SHA256) # sha1 -if(USE_SHA1 STREQUAL ON) +if(USE_SHA1 STREQUAL "" OR USE_SHA1 STREQUAL ON) SET(USE_SHA1 "CollisionDetection") elseif(USE_SHA1 STREQUAL "HTTPS") if(USE_HTTPS STREQUAL "SecureTransport") @@ -20,7 +19,7 @@ elseif(USE_SHA1 STREQUAL "HTTPS") elseif(USE_HTTPS) set(USE_SHA1 ${USE_HTTPS}) else() - set(USE_SHA1 "CollisionDetection") + message(FATAL_ERROR "asked for HTTPS SHA1 backend but HTTPS is not enabled") endif() endif() @@ -41,15 +40,21 @@ elseif(USE_SHA1 STREQUAL "mbedTLS") elseif(USE_SHA1 STREQUAL "Win32") set(GIT_SHA1_WIN32 1) else() - message(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}") + message(FATAL_ERROR "asked for unknown SHA1 backend: ${USE_SHA1}") endif() # sha256 -if(USE_SHA256 STREQUAL ON AND USE_HTTPS) - SET(USE_SHA256 "HTTPS") -elseif(USE_SHA256 STREQUAL ON) - SET(USE_SHA256 "Builtin") +if(USE_SHA256 STREQUAL "" OR USE_SHA256 STREQUAL ON) + if(USE_HTTPS) + SET(USE_SHA256 "HTTPS") + else() + SET(USE_SHA256 "builtin") + endif() +endif() + +if(USE_SHA256 STREQUAL "Builtin") + set(USE_SHA256 "builtin") endif() if(USE_SHA256 STREQUAL "HTTPS") @@ -64,7 +69,7 @@ if(USE_SHA256 STREQUAL "HTTPS") endif() endif() -if(USE_SHA256 STREQUAL "Builtin") +if(USE_SHA256 STREQUAL "builtin") set(GIT_SHA256_BUILTIN 1) elseif(USE_SHA256 STREQUAL "OpenSSL") set(GIT_SHA256_OPENSSL 1) @@ -81,7 +86,7 @@ elseif(USE_SHA256 STREQUAL "mbedTLS") elseif(USE_SHA256 STREQUAL "Win32") set(GIT_SHA256_WIN32 1) else() - message(FATAL_ERROR "Asked for unknown SHA256 backend: ${USE_SHA256}") + message(FATAL_ERROR "asked for unknown SHA256 backend: ${USE_SHA256}") endif() # add library requirements diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index a78a7e4223a..3692dc3d332 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -49,7 +49,7 @@ endif() list(SORT UTIL_SRC_SHA1) -if(USE_SHA256 STREQUAL "Builtin") +if(USE_SHA256 STREQUAL "builtin") file(GLOB UTIL_SRC_SHA256 hash/builtin.* hash/rfc6234/*) elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) @@ -61,7 +61,7 @@ elseif(USE_SHA256 STREQUAL "mbedTLS") elseif(USE_SHA256 STREQUAL "Win32") file(GLOB UTIL_SRC_SHA256 hash/win32.*) else() - message(FATAL_ERROR "Asked for unknown SHA256 backend: ${USE_SHA256}") + message(FATAL_ERROR "asked for unknown SHA256 backend: ${USE_SHA256}") endif() list(SORT UTIL_SRC_SHA256) From d37d6a9f03d38fdcf4018234d5a2fcfe489f38a9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 10:55:22 +0100 Subject: [PATCH 684/816] cmake: better document dependency options --- CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 44a0e1d357a..1a864cb1f4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,14 +30,14 @@ option(USE_THREADS "Use threads for parallel processing when possibl option(USE_NSEC "Support nanosecond precision file mtimes and ctimes" ON) # Backend selection - set(USE_SSH "" CACHE STRING "Enables SSH support. One of libssh2, exec, or OFF. (Defaults to OFF.)") - set(USE_HTTPS "" CACHE STRING "Enable HTTPS support. One of ON (to autodetect), OFF, or a specific backend: OpenSSL, OpenSSL-FIPS, OpenSSL-Dynamic, mbedTLS, SecureTransport, Schannel, or WinHTTP. (Defaults to ON.)") -option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS" ON) -option(USE_SHA256 "Enable SHA256. Can be set to HTTPS/Builtin" ON) -option(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) - set(USE_HTTP_PARSER "" CACHE STRING "Specifies the HTTP Parser implementation. One of http-parser, llhttp, or builtin. (Defaults to builtin.)") + set(USE_SSH "" CACHE STRING "Enables SSH support and optionally selects provider. One of ON, OFF, or a specific provider: libssh2 or exec. (Defaults to OFF.)") + set(USE_HTTPS "" CACHE STRING "Enable HTTPS support and optionally selects the provider. One of ON, OFF, or a specific provider: OpenSSL, OpenSSL-FIPS, OpenSSL-Dynamic, mbedTLS, SecureTransport, Schannel, or WinHTTP. (Defaults to ON.)") + set(USE_SHA1 "" CACHE STRING "Selects SHA1 provider. One of CollisionDetection, HTTPS, or a specific provider. (Defaults to CollisionDetection.)") + set(USE_SHA256 "" CACHE STRING "Selects SHA256 provider. One of Builtin, HTTPS, or a specific provider. (Defaults to HTTPS.)") +option(USE_GSSAPI "Enable SPNEGO authentication using GSSAPI" OFF) + set(USE_HTTP_PARSER "" CACHE STRING "Selects HTTP Parser support: http-parser, llhttp, or builtin. (Defaults to builtin.)") # set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") - set(REGEX_BACKEND "" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") + set(REGEX_BACKEND "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") option(USE_BUNDLED_ZLIB "Use the bundled version of zlib. Can be set to one of Bundled(ON)/Chromium. The Chromium option requires a x86_64 processor with SSE4.2 and CLMUL" OFF) # Debugging options From 22ee5a59a2a738d86400180e82a3fc41c9f7fd6b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 11:12:49 +0100 Subject: [PATCH 685/816] docs: update README for dependency selection --- README.md | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 55b3c536cb0..261bf5c3ece 100644 --- a/README.md +++ b/README.md @@ -265,29 +265,39 @@ Build options: Dependency options: -* `USE_SSH=type`: enables SSH support; `type` can be set to `libssh2` - or `exec` (which will execute an external OpenSSH command) -* `USE_HTTPS=type`: enables HTTPS support; `type` can be set to - `OpenSSL`, `mbedTLS`, `SecureTransport`, `Schannel`, or `WinHTTP`; - the default is `SecureTransport` on macOS, `WinHTTP` on Windows, and - whichever of `OpenSSL` or `mbedTLS` is detected on other platforms. +* `USE_SSH=type`: enables SSH support and optionally selects the provider; + `type` can be set to `libssh2` or `exec` (which will execute an external + OpenSSH command). `ON` implies `libssh2`; defaults to `OFF`. +* `USE_HTTPS=type`: enables HTTPS support and optionally selects the + provider; `type` can be set to `OpenSSL`, `OpenSSL-Dynamic` (to not + link against OpenSSL, but load it dynamically), `SecureTransport`, + `Schannel` or `WinHTTP`; the default is `SecureTransport` on macOS, + `WinHTTP` on Windows, and whichever of `OpenSSL` or `mbedTLS` is + detected on other platforms. Defaults to `ON`. * `USE_SHA1=type`: selects the SHA1 mechanism to use; `type` can be set - to `CollisionDetection` (default), or `HTTPS` to use the HTTPS - driver specified above as the hashing provider. + to `CollisionDetection`, `HTTPS` to use the system or HTTPS provider, + or one of `OpenSSL`, `OpenSSL-Dynamic`, `OpenSSL-FIPS` (to use FIPS + compliant routines in OpenSSL), `CommonCrypto`, or `Schannel`. + Defaults to `CollisionDetection`. This option is retained for + backward compatibility and should not be changed. * `USE_SHA256=type`: selects the SHA256 mechanism to use; `type` can be - set to `HTTPS` (default) to use the HTTPS driver specified above as - the hashing provider, or `Builtin`. + set to `HTTPS` to use the system or HTTPS driver, `builtin`, or one of + `OpenSSL`, `OpenSSL-Dynamic`, `OpenSSL-FIPS` (to use FIPS compliant + routines in OpenSSL), `CommonCrypto`, or `Schannel`. Defaults to `HTTPS`. * `USE_GSSAPI=`: enables GSSAPI for SPNEGO authentication on - Unix + Unix. Defaults to `OFF`. * `USE_HTTP_PARSER=type`: selects the HTTP Parser; either `http-parser` for an external [`http-parser`](https://github.com/nodejs/http-parser) dependency, `llhttp` for an external [`llhttp`](https://github.com/nodejs/llhttp) - dependency, or `builtin` + dependency, or `builtin`. Defaults to `builtin`. * `REGEX_BACKEND=type`: selects the regular expression backend to use; - one of `regcomp_l`, `pcre2`, `pcre`, `regcomp`, or `builtin`. -* `USE_BUNDLED_ZLIB=type`: selects the zlib dependency to use; one of - `bundled` or `Chromium`. + one of `regcomp_l`, `pcre2`, `pcre`, `regcomp`, or `builtin`. The + default is to use `regcomp_l` where available, PCRE if found, otherwise, + to use the builtin. +* `USE_BUNDLED_ZLIB=type`: selects the bundled zlib; either `ON` or `OFF`. + Defaults to using the system zlib if available, falling back to the + bundled zlib. Locating Dependencies --------------------- From 13a326f4c1e4df98b5351589344ba90d537f3ffe Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 10:06:43 +0100 Subject: [PATCH 686/816] ci: build and test with system http-parser --- .github/workflows/main.yml | 2 +- ci/docker/noble | 1 + ci/docker/xenial | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cb362eaf118..d16647299b4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,7 +42,7 @@ jobs: name: noble env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DUSE_HTTP_PARSER=http-parser CMAKE_GENERATOR: Ninja - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" id: xenial-gcc-openssl diff --git a/ci/docker/noble b/ci/docker/noble index 05cd2768fe4..0a5fca413a0 100644 --- a/ci/docker/noble +++ b/ci/docker/noble @@ -13,6 +13,7 @@ RUN apt-get update && \ libclang-rt-17-dev \ libcurl4-gnutls-dev \ libgcrypt20-dev \ + libhttp-parser-dev \ libkrb5-dev \ libpcre3-dev \ libssl-dev \ diff --git a/ci/docker/xenial b/ci/docker/xenial index 793df4bda50..c84db419ab9 100644 --- a/ci/docker/xenial +++ b/ci/docker/xenial @@ -7,13 +7,13 @@ RUN apt-get update && \ clang \ cmake \ curl \ - gettext \ + gettext \ gcc \ krb5-user \ libcurl4-gnutls-dev \ - libexpat1-dev \ + libexpat1-dev \ libgcrypt20-dev \ - libintl-perl \ + libintl-perl \ libkrb5-dev \ libpcre3-dev \ libssl-dev \ From 95f47a3458d94c511420cc1b87a2da2b52b7b9cf Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Oct 2024 11:28:40 +0100 Subject: [PATCH 687/816] ci: update noble build Ubuntu noble clang is now `clang-18`; update that, and update valgrind to v3.23.0 so that clang compiles it properly. --- ci/docker/noble | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/ci/docker/noble b/ci/docker/noble index 0a5fca413a0..e7330277379 100644 --- a/ci/docker/noble +++ b/ci/docker/noble @@ -4,13 +4,14 @@ FROM ${BASE} AS apt RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ bzip2 \ - clang \ + clang \ + clang-18 \ cmake \ curl \ gcc \ git \ krb5-user \ - libclang-rt-17-dev \ + libclang-rt-18-dev \ libcurl4-gnutls-dev \ libgcrypt20-dev \ libhttp-parser-dev \ @@ -18,7 +19,7 @@ RUN apt-get update && \ libpcre3-dev \ libssl-dev \ libz-dev \ - llvm-17 \ + llvm-18 \ make \ ninja-build \ openjdk-8-jre-headless \ @@ -41,10 +42,10 @@ RUN cd /tmp && \ scripts/config.pl set MBEDTLS_MD4_C 1 && \ mkdir build build-msan && \ cd build && \ - CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + CC=clang-18 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ ninja install && \ cd ../build-msan && \ - CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ + CC=clang-18 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ ninja install && \ cd .. && \ rm -rf mbedtls-mbedtls-2.28.6 @@ -55,24 +56,24 @@ RUN cd /tmp && \ cd libssh2-1.11.0 && \ mkdir build build-msan && \ cd build && \ - CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + CC=clang-18 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ ninja install && \ cd ../build-msan && \ - CC=clang-17 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ + CC=clang-18 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ ninja install && \ cd .. && \ rm -rf libssh2-1.11.0 FROM libssh2 AS valgrind RUN cd /tmp && \ - curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.22.0.tar.bz2 | \ + curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.23.0.tar.bz2 | \ tar -xj && \ - cd valgrind-3.22.0 && \ - CC=clang-17 ./configure && \ + cd valgrind-3.23.0 && \ + CC=clang-18 ./configure && \ make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \ make install && \ cd .. && \ - rm -rf valgrind-3.22.0 + rm -rf valgrind-3.23.0 FROM valgrind AS adduser ARG UID="" From b190162f3e58abffecefc6c52c0e8097a21bb331 Mon Sep 17 00:00:00 2001 From: Vladyslav Yeremeichuk Date: Tue, 22 Oct 2024 13:58:10 +0300 Subject: [PATCH 688/816] Add the ability to get the number of objects in mempack Implement git_mempack_object_count, which returns the number of objects in mempack and -1 on error. --- include/git2/sys/mempack.h | 6 +++--- src/libgit2/odb_mempack.c | 8 ++------ tests/libgit2/odb/backend/mempack.c | 25 +++++++++++++++++-------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/git2/sys/mempack.h b/include/git2/sys/mempack.h index f8dedee8255..171c9e56e01 100644 --- a/include/git2/sys/mempack.h +++ b/include/git2/sys/mempack.h @@ -102,12 +102,12 @@ GIT_EXTERN(int) git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_ba GIT_EXTERN(int) git_mempack_reset(git_odb_backend *backend); /** - * Checks if mempack is empty + * Get the total number of objects in mempack * * @param backend The mempack backend - * @return 1 if the repository is empty, 0 if it isn't + * @return the number of objects in the mempack, -1 on error */ -GIT_EXTERN(int) git_mempack_empty(git_odb_backend *backend); +GIT_EXTERN(int) git_mempack_object_count(git_odb_backend *backend); GIT_END_DECL diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c index 732a30573cb..55bb134dfd7 100644 --- a/src/libgit2/odb_mempack.c +++ b/src/libgit2/odb_mempack.c @@ -210,13 +210,9 @@ int git_mempack_new(git_odb_backend **out) return 0; } -int git_mempack_empty(git_odb_backend *_backend) +int git_mempack_object_count(git_odb_backend *_backend) { struct memory_packer_db *db = (struct memory_packer_db *)_backend; GIT_ASSERT_ARG(_backend); - - if (git_odb_mempack_oidmap_size(&db->objects) || db->commits.size) - return 0; - - return 1; + return git_odb_mempack_oidmap_size(&db->objects); } diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c index 66450a6c53c..bb59d38c44b 100644 --- a/tests/libgit2/odb/backend/mempack.c +++ b/tests/libgit2/odb/backend/mempack.c @@ -32,14 +32,6 @@ void test_odb_backend_mempack__write_succeeds(void) cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); } -void test_odb_backend_mempack_empty(void) -{ - const char *data = "data"; - cl_assert_equal_sz(1, git_mempack_empty(_backend)); - cl_git_pass(git_odb_write(&_oid, _odb, data, strlen(data) + 1, GIT_OBJECT_BLOB)); - cl_assert_equal_sz(0, git_mempack_empty(_backend)); -} - void test_odb_backend_mempack__read_of_missing_object_fails(void) { cl_git_pass(git_oid__fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); @@ -66,3 +58,20 @@ void test_odb_backend_mempack__blob_create_from_buffer_succeeds(void) cl_git_pass(git_blob_create_from_buffer(&_oid, _repo, data, strlen(data) + 1)); cl_assert(git_odb_exists(_odb, &_oid) == 1); } + +void test_odb_backend_mempack__empty_object_count_succeeds(void) +{ + cl_assert_equal_sz(0, git_mempack_object_count(_backend)); +} + +void test_odb_backend_mempack__object_count_succeeds(void) +{ + const char *data = "data"; + cl_git_pass(git_odb_write(&_oid, _odb, data, strlen(data) + 1, GIT_OBJECT_BLOB)); + cl_assert_equal_sz(1, git_mempack_object_count(_backend)); +} + +void test_odb_backend_mempack__object_count_fails(void) +{ + cl_git_fail_with(-1, git_mempack_object_count(0)); +} From 95149d2c77e16b21914c9773b12312c9961970df Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 23 Oct 2024 10:30:20 +0100 Subject: [PATCH 689/816] readme: add OpenSSF best practices badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 261bf5c3ece..d893b5376f9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ libgit2 - the Git linkable library ================================== +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9609/badge)](https://www.bestpractices.dev/projects/9609) | Build Status | | | ------------ | - | From 73ac58fb7273b838b556e9ab358edda20b776869 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 23 Oct 2024 13:18:00 +0100 Subject: [PATCH 690/816] ci: port latest fixes to nightlies We've made some changes to our CI builds; move them to nightlies. --- .github/workflows/nightly.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e647aaae9e7..b9392f84063 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -43,7 +43,7 @@ jobs: name: noble env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DUSE_HTTP_PARSER=http-parser CMAKE_GENERATOR: Ninja - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" id: xenial-gcc-openssl @@ -141,9 +141,9 @@ jobs: container: name: noble env: - CC: clang-17 + CC: clang CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DCMAKE_C_EXTENSIONS=ON -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true @@ -156,7 +156,7 @@ jobs: container: name: noble env: - CC: clang-17 + CC: clang CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -171,7 +171,7 @@ jobs: container: name: noble env: - CC: clang-17 + CC: clang CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -440,7 +440,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download test results - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Generate test summary uses: test-summary/action@v2 with: From d2f5ce220c092b19cef52979d3a6c8cca9c85b20 Mon Sep 17 00:00:00 2001 From: Caleb Owens Date: Wed, 23 Oct 2024 19:10:39 +0100 Subject: [PATCH 691/816] Update documentation of merge_base_many --- include/git2/merge.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/git2/merge.h b/include/git2/merge.h index fcce5594d47..11f84f1fb8a 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -471,6 +471,37 @@ GIT_EXTERN(int) git_merge_base_many( /** * Find all merge bases given a list of commits * + * This behaves similar to [`git merge-base`](https://git-scm.com/docs/git-merge-base#_discussion). + * + * Given three commits `a`, `b`, and `c`, `merge_base_many` + * will compute a hypothetical commit `m`, which is a merge between `b` + * and `c`. + + * For example, with the following topology: + * ```text + * o---o---o---o---C + * / + * / o---o---o---B + * / / + * ---2---1---o---o---o---A + * ``` + * + * the result of `merge_base_many` given `a`, `b`, and `c` is 1. This is + * because the equivalent topology with the imaginary merge commit `m` + * between `b` and `c` is: + * ```text + * o---o---o---o---o + * / \ + * / o---o---o---o---M + * / / + * ---2---1---o---o---o---A + * ``` + * + * and the result of `merge_base_many` given `a` and `m` is 1. + * + * If you're looking to recieve the common ancestor between all the + * given commits, use `merge_base_octopus`. + * * @param out array in which to store the resulting ids * @param repo the repository where the commits exist * @param length The number of commits in the provided `input_array` From 57ae4b11b6d883b67e6bfb0d996c89e227d55527 Mon Sep 17 00:00:00 2001 From: Laurence McGlashan Date: Fri, 25 Oct 2024 20:29:55 +0100 Subject: [PATCH 692/816] util/win32: Continue if access is denied when deleting a folder. --- src/util/win32/posix_w32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/win32/posix_w32.c b/src/util/win32/posix_w32.c index ace23200f59..7ace3b1e1f8 100644 --- a/src/util/win32/posix_w32.c +++ b/src/util/win32/posix_w32.c @@ -770,6 +770,7 @@ int p_rmdir(const char *path) * handle to the directory." This sounds like what everybody else calls * EBUSY. Let's convert appropriate error codes. */ + case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: errno = EBUSY; break; From d1f1e17404d4928004b4eb9a84e74da3404e45da Mon Sep 17 00:00:00 2001 From: Antoine Jacoutot Date: Sun, 27 Oct 2024 09:47:31 +0100 Subject: [PATCH 693/816] realpath: unbreak build on OpenBSD --- src/util/unix/realpath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/unix/realpath.c b/src/util/unix/realpath.c index e1d2adb8dba..2565e2e83bc 100644 --- a/src/util/unix/realpath.c +++ b/src/util/unix/realpath.c @@ -24,7 +24,7 @@ char *p_realpath(const char *pathname, char *resolved) #ifdef __OpenBSD__ /* The OpenBSD realpath function behaves differently, * figure out if the file exists */ - if (access(ret, F_OK) < 0) { + if (access(result, F_OK) < 0) { if (!resolved) free(result); From 728e63f092759c24ea8d4e1683000c571bf2ffe0 Mon Sep 17 00:00:00 2001 From: Laurence McGlashan Date: Fri, 15 Nov 2024 09:30:09 +0000 Subject: [PATCH 694/816] ssh: Include rsa-sha2-256 and rsa-sha2-512 in the list of preferred hostkey types --- src/libgit2/transports/ssh_libssh2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libgit2/transports/ssh_libssh2.c b/src/libgit2/transports/ssh_libssh2.c index 7011674f74e..6469c8d6480 100644 --- a/src/libgit2/transports/ssh_libssh2.c +++ b/src/libgit2/transports/ssh_libssh2.c @@ -515,6 +515,8 @@ static void find_hostkey_preference( add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_384, "ecdsa-sha2-nistp384"); add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_521, "ecdsa-sha2-nistp521"); #endif + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_SSHRSA, "rsa-sha2-512"); + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_SSHRSA, "rsa-sha2-256"); add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_SSHRSA, "ssh-rsa"); } From 27549bdcce0519983b96027627678fcf799041b1 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Wed, 20 Nov 2024 21:27:45 +0000 Subject: [PATCH 695/816] object: core.abbrev accepts string values --- src/libgit2/config_cache.c | 13 +++++++--- src/libgit2/diff_print.c | 6 +---- src/libgit2/object.c | 36 +++++++++++++++++++++++---- src/libgit2/object.h | 2 ++ src/libgit2/repository.h | 2 ++ tests/libgit2/object/shortid.c | 45 +++++++++++++++++++++++++++++++--- 6 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/libgit2/config_cache.c b/src/libgit2/config_cache.c index 4bb91f52b9f..9bb2bb99845 100644 --- a/src/libgit2/config_cache.c +++ b/src/libgit2/config_cache.c @@ -65,10 +65,15 @@ static git_configmap _configmap_logallrefupdates[] = { }; /* - * Generic map for integer values - */ -static git_configmap _configmap_int[] = { +Set the length object names are abbreviated to. If unspecified or set to "auto", +an appropriate value is computed based on the approximate number of packed objects in your repository, +which hopefully is enough for abbreviated object names to stay unique for some time. If set to "no", +no abbreviation is made and the object names are shown in their full length. The minimum length is 4. +*/ +static git_configmap _configmap_abbrev[] = { + {GIT_CONFIGMAP_FALSE, NULL, GIT_ABBREV_FALSE}, {GIT_CONFIGMAP_INT32, NULL, 0}, + {GIT_CONFIGMAP_STRING, "auto", GIT_ABBREV_DEFAULT} }; static struct map_data _configmaps[] = { @@ -79,7 +84,7 @@ static struct map_data _configmaps[] = { {"core.filemode", NULL, 0, GIT_FILEMODE_DEFAULT }, {"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT }, {"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT }, - {"core.abbrev", _configmap_int, 1, GIT_ABBREV_DEFAULT }, + {"core.abbrev", _configmap_abbrev, ARRAY_SIZE(_configmap_abbrev), GIT_ABBREV_DEFAULT }, {"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT }, {"core.safecrlf", _configmap_safecrlf, ARRAY_SIZE(_configmap_safecrlf), GIT_SAFE_CRLF_DEFAULT}, {"core.logallrefupdates", _configmap_logallrefupdates, ARRAY_SIZE(_configmap_logallrefupdates), GIT_LOGALLREFUPDATES_DEFAULT}, diff --git a/src/libgit2/diff_print.c b/src/libgit2/diff_print.c index 96950cc60ea..8e76e85b4f8 100644 --- a/src/libgit2/diff_print.c +++ b/src/libgit2/diff_print.c @@ -53,14 +53,10 @@ static int diff_print_info_init__common( if (!pi->id_strlen) { if (!repo) pi->id_strlen = GIT_ABBREV_DEFAULT; - else if (git_repository__configmap_lookup(&pi->id_strlen, repo, GIT_CONFIGMAP_ABBREV) < 0) + else if (git_object__abbrev_length(&pi->id_strlen, repo) < 0) return -1; } - if (pi->id_strlen > 0 && - (size_t)pi->id_strlen > git_oid_hexsize(pi->oid_type)) - pi->id_strlen = (int)git_oid_hexsize(pi->oid_type); - memset(&pi->line, 0, sizeof(pi->line)); pi->line.old_lineno = -1; pi->line.new_lineno = -1; diff --git a/src/libgit2/object.c b/src/libgit2/object.c index 5fab77e6ae3..245e5867641 100644 --- a/src/libgit2/object.c +++ b/src/libgit2/object.c @@ -520,13 +520,38 @@ int git_object_lookup_bypath( return error; } +int git_object__abbrev_length(int *out, git_repository *repo) +{ + size_t oid_hexsize; + int len; + int error; + + oid_hexsize = git_oid_hexsize(repo->oid_type); + + if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0) + return error; + + if (len == GIT_ABBREV_FALSE) { + len = oid_hexsize; + } + + if (len < GIT_ABBREV_MINIMUM || (size_t)len > oid_hexsize) { + git_error_set(GIT_ERROR_CONFIG, "invalid oid abbreviation setting: '%d'", len); + return -1; + } + + *out = len; + + return error; +} + static int git_object__short_id(git_str *out, const git_object *obj) { git_repository *repo; git_oid id; git_odb *odb; size_t oid_hexsize; - int len = GIT_ABBREV_DEFAULT, error; + int len, error; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(obj); @@ -536,12 +561,13 @@ static int git_object__short_id(git_str *out, const git_object *obj) git_oid_clear(&id, repo->oid_type); oid_hexsize = git_oid_hexsize(repo->oid_type); - if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0) + if ((error = git_object__abbrev_length(&len, repo)) < 0) return error; - if (len < 0 || (size_t)len > oid_hexsize) { - git_error_set(GIT_ERROR_CONFIG, "invalid oid abbreviation setting: '%d'", len); - return -1; + if ((size_t)len == oid_hexsize) { + if ((error = git_oid_cpy(&id, &obj->cached.oid)) < 0) { + return error; + } } if ((error = git_repository_odb(&odb, repo)) < 0) diff --git a/src/libgit2/object.h b/src/libgit2/object.h index b6c604c8178..b21165f70aa 100644 --- a/src/libgit2/object.h +++ b/src/libgit2/object.h @@ -83,4 +83,6 @@ GIT_INLINE(git_object_t) git_object__type_from_filemode(git_filemode_t mode) } } +int git_object__abbrev_length(int *out, git_repository *repo); + #endif diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index 704e0ad2e10..4e820c9b866 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -102,6 +102,8 @@ typedef enum { /* core.trustctime */ GIT_TRUSTCTIME_DEFAULT = GIT_CONFIGMAP_TRUE, /* core.abbrev */ + GIT_ABBREV_FALSE = GIT_CONFIGMAP_FALSE, + GIT_ABBREV_MINIMUM = 4, GIT_ABBREV_DEFAULT = 7, /* core.precomposeunicode */ GIT_PRECOMPOSE_DEFAULT = GIT_CONFIGMAP_FALSE, diff --git a/tests/libgit2/object/shortid.c b/tests/libgit2/object/shortid.c index 69fceeedaf0..81e7b2f35f9 100644 --- a/tests/libgit2/object/shortid.c +++ b/tests/libgit2/object/shortid.c @@ -4,13 +4,12 @@ git_repository *_repo; void test_object_shortid__initialize(void) { - cl_git_pass(git_repository_open(&_repo, cl_fixture("duplicate.git"))); + _repo = cl_git_sandbox_init("duplicate.git"); } void test_object_shortid__cleanup(void) { - git_repository_free(_repo); - _repo = NULL; + cl_git_sandbox_cleanup(); } void test_object_shortid__select(void) @@ -49,3 +48,43 @@ void test_object_shortid__select(void) git_buf_dispose(&shorty); } + +void test_object_shortid__core_abbrev(void) +{ + git_oid full; + git_object *obj; + git_buf shorty = {0}; + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, _repo)); + git_oid__fromstr(&full, "ce013625030ba8dba906f756967f9e9ca394464a", GIT_OID_SHA1); + cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJECT_ANY)); + + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "auto")); + cl_git_pass(git_object_short_id(&shorty, obj)); + cl_assert_equal_i(7, shorty.size); + cl_assert_equal_s("ce01362", shorty.ptr); + + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "off")); + cl_git_pass(git_object_short_id(&shorty, obj)); + cl_assert_equal_i(40, shorty.size); + cl_assert_equal_s("ce013625030ba8dba906f756967f9e9ca394464a", shorty.ptr); + + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "4")); + cl_git_pass(git_object_short_id(&shorty, obj)); + cl_assert_equal_i(4, shorty.size); + cl_assert_equal_s("ce01", shorty.ptr); + + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "3")); + cl_git_fail(git_object_short_id(&shorty, obj)); + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "41")); + cl_git_fail(git_object_short_id(&shorty, obj)); + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "invalid")); + cl_git_fail(git_object_short_id(&shorty, obj)); + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "true")); + cl_git_fail(git_object_short_id(&shorty, obj)); + + git_object_free(obj); + git_buf_dispose(&shorty); + git_config_free(cfg); +} From 6ee06ca7376138b37858cbddd721e839a29b59f0 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Wed, 20 Nov 2024 21:32:24 +0000 Subject: [PATCH 696/816] Remove unnecessary comment. --- src/libgit2/config_cache.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libgit2/config_cache.c b/src/libgit2/config_cache.c index 9bb2bb99845..0b574c20c4e 100644 --- a/src/libgit2/config_cache.c +++ b/src/libgit2/config_cache.c @@ -64,12 +64,6 @@ static git_configmap _configmap_logallrefupdates[] = { {GIT_CONFIGMAP_STRING, "always", GIT_LOGALLREFUPDATES_ALWAYS}, }; -/* -Set the length object names are abbreviated to. If unspecified or set to "auto", -an appropriate value is computed based on the approximate number of packed objects in your repository, -which hopefully is enough for abbreviated object names to stay unique for some time. If set to "no", -no abbreviation is made and the object names are shown in their full length. The minimum length is 4. -*/ static git_configmap _configmap_abbrev[] = { {GIT_CONFIGMAP_FALSE, NULL, GIT_ABBREV_FALSE}, {GIT_CONFIGMAP_INT32, NULL, 0}, From 98fee5212f488b0b073bcad2dcc18fd9e5fcb795 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Wed, 20 Nov 2024 21:46:20 +0000 Subject: [PATCH 697/816] Cast size_t to int --- src/libgit2/object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/object.c b/src/libgit2/object.c index 245e5867641..9b885120470 100644 --- a/src/libgit2/object.c +++ b/src/libgit2/object.c @@ -532,7 +532,7 @@ int git_object__abbrev_length(int *out, git_repository *repo) return error; if (len == GIT_ABBREV_FALSE) { - len = oid_hexsize; + len = (int)oid_hexsize; } if (len < GIT_ABBREV_MINIMUM || (size_t)len > oid_hexsize) { From eb84531575d8a795bfd796ea96f419955717484f Mon Sep 17 00:00:00 2001 From: lmcglash Date: Mon, 25 Nov 2024 21:55:43 +0000 Subject: [PATCH 698/816] Clear data after negotiation --- src/libgit2/transports/smart_protocol.c | 1 + tests/libgit2/online/clone.c | 26 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index fb2dd7cf2d6..0522f751784 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -433,6 +433,7 @@ int git_smart__negotiate_fetch( if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; + git_str_clear(&data); while ((error = recv_pkt((git_pkt **)&pkt, NULL, t)) == 0) { bool complete = false; diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 180a76603ff..6e9c8ea5051 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -663,7 +663,7 @@ static int github_credentials( void test_online_clone__ssh_github(void) { -#if !defined(GIT_SSH) || !defined(GIT_SSH_MEMORY_CREDENTIALS) +#if !defined(GIT_SSH) || !defined(GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS) clar__skip(); #endif @@ -678,6 +678,24 @@ void test_online_clone__ssh_github(void) cl_git_pass(git_clone(&g_repo, SSH_REPO_URL, "./foo", &g_options)); } +void test_online_clone__ssh_github_shallow(void) +{ +#if !defined(GIT_SSH) || !defined(GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS) + clar__skip(); +#endif + + if (!_github_ssh_pubkey || !_github_ssh_privkey) + clar__skip(); + + cl_fake_homedir(NULL); + + g_options.fetch_opts.callbacks.credentials = github_credentials; + g_options.fetch_opts.callbacks.certificate_check = succeed_certificate_check; + g_options.fetch_opts.depth = 1; + + cl_git_pass(git_clone(&g_repo, SSH_REPO_URL, "./foo", &g_options)); +} + void test_online_clone__ssh_auth_methods(void) { int with_user; @@ -704,7 +722,7 @@ void test_online_clone__ssh_auth_methods(void) */ void test_online_clone__ssh_certcheck_accepts_unknown(void) { -#if !defined(GIT_SSH_LIBSSH2) || !defined(GIT_SSH_MEMORY_CREDENTIALS) +#if !defined(GIT_SSH_LIBSSH2) || !defined(GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS) clar__skip(); #endif @@ -733,7 +751,7 @@ void test_online_clone__ssh_certcheck_override_knownhosts(void) { git_str knownhostsfile = GIT_STR_INIT; -#if !defined(GIT_SSH) || !defined(GIT_SSH_MEMORY_CREDENTIALS) +#if !defined(GIT_SSH) || !defined(GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS) clar__skip(); #endif @@ -927,7 +945,7 @@ static int ssh_memory_cred_cb(git_credential **cred, const char *url, const char void test_online_clone__ssh_memory_auth(void) { -#ifndef GIT_SSH_MEMORY_CREDENTIALS +#ifndef GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS clar__skip(); #endif if (!_remote_url || !_remote_user || !_remote_ssh_privkey || strncmp(_remote_url, "ssh://", 5) != 0) From 89cc5ef8e8182eab6482717383c02b3bdd575161 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 25 Nov 2024 10:12:29 +0000 Subject: [PATCH 699/816] Include documentation generator libgit2 has a new documentation generator that generates API schema from our headers, then produces reference documentation that is included into the website directly. --- .github/workflows/documentation.yml | 60 ++ .github/workflows/main.yml | 49 - script/api-docs/README.md | 13 + script/api-docs/api-generator.js | 1543 +++++++++++++++++++++++++++ script/api-docs/docs-generator.js | 1326 +++++++++++++++++++++++ script/api-docs/generate | 105 ++ script/api-docs/package-lock.json | 79 ++ script/api-docs/package.json | 6 + 8 files changed, 3132 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/documentation.yml create mode 100644 script/api-docs/README.md create mode 100755 script/api-docs/api-generator.js create mode 100755 script/api-docs/docs-generator.js create mode 100755 script/api-docs/generate create mode 100644 script/api-docs/package-lock.json create mode 100644 script/api-docs/package.json diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000000..a2e45ca5ff2 --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,60 @@ +# Update the www.libgit2.org reference documentation +name: Generate Documentation + +on: + push: + branches: [ main, maint/* ] + release: + workflow_dispatch: + +permissions: + contents: read + +jobs: + documentation: + name: "Generate documentation" + runs-on: "ubuntu-latest" + steps: + - name: Check out source repository + uses: actions/checkout@v4 + with: + path: source + fetch-depth: 0 + - name: Check out documentation repository + uses: actions/checkout@v4 + with: + repository: libgit2/www.libgit2.org + path: www + fetch-depth: 0 + ssh-key: ${{ secrets.DOCS_PUBLISH_KEY }} + - name: Prepare branches + run: | + for a in main $(git branch -r --list 'origin/maint/*' | sed -e "s/^ origin\///"); do + git branch --track "$a" "origin/$a" + done + working-directory: source + - name: Generate documentation + run: | + npm install + ./generate ../.. ../../../www/docs + working-directory: source/script/api-docs + - name: Examine changes + run: | + if [ -n "$(git diff --name-only)" ]; then + echo "changes=true" >> $GITHUB_OUTPUT + else + echo "changes=false" >> $GITHUB_OUTPUT + fi + id: check + working-directory: www + - name: Publish documentation + run: | + DATE=$(date +"%Y-%m-%d") + + git config user.name 'Documentation Site Generator' + git config user.email 'libgit2@users.noreply.github.com' + git add . + git commit -m"Documentation update ${DATE}" + git push origin main + if: steps.check.outputs.changes == 'true' + working-directory: www diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d16647299b4..d18321f5fb0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -245,52 +245,3 @@ jobs: uses: test-summary/action@v2 with: paths: 'test-results-*/*.xml' - - - # Generate documentation using docurium. We'll upload the documentation - # as a build artifact so that it can be reviewed as part of a pull - # request or in a forked build. For CI builds in the main repository's - # main branch, we'll push the gh-pages branch back up so that it is - # published to our documentation site. - documentation: - name: Generate documentation - if: success() || failure() - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - path: source - fetch-depth: 0 - - name: Set up container - uses: ./source/.github/actions/download-or-build-container - with: - registry: ${{ env.docker-registry }} - config-path: ${{ env.docker-config-path }} - container: docurium - github_token: ${{ secrets.github_token }} - dockerfile: ${{ matrix.platform.container.dockerfile }} - - name: Generate documentation - working-directory: source - run: | - git config user.name 'Documentation Generation' - git config user.email 'libgit2@users.noreply.github.com' - git branch gh-pages origin/gh-pages - docker login https://${{ env.docker-registry }} -u ${{ github.actor }} -p ${{ github.token }} - docker run \ - --rm \ - -v "$(pwd):/home/libgit2" \ - -w /home/libgit2 \ - ${{ env.docker-registry }}/${{ github.repository }}/docurium:latest \ - cm doc api.docurium - git checkout gh-pages - zip --exclude .git/\* --exclude .gitignore --exclude .gitattributes -r api-documentation.zip . - - uses: actions/upload-artifact@v4 - name: Upload artifact - with: - name: api-documentation - path: source/api-documentation.zip - - name: Push documentation branch - working-directory: source - run: git push origin gh-pages - if: github.event_name == 'push' && github.repository == 'libgit2/libgit2' diff --git a/script/api-docs/README.md b/script/api-docs/README.md new file mode 100644 index 00000000000..fb329e2faa1 --- /dev/null +++ b/script/api-docs/README.md @@ -0,0 +1,13 @@ +# API Documentation Generator + +These scripts generate the "raw API" specs and reference documentation +for [www.libgit2.org](https://libgit2.org/docs/reference). + +The "raw API" specs consists of JSON documents, on per +released version or branch, that describes the APIs. This is +suitable for creating documentation from, or may be useful for +language bindings as well. + +The reference documentation is documentation fragments for each +API in each version, ready to be included in the libgit2 documentation +website. diff --git a/script/api-docs/api-generator.js b/script/api-docs/api-generator.js new file mode 100755 index 00000000000..fffeb5e9c48 --- /dev/null +++ b/script/api-docs/api-generator.js @@ -0,0 +1,1543 @@ +#!/usr/bin/env node + +const path = require('node:path'); +const child_process = require('node:child_process'); +const fs = require('node:fs').promises; +const util = require('node:util'); +const process = require('node:process'); + +const { program } = require('commander'); + +const includePath = (p) => `${p}/include`; +const ancientIncludePath = (p) => `${p}/src/git`; +const legacyIncludePath = (p) => `${p}/src/git2`; +const standardIncludePath = (p) => `${includePath(p)}/git2`; +const systemIncludePath = (p) => `${includePath(p)}/git2/sys`; + +const fileIgnoreList = [ 'stdint.h', 'inttypes.h' ]; +const apiIgnoreList = [ 'GIT_BEGIN_DECL', 'GIT_END_DECL', 'GIT_WIN32' ]; + +// Some older versions of libgit2 need some help with includes +const defaultIncludes = [ + 'checkout.h', 'common.h', 'diff.h', 'email.h', 'oidarray.h', 'merge.h', 'remote.h', 'types.h' +]; + +// We're unable to fully map `types.h` defined types into groups; +// provide some help. +const groupMap = { + 'filemode': 'tree', + 'treebuilder': 'tree', + 'note': 'notes', + 'packbuilder': 'pack', + 'reference': 'refs', + 'push': 'remote' }; + +async function headerPaths(p) { + const possibleIncludePaths = [ + ancientIncludePath(p), + legacyIncludePath(p), + standardIncludePath(p), + systemIncludePath(p) + ]; + + const includePaths = [ ]; + const paths = [ ]; + + for (const possibleIncludePath of possibleIncludePaths) { + try { + await fs.stat(possibleIncludePath); + includePaths.push(possibleIncludePath); + } + catch (e) { + if (e?.code !== 'ENOENT') { + throw e; + } + } + } + + if (!includePaths.length) { + throw new Error(`no include paths for ${p}`); + } + + for (const fullPath of includePaths) { + paths.push(...(await fs.readdir(fullPath)). + filter((filename) => filename.endsWith('.h')). + filter((filename) => !fileIgnoreList.includes(filename)). + map((filename) => `${fullPath}/${filename}`)); + } + + return paths; +} + +function trimPath(basePath, headerPath) { + const possibleIncludePaths = [ + ancientIncludePath(basePath), + legacyIncludePath(basePath), + standardIncludePath(basePath), + systemIncludePath(basePath) + ]; + + for (const possibleIncludePath of possibleIncludePaths) { + if (headerPath.startsWith(possibleIncludePath + '/')) { + return headerPath.substr(possibleIncludePath.length + 1); + } + } + + throw new Error("header path is not beneath include root"); +} + +function parseFileAst(path, ast) { + let currentFile = undefined; + const fileData = [ ]; + + for (const node of ast.inner) { + if (node.loc?.file && currentFile != node.loc.file) { + currentFile = node.loc.file; + } else if (node.loc?.spellingLoc?.file && currentFile != node.loc.spellingLoc.file) { + currentFile = node.loc.spellingLoc.file; + } + + if (currentFile != path) { + continue; + } + + fileData.push(node); + } + + return fileData; +} + +function includeBase(path) { + const segments = path.split('/'); + + while (segments.length > 1) { + if (segments[segments.length - 1] === 'git2' || + segments[segments.length - 1] === 'git') { + segments.pop(); + return segments.join('/'); + } + + segments.pop(); + } + + throw new Error(`could not resolve include base for ${path}`); +} + +function readAst(path, options) { + return new Promise((resolve, reject) => { + let errorMessage = ''; + const chunks = [ ]; + + const processArgs = [ path, '-Xclang', '-ast-dump=json', `-I${includeBase(path)}` ]; + + if (options?.deprecateHard) { + processArgs.push(`-DGIT_DEPRECATE_HARD`); + } + + if (options?.includeFiles) { + for (const file of options.includeFiles) { + processArgs.push(`-include`); + processArgs.push(file) + } + } + + const process = child_process.spawn('clang', processArgs); + + process.stderr.on('data', (message) => { + errorMessage += message; + }); + process.stdout.on('data', (chunk) => { + chunks.push(chunk); + }); + process.on('close', (code) => { + if (code != 0 && options.strict) { + reject(new Error(`clang exit code ${code}: ${errorMessage}`)); + } + else if (code != 0) { + resolve([ ]); + } + else { + const ast = JSON.parse(Buffer.concat(chunks).toString()); + resolve(parseFileAst(path, ast)); + } + }); + process.on('error', function (err) { + reject(err); + }); + }); +} + +async function readFile(path) { + const buf = await fs.readFile(path); + return buf.toString(); +} + +function ensure(message, test) { + if (!test) { + throw new Error(message); + } +} + +function ensureDefined(name, value) { + if (!value) { + throw new Error(`could not find ${name} for declaration`); + } + + return value; +} + +function groupifyId(location, id) { + if (!id) { + throw new Error(`could not find id in declaration`); + } + + if (!location || !location.file) { + throw new Error(`unspecified location`); + } + + return `${location.file}-${id}`; +} + +function blockCommentText(block) { + ensure('block does not have a single paragraph element', block.inner.length === 1 && block.inner[0].kind === 'ParagraphComment'); + return commentText(block.inner[0]); +} + +function richBlockCommentText(block) { + ensure('block does not have a single paragraph element', block.inner.length === 1 && block.inner[0].kind === 'ParagraphComment'); + return richCommentText(block.inner[0]); +} + +function paramCommentText(param) { + ensure('param does not have a single paragraph element', param.inner.length === 1 && param.inner[0].kind === 'ParagraphComment'); + return richCommentText(param.inner[0]); +} + +function appendCommentText(chunk) { + return chunk.startsWith(' ') ? "\n" + chunk : chunk; +} + +function commentText(para) { + let text = ''; + + for (const comment of para.inner) { + // docbook allows backslash escaped text, and reports it differently. + // we restore the literal `\`. + if (comment.kind === 'InlineCommandComment') { + text += `\\${comment.name}`; + } + else if (comment.kind === 'TextComment') { + text += text ? "\n" + comment.text : comment.text; + } else { + throw new Error(`unknown paragraph comment element: ${comment.kind}`); + } + } + + return text.trim(); +} + +function nextText(para, idx) { + if (!para.inner[idx + 1] || para.inner[idx + 1].kind !== 'TextComment') { + throw new Error("expected text comment"); + } + + return para.inner[idx + 1].text; +} + +function inlineCommandData(data, command) { + ensure(`${command} information does not follow @${command}`, data?.kind === 'TextComment'); + + const result = data.text.match(/^(?:\[([^\]]+)\])? ((?:[a-zA-Z0-9\_]+)|`[a-zA-Z0-9\_\* ]+`)(.*)/); + ensure(`${command} data does not follow @${command}`, result); + + const [ , attr, spec, remain ] = result; + return [ attr, spec.replace(/^`(.*)`$/, "$1"), remain ] +} + +function richCommentText(para) { + let text = ''; + let extendedType = undefined; + let subkind = undefined; + let versionMacro = undefined; + let initMacro = undefined; + let initFunction = undefined; + let lastComment = undefined; + + for (let i = 0; i < para.inner?.length; i++) { + const comment = para.inner[i]; + + if (comment.kind === 'InlineCommandComment' && + comment.name === 'type') { + const [ attr, data, remain ] = inlineCommandData(para.inner[++i], "type"); + + extendedType = { kind: attr, type: data }; + text += remain; + } + else if (comment.kind === 'InlineCommandComment' && + comment.name === 'flags') { + subkind = 'flags'; + } + else if (comment.kind === 'InlineCommandComment' && + comment.name === 'options') { + const [ attr, data, remain ] = inlineCommandData(para.inner[++i], "options"); + + if (attr === 'version') { + versionMacro = data; + } + else if (attr === 'init_macro') { + initMacro = data; + } + else if (attr === 'init_function') { + initFunction = data; + } + + subkind = 'options'; + text += remain; + } + // docbook allows backslash escaped text, and reports it differently. + // we restore the literal `\`. + else if (comment.kind === 'InlineCommandComment') { + text += `\\${comment.name}`; + } + else if (comment.kind === 'TextComment') { + // clang oddity: it breaks into two + // comment blocks, assuming that the trailing > should be a + // blockquote newline sort of thing. unbreak them. + if (comment.text.startsWith('>') && + lastComment && + lastComment.loc.offset + lastComment.text.length === comment.loc.offset) { + + text += comment.text; + } else { + text += text ? "\n" + comment.text : comment.text; + } + } + else if (comment.kind === 'HTMLStartTagComment' && comment.name === 'p') { + text += "\n"; + } + else { + throw new Error(`unknown paragraph comment element: ${comment.kind}`); + } + + lastComment = comment; + } + + return { + text: text.trim(), + extendedType: extendedType, + subkind: subkind, + versionMacro: versionMacro, + initMacro: initMacro, + initFunction: initFunction + } +} + +function join(arr, elem) { + if (arr) { + return [ ...arr, elem ]; + } + + return [ elem ]; +} + +function joinIfNotEmpty(arr, elem) { + if (!elem || elem === '') { + return arr; + } + + if (arr) { + return [ ...arr, elem ]; + } + + return [ elem ]; +} + +function pushIfNotEmpty(arr, elem) { + if (elem && elem !== '') { + arr.push(elem); + } +} + +function single(arr, fn, message) { + let result = undefined; + + if (!arr) { + return undefined; + } + + for (const match of arr.filter(fn)) { + if (result) { + throw new Error(`multiple matches in array for ${fn}${message ? ' (' + message + ')': ''}`); + } + + result = match; + } + + return result; +} + +function updateLocation(location, decl) { + location.file = trimBase(decl.loc?.spellingLoc?.file || decl.loc?.file) || location.file; + location.line = decl.loc?.spellingLoc?.line || decl.loc?.line || location.line; + location.column = decl.loc?.spellingLoc?.col || decl.loc?.col || location.column; + + return location; +} + +async function readFileLocation(startLocation, endLocation) { + if (startLocation.file != endLocation.file) { + throw new Error("cannot read across files"); + } + + const data = await fs.readFile(startLocation.file, "utf8"); + const lines = data.split(/\r?\n/).slice(startLocation.line - 1, endLocation.line); + + lines[lines.length - 1] = lines[lines.length - 1].slice(0, endLocation.column); + lines[0] = lines[0].slice(startLocation.column - 1); + + return lines +} + +function formatLines(lines) { + let result = ""; + let continuation = false; + + for (const i in lines) { + if (!continuation) { + lines[i] = lines[i].trimStart(); + } + + continuation = lines[i].endsWith("\\"); + + if (continuation) { + lines[i] = lines[i].slice(0, -1); + } else { + lines[i] = lines[i].trimEnd(); + } + + result += lines[i]; + } + + if (continuation) { + throw new Error("unterminated literal continuation"); + } + + return result; +} + +async function parseExternalRange(location, range) { + const startLocation = {...location}; + startLocation.file = trimBase(range.begin.spellingLoc.file || startLocation.file); + startLocation.line = range.begin.spellingLoc.line || startLocation.line; + startLocation.column = range.begin.spellingLoc.col || startLocation.column; + + const endLocation = {...startLocation}; + endLocation.file = trimBase(range.end.spellingLoc.file || endLocation.file); + endLocation.line = range.end.spellingLoc.line || endLocation.line; + endLocation.column = range.end.spellingLoc.col || endLocation.column; + + const lines = await readFileLocation(startLocation, endLocation); + + return formatLines(lines); +} + +async function parseLiteralRange(location, range) { + const startLocation = updateLocation({...location}, { loc: range.begin }); + const endLocation = updateLocation({...location}, { loc: range.end }); + + const lines = await readFileLocation(startLocation, endLocation); + + return formatLines(lines); +} + +async function parseRange(location, range) { + return range.begin.spellingLoc ? parseExternalRange(location, range) : parseLiteralRange(location, range); +} + +class ParserError extends Error { + constructor(message, location) { + if (!location) { + super(`${message} at (unknown)`); + } + else { + super(`${message} at ${location.file}:${location.line}`); + } + this.name = 'ParserError'; + } +} + +function validateParsing(test, message, location) { + if (!test) { + throw new ParserError(message, location); + } +} + +function parseComment(spec, location, comment, options) { + let result = { }; + let last = undefined; + + for (const c of comment.inner.filter(c => c.kind === 'ParagraphComment' || c.kind === 'VerbatimLineComment')) { + if (c.kind === 'ParagraphComment') { + const commentData = richCommentText(c); + + result.comment = joinIfNotEmpty(result.comment, commentData.text); + delete commentData.text; + + result = { ...result, ...commentData }; + } + else if (c.kind === 'VerbatimLineComment') { + result.comment = joinIfNotEmpty(result.comment, c.text.trim()); + } + else { + throw new Error(`unknown comment ${c.kind}`); + } + } + + for (const c of comment.inner.filter(c => c.kind !== 'ParagraphComment' && c.kind !== 'VerbatimLineComment')) { + if (c.kind === 'BlockCommandComment' && c.name === 'see') { + result.see = joinIfNotEmpty(result.see, blockCommentText(c)); + } + else if (c.kind === 'BlockCommandComment' && c.name === 'note') { + result.notes = joinIfNotEmpty(result.notes, blockCommentText(c)); + } + else if (c.kind === 'BlockCommandComment' && c.name === 'deprecated') { + result.deprecations = joinIfNotEmpty(result.deprecations, blockCommentText(c)); + } + else if (c.kind === 'BlockCommandComment' && c.name === 'warning') { + result.warnings = joinIfNotEmpty(result.warnings, blockCommentText(c)); + } + else if (c.kind === 'BlockCommandComment' && + (c.name === 'return' || (c.name === 'returns' && !options.strict))) { + const returnData = richBlockCommentText(c); + + result.returns = { + extendedType: returnData.extendedType, + comment: returnData.text + }; + } + else if (c.kind === 'ParamCommandComment') { + ensure('param has a name', c.param); + + const paramDetails = paramCommentText(c); + + result.params = join(result.params, { + name: c.param, + direction: c.direction, + values: paramDetails.type, + extendedType: paramDetails.extendedType, + comment: paramDetails.text + }); + } + else if (options.strict) { + if (c.kind === 'BlockCommandComment') { + throw new ParserError(`unknown block command comment ${c.name}`, location); + } + else if (c.kind === 'VerbatimBlockComment') { + throw new Error(`unknown verbatim command comment ${c.name}`, location); + } + else { + throw new Error(`unknown comment ${c.kind} in ${kind}`); + } + } + } + + return result; +} + +async function parseFunction(location, decl, options) { + let result = { + kind: 'function', + id: groupifyId(location, decl.id), + name: ensureDefined('name', decl.name), + location: {...location} + }; + + // prototype + const [ , returnType, ] = decl.type.qualType.match(/(.*?)(?: )?\((.*)\)$/) || [ ]; + ensureDefined('return type declaration', returnType); + result.returns = { type: returnType }; + + for (const paramDecl of decl.inner.filter(attr => attr.kind === 'ParmVarDecl')) { + updateLocation(location, paramDecl); + + const inner = paramDecl.inner || []; + const innerLocation = {...location}; + let paramAnnotations = undefined; + + for (const annotateDecl of inner.filter(attr => attr.kind === 'AnnotateAttr')) { + updateLocation(innerLocation, annotateDecl); + + paramAnnotations = join(paramAnnotations, await parseRange(innerLocation, annotateDecl.range)); + } + + result.params = join(result.params, { + name: paramDecl.name, + type: paramDecl.type.qualType, + annotations: paramAnnotations + }); + } + + // doc comment + const commentText = single(decl.inner, (attr => attr.kind === 'FullComment')); + + if (commentText) { + const commentData = parseComment(`function:${decl.name}`, location, commentText, options); + + if (result.params) { + if (options.strict && (!commentData.params || result.params.length > commentData.params.length)) { + throw new ParserError(`not all params are documented`, location); + } + + if (options.strict && result.params.length < commentData.params.length) { + throw new ParserError(`additional params are documented`, location); + } + } + + if (commentData.params) { + for (const i in result.params) { + let match; + + for (const j in commentData.params) { + if (result.params[i].name === commentData.params[j].name) { + match = j; + break; + } + } + + if (options.strict && (!match || match != i)) { + throw new ParserError( + `param documentation does not match param name '${result.params[i].name}'`, + location); + } + + if (match) { + result.params[i] = { ...result.params[i], ...commentData.params[match] }; + } + } + } else if (options.strict && result.params) { + throw new ParserError(`no params documented for ${decl.name}`, location); + } + + if (options.strict && !commentData.returns && result.returns.type != 'void') { + throw new ParserError(`return information is not documented for ${decl.name}`, location); + } + + result.returns = { ...result.returns, ...commentData.returns }; + + delete commentData.params; + delete commentData.returns; + + result = { ...result, ...commentData }; + } + else if (options.strict) { + throw new ParserError(`no documentation for function ${decl.name}`, location); + } + + return result; +} + +function parseEnum(location, decl, options) { + let result = { + kind: 'enum', + id: groupifyId(location, decl.id), + name: decl.name, + referenceName: decl.name ? `enum ${decl.name}` : undefined, + members: [ ], + comment: undefined, + location: {...location} + }; + + for (const member of decl.inner.filter(attr => attr.kind === 'EnumConstantDecl')) { + ensure('enum constant has a name', member.name); + + const explicitValue = single(member.inner, (attr => attr.kind === 'ConstantExpr')); + const commentText = single(member.inner, (attr => attr.kind === 'FullComment')); + const commentData = commentText ? parseComment(`enum:${decl.name}:member:${member.name}`, location, commentText, options) : undefined; + + result.members.push({ + name: member.name, + value: explicitValue ? explicitValue.value : undefined, + ...commentData + }); + } + + const commentText = single(decl.inner, (attr => attr.kind === 'FullComment')); + + if (commentText) { + result = { ...result, ...parseComment(`enum:${decl.name}`, location, commentText, options) }; + } + + return result; +} + +function resolveFunctionPointerTypedef(location, typedef) { + const signature = typedef.type.match(/^((?:const )?[^\s]+(?:\s+\*+)?)\s*\(\*\)\((.*)\)$/); + const [ , returnType, paramData ] = signature; + const params = paramData.split(/,\s+/); + + if (options.strict && (!typedef.params || params.length != typedef.params.length)) { + throw new ParserError(`not all params are documented for function pointer typedef ${typedef.name}`, typedef.location); + } + + if (!typedef.params) { + typedef.params = [ ]; + } + + for (const i in params) { + if (!typedef.params[i]) { + typedef.params[i] = { }; + } + + typedef.params[i].type = params[i]; + } + + if (typedef.returns === undefined && returnType === 'void') { + typedef.returns = { type: 'void' }; + } + else if (typedef.returns !== undefined) { + typedef.returns.type = returnType; + } + else if (options.strict) { + throw new ParserError(`return type is not documented for function pointer typedef ${typedef.name}`, typedef.location); + } +} + +function parseTypedef(location, decl, options) { + updateLocation(location, decl); + + let result = { + kind: 'typedef', + id: groupifyId(location, decl.id), + name: ensureDefined('name', decl.name), + type: ensureDefined('type.qualType', decl.type.qualType), + targetId: undefined, + comment: undefined, + location: {...location} + }; + + const elaborated = single(decl.inner, (attr => attr.kind === 'ElaboratedType')); + if (elaborated !== undefined && elaborated.ownedTagDecl?.id) { + result.targetId = groupifyId(location, elaborated.ownedTagDecl?.id); + } + + const commentText = single(decl.inner, (attr => attr.kind === 'FullComment')); + + if (commentText) { + const commentData = parseComment(`typedef:${decl.name}`, location, commentText, options); + result = { ...result, ...commentData }; + } + + if (isFunctionPointer(result.type)) { + resolveFunctionPointerTypedef(location, result); + } + + return result; +} + +function parseStruct(location, decl, options) { + let result = { + kind: 'struct', + id: groupifyId(location, decl.id), + name: decl.name, + referenceName: decl.name ? `struct ${decl.name}` : undefined, + comment: undefined, + members: [ ], + location: {...location} + }; + + for (const member of decl.inner.filter(attr => attr.kind === 'FieldDecl')) { + let memberData = { + 'name': member.name, + 'type': member.type.qualType + }; + + const commentText = single(member.inner, (attr => attr.kind === 'FullComment')); + + if (commentText) { + memberData = {...memberData, ...parseComment(`struct:${decl.name}:member:${member.name}`, location, commentText, options)}; + } + + result.members.push(memberData); + } + + const commentText = single(decl.inner, (attr => attr.kind === 'FullComment')); + + if (commentText) { + const commentData = parseComment(`struct:${decl.name}`, location, commentText, options); + result = { ...result, ...commentData }; + } + + return result; +} + +function newResults() { + return { + all: [ ], + functions: [ ], + enums: [ ], + typedefs: [ ], + structs: [ ], + macros: [ ] + }; +}; + +const returnMap = { }; +const paramMap = { }; + +function simplifyType(givenType) { + let type = givenType; + + if (type.startsWith('const ')) { + type = type.substring(6); + } + + while (type.endsWith('*') && type !== 'void *' && type !== 'char *') { + type = type.substring(0, type.length - 1).trim(); + } + + if (!type.length) { + throw new Error(`invalid type: ${result.returns.extendedType || result.returns.type}`); + } + + return type; +} + +function createAndPush(arr, name, value) { + if (!arr[name]) { + arr[name] = [ ]; + } + + if (arr[name].length && arr[name][arr[name].length - 1] === value) { + return; + } + + arr[name].push(value); +} + +function addReturn(result) { + if (!result.returns) { + return; + } + + let type = simplifyType(result.returns.extendedType?.type || result.returns.type); + + createAndPush(returnMap, type, result.name); +} + +function addParameters(result) { + if (!result.params) { + return; + } + + for (const param of result.params) { + let type = param.extendedType?.type || param.type; + + if (!type && options.strict) { + throw new Error(`parameter ${result.name} erroneously documented when not specified`); + } else if (!type) { + continue; + } + + type = simplifyType(type); + + if (param.direction === 'out') { + createAndPush(returnMap, type, result.name); + } + else { + createAndPush(paramMap, type, result.name); + } + } +} + +function addResult(results, result) { + results[`${result.kind}s`].push(result); + results.all.push(result); + + addReturn(result); + addParameters(result); +} + +function mergeResults(one, two) { + const results = newResults(); + + for (const inst of Object.keys(results)) { + results[inst].push(...one[inst]); + results[inst].push(...two[inst]); + } + + return results; +} + +function getById(results, id) { + ensure("id is set", id !== undefined); + return single(results.all.all, (item => item.id === id), id); +} + +function getByKindAndName(results, kind, name) { + ensure("kind is set", kind !== undefined); + ensure("name is set", name !== undefined); + return single(results.all[`${kind}s`], (item => item.name === name), name); +} + +function getByName(results, name) { + ensure("name is set", name !== undefined); + return single(results.all.all, (item => item.name === name), name); +} + +function isFunctionPointer(type) { + return type.match(/^(?:const )?[A-Za-z0-9_]+\s+\**\(\*/); +} + +function resolveCallbacks(results) { + // expand callback types + for (const fn of results.all.functions) { + for (const param of fn.params || [ ]) { + const typedef = getByName(results, param.type); + + if (typedef === undefined) { + continue; + } + + param.referenceType = typedef.type; + } + } + + for (const struct of results.all.structs) { + for (const member of struct.members) { + const typedef = getByKindAndName(results, 'typedef', member.type); + + if (typedef === undefined) { + continue; + } + + member.referenceType = typedef.type; + } + } +} + +function trimBase(path) { + if (!path) { + return path; + } + + for (const segment of [ 'git2', 'git' ]) { + const base = [ includeBase(path), segment ].join('/'); + + if (path.startsWith(base + '/')) { + return path.substr(base.length + 1); + } + } + + throw new Error(`header path ${path} is not beneath standard root`); +} + +function resolveTypedefs(results) { + for (const typedef of results.all.typedefs) { + let target = typedef.targetId ? getById(results, typedef.targetId) : undefined; + + if (target) { + // update the target's preferred name with the short name + target.referenceName = typedef.name; + + if (target.name === undefined) { + target.name = typedef.name; + } + } + else if (typedef.type.startsWith('struct ')) { + const path = typedef.location.file; + + /* + * See if this is actually a typedef to a declared struct, + * then it is not actually opaque. + */ + if (results.all.structs.filter(fn => fn.name === typedef.name).length > 0) { + typedef.opaque = false; + continue; + } + + opaque = { + kind: 'struct', + id: groupifyId(typedef.location, typedef.id), + name: typedef.name, + referenceName: typedef.type, + opaque: true, + comment: typedef.comment, + location: typedef.location, + group: typedef.group + }; + + addResult(results.files[path], opaque); + addResult(results.all, opaque); + } + else if (isFunctionPointer(typedef.type) || + typedef.type === 'int64_t' || + typedef.type === 'uint64_t') { + // standard types + // TODO : make these a list + } + else { + typedef.kind = 'alias'; + typedef.typedef = true; + } + } +} + +function lastCommentIsGroupDelimiter(decls) { + if (decls[decls.length - 1].inner && + decls[decls.length - 1].inner.length > 0) { + return lastCommentIsGroupDelimiter(decls[decls.length - 1].inner); + } + + if (decls.length >= 2 && + decls[decls.length - 1].kind.endsWith('Comment') && + decls[decls.length - 2].kind.endsWith('Comment') && + decls[decls.length - 2].text === '@' && + decls[decls.length - 1].text === '{') { + return true; + } + + return false; +} + +async function parseAst(decls, options) { + const location = { + file: undefined, + line: undefined, + column: undefined + }; + + const results = newResults(); + + /* The first decl might have picked up the javadoc _for the file + * itself_ based on the file's structure. Remove it. + */ + if (decls.length && decls[0].inner && + decls[0].inner.length > 0 && + decls[0].inner[0].kind === 'FullComment' && + lastCommentIsGroupDelimiter(decls[0].inner[0].inner)) { + updateLocation(location, decls[0]); + delete decls[0].inner[0]; + } + + for (const decl of decls) { + updateLocation(location, decl); + + ensureDefined('kind', decl.kind); + + if (decl.kind === 'FunctionDecl') { + addResult(results, await parseFunction({...location}, decl, options)); + } + else if (decl.kind === 'EnumDecl') { + addResult(results, parseEnum({...location}, decl, options)); + } + else if (decl.kind === 'TypedefDecl') { + addResult(results, parseTypedef({...location}, decl, options)); + } + else if (decl.kind === 'RecordDecl' && decl.tagUsed === 'struct') { + if (decl.completeDefinition) { + addResult(results, parseStruct({...location}, decl, options)); + } + } + else if (decl.kind === 'VarDecl') { + if (options.strict) { + throw new Error(`unsupported variable declaration ${decl.kind}`); + } + } + else { + throw new Error(`unknown declaration type ${decl.kind}`); + } + } + + return results; +} + +function parseCommentForMacro(lines, macroIdx, name) { + let startIdx = -1, endIdx = 0; + const commentLines = [ ]; + + while (macroIdx > 0 && + (line = lines[macroIdx - 1].trim()) && + (line.trim() === '' || + line.trim().endsWith('\\') || + line.trim().match(/^#\s*if\s+/) || + line.trim().startsWith('#ifdef ') || + line.trim().startsWith('#ifndef ') || + line.trim().startsWith('#elif ') || + line.trim().startsWith('#else ') || + line.trim().match(/^#\s*define\s+${name}\s+/))) { + macroIdx--; + } + + if (macroIdx > 0 && lines[macroIdx - 1].trim().endsWith('*/')) { + endIdx = macroIdx - 1; + } else { + return ''; + } + + for (let i = endIdx; i >= 0; i--) { + if (lines[i].trim().startsWith('/**')) { + startIdx = i; + break; + } + else if (lines[i].trim().startsWith('/*')) { + break; + } + } + + if (startIdx < 0) { + return ''; + } + + for (let i = startIdx; i <= endIdx; i++) { + let line = lines[i].trim(); + + if (i == startIdx) { + line = line.replace(/^\s*\/\*\*\s*/, ''); + } + + if (i === endIdx) { + line = line.replace(/\s*\*\/\s*$/, ''); + } + + if (i != startIdx) { + line = line.replace(/^\s*\*\s*/, ''); + } + + if (i == startIdx && (line === '@{' || line.startsWith("@{ "))) { + return ''; + } + + if (line === '') { + continue; + } + + commentLines.push(line); + } + + return commentLines.join(' '); +} + +async function parseInfo(data) { + const fileHeader = data.match(/(.*)\n+GIT_BEGIN_DECL.*/s); + const headerLines = fileHeader ? fileHeader[1].split(/\n/) : [ ]; + + let lines = [ ]; + const detailsLines = [ ]; + + let summary = undefined; + let endIdx = headerLines.length - 1; + + for (let i = headerLines.length - 1; i >= 0; i--) { + let line = headerLines[i].trim(); + + if (line.match(/^\s*\*\/\s*$/)) { + endIdx = i; + } + + if (line.match(/^\/\*\*(\s+.*)?$/)) { + lines = headerLines.slice(i + 1, endIdx); + break; + } + else if (line.match(/^\/\*(\s+.*)?$/)) { + break; + } + } + + for (let line of lines) { + line = line.replace(/^\s\*/, ''); + line = line.trim(); + + const comment = line.match(/^\@(\w+|{)\s*(.*)/); + + if (comment) { + if (comment[1] === 'brief') { + summary = comment[2]; + } + } + else if (line != '') { + detailsLines.push(line); + } + } + + const details = detailsLines.length > 0 ? detailsLines.join("\n") : undefined; + + return { + 'summary': summary, + 'details': details + }; +} + +async function parseMacros(path, data, options) { + const results = newResults(); + const lines = data.split(/\r?\n/); + + const macros = { }; + + for (let i = 0; i < lines.length; i++) { + const macro = lines[i].match(/^(\s*#\s*define\s+)([^\s\(]+)(\([^\)]+\))?\s*(.*)/); + let more = false; + + if (!macro) { + continue; + } + + let [ , prefix, name, args, value ] = macro; + + if (name.startsWith('INCLUDE_') || name.startsWith('_INCLUDE_')) { + continue; + } + + if (args) { + name = name + args; + } + + if (macros[name]) { + continue; + } + + macros[name] = true; + + value = value.trim(); + + if (value.endsWith('\\')) { + value = value.substring(0, value.length - 1).trim(); + more = true; + } + + while (more) { + more = false; + + let line = lines[++i]; + + if (line.endsWith('\\')) { + line = line.substring(0, line.length - 1); + more = true; + } + + value += ' ' + line.trim(); + } + + const comment = parseCommentForMacro(lines, i, name); + const location = { + file: path, + line: i + 1, + column: prefix.length + 1, + }; + + if (options.strict && !comment) { + throw new ParserError(`no comment for ${name}`, location); + } + + addResult(results, { + kind: 'macro', + name: name, + location: location, + value: value, + comment: comment, + }); + } + + return results; +} + +function resolveUngroupedTypes(results) { + const groups = { }; + + for (const result of results.all.all) { + result.group = result.location.file; + + if (result.group.endsWith('.h')) { + result.group = result.group.substring(0, result.group.length - 2); + groups[result.group] = true; + } + } + + for (const result of results.all.all) { + if (result.location.file === 'types.h' && + result.name.startsWith('git_')) { + let possibleGroup = result.name.substring(4); + + do { + if (groupMap[possibleGroup]) { + result.group = groupMap[possibleGroup]; + break; + } + else if (groups[possibleGroup]) { + result.group = possibleGroup; + break; + } + else if (groups[`sys/${possibleGroup}`]) { + result.group = `sys/${possibleGroup}`; + break; + } + + let match = possibleGroup.match(/^(.*)_[^_]+$/); + + if (!match) { + break; + } + + possibleGroup = match[1]; + } while (true); + } + } +} + +function resolveReturns(results) { + for (const result of results.all.all) { + result.returnedBy = returnMap[result.name]; + } +} + +function resolveParameters(results) { + for (const result of results.all.all) { + result.parameterTo = paramMap[result.name]; + } +} + +async function parseHeaders(sourcePath, options) { + const results = { all: newResults(), files: { } }; + + for (const fullPath of await headerPaths(sourcePath)) { + const path = trimPath(sourcePath, fullPath); + const fileContents = await readFile(fullPath); + + const ast = await parseAst(await readAst(fullPath, options), options); + const macros = await parseMacros(path, fileContents, options); + const info = await parseInfo(fileContents); + + const filedata = mergeResults(ast, macros); + + filedata['info'] = info; + + results.files[path] = filedata; + results.all = mergeResults(results.all, filedata); + } + + resolveCallbacks(results); + resolveTypedefs(results); + + resolveUngroupedTypes(results); + + resolveReturns(results); + resolveParameters(results); + + return results; +} + +function isFunctionPointer(type) { + return type.match(/^(const\s+)?[A-Za-z0-9_]+\s+\*?\(\*/); +} +function isEnum(type) { + return type.match(/^enum\s+/); +} +function isStruct(type) { + return type.match(/^struct\s+/); +} + +/* + * We keep the `all` arrays around so that we can lookup; drop them + * for the end result. + */ +function simplify(results) { + const simplified = { + 'info': { }, + 'groups': { } + }; + + results.all.all.sort((a, b) => { + if (!a.group) { + throw new Error(`missing group for api ${a.name}`); + } + + if (!b.group) { + throw new Error(`missing group for api ${b.name}`); + } + + const aSystem = a.group.startsWith('sys/'); + const aName = aSystem ? a.group.substr(4) : a.group; + + const bSystem = b.group.startsWith('sys/'); + const bName = bSystem ? b.group.substr(4) : b.group; + + if (aName !== bName) { + return aName.localeCompare(bName); + } + + if (aSystem !== bSystem) { + return aSystem ? 1 : -1; + } + + if (a.location.file !== b.location.file) { + return a.location.file.localeCompare(b.location.file); + } + + if (a.location.line !== b.location.line) { + return a.location.line - b.location.line; + } + + return a.location.column - b.location.column; + }); + + for (const api of results.all.all) { + delete api.id; + delete api.targetId; + + const type = api.referenceType || api.type; + + if (api.kind === 'typedef' && isFunctionPointer(type)) { + api.kind = 'callback'; + api.typedef = true; + } + else if (api.kind === 'typedef' && (!isEnum(type) && !isStruct(type))) { + api.kind = 'alias'; + api.typedef = true; + } + else if (api.kind === 'typedef') { + continue; + } + + if (apiIgnoreList.includes(api.name)) { + continue; + } + + // TODO: do a warning where there's a redefinition of a symbol + // There are occasions where we redefine a symbol. First, our + // parser is not smart enough to know #ifdef's around #define's. + // But also we declared `git_email_create_from_diff` twice (in + // email.h and sys/email.h) for several releases. + + if (!simplified['groups'][api.group]) { + simplified['groups'][api.group] = { }; + simplified['groups'][api.group].apis = { }; + simplified['groups'][api.group].info = results.files[`${api.group}.h`].info; + } + + simplified['groups'][api.group].apis[api.name] = api; + } + + return simplified; +} + +function joinArguments(next, previous) { + if (previous) { + return [...previous, next]; + } + return [next]; +} + +async function findIncludes() { + const includes = [ ]; + + for (const possible of defaultIncludes) { + const includeFile = `${docsPath}/include/git2/${possible}`; + + try { + await fs.stat(includeFile); + includes.push(`git2/${possible}`); + } + catch (e) { + if (e?.code !== 'ENOENT') { + throw e; + } + } + } + + return includes; +} + +async function execGit(path, command) { + const process = child_process.spawn('git', command, { cwd: path }); + const chunks = [ ]; + + return new Promise((resolve, reject) => { + process.stdout.on('data', (chunk) => { + chunks.push(chunk); + }); + process.on('close', (code) => { + resolve(code == 0 ? Buffer.concat(chunks).toString() : undefined); + }); + process.on('error', function (err) { + reject(err); + }); + }); +} + +async function readMetadata(path) { + let commit = await execGit(path, [ 'rev-parse', 'HEAD' ]); + + if (commit) { + commit = commit.trimEnd(); + } + + let version = await execGit(path, [ 'describe', '--tags', '--exact' ]); + + if (!version) { + const ref = await execGit(path, [ 'describe', '--all', '--exact' ]); + + if (ref && ref.startsWith('heads/')) { + version = ref.substr(6); + } + } + + if (version) { + version = version.trimEnd(); + } + + return { + 'version': version, + 'commit': commit + }; +} + +program.option('--output ') + .option('--include ', undefined, joinArguments) + .option('--no-includes') + .option('--deprecate-hard') + .option('--strict'); +program.parse(); + +const options = program.opts(); + +if (program.args.length != 1) { + console.error(`usage: ${path.basename(process.argv[1])} docs`); + process.exit(1); +} + +const docsPath = program.args[0]; + +if (options['include'] && !options['includes']) { + console.error(`usage: cannot combined --include with --no-include`); + process.exit(1); +} + +(async () => { + try { + if (options['include']) { + includes = options['include']; + } + else if (!options['includes']) { + includes = [ ]; + } + else { + includes = await findIncludes(); + } + + const parseOptions = { + deprecateHard: options.deprecateHard || false, + includeFiles: includes, + strict: options.strict || false + }; + + const results = await parseHeaders(docsPath, parseOptions); + const metadata = await readMetadata(docsPath); + + const simplified = simplify(results); + simplified['info'] = metadata; + + console.log(JSON.stringify(simplified, null, 2)); + } catch (e) { + console.error(e); + process.exit(1); + } +})(); diff --git a/script/api-docs/docs-generator.js b/script/api-docs/docs-generator.js new file mode 100755 index 00000000000..5be9e1d20b3 --- /dev/null +++ b/script/api-docs/docs-generator.js @@ -0,0 +1,1326 @@ +#!/usr/bin/env node + +const markdownit = require('markdown-it'); +const { program } = require('commander'); + +const path = require('node:path'); +const fs = require('node:fs/promises'); +const process = require('node:process'); + +const githubPath = 'https://github.com/libgit2/libgit2'; + +const linkPrefix = '/docs/reference'; + +const projectTitle = 'libgit2'; +const includePath = 'include/git2'; + +const fileDenylist = [ 'stdint.h' ]; +const showVersions = true; + +const defaultBranch = 'main'; + +const markdown = markdownit(); +const markdownDefaults = { + code_inline: markdown.renderer.rules.code_inline +}; +markdown.renderer.rules.code_inline = (tokens, idx, options, env, self) => { + const version = env.__version || defaultBranch; + + const code = tokens[idx].content; + const text = `${nowrap(sanitize(tokens[idx].content))}`; + const link = linkForCode(version, code, text); + + return link ? link : text; +}; + +// globals +const apiData = { }; +const versions = [ ]; +const versionDeltas = { }; + +function produceVersionPicker(version, classes, cb) { + let content = ""; + + if (!showVersions) { + return content; + } + + content += `

    \n`; + content += ` Version:\n`; + content += ` \n`; + + content += `
    \n`; + + return content; +} + +function produceBreadcrumb(version, api, type) { + let content = ""; + let group = api.group; + let sys = false; + + if (group.endsWith('.h')) { + group = group.substr(0, group.length - 2); + } + + let groupTitle = group; + + if (groupTitle.startsWith('sys/')) { + groupTitle = groupTitle.substr(4); + groupTitle += ' (advanced)'; + } + + content += `
    \n`; + content += ` \n`; + content += `
    \n`; + + return content; +} + +function produceHeader(version, api, type) { + let content = ""; + + content += `
    \n`; + content += `

    ${api.name}

    \n`; + + content += produceAttributes(version, api, type); + + content += produceVersionPicker(version, + `apiHeaderVersionSelect ${type}HeaderVersionSelect`, + (v) => { + const versionedApi = selectApi(v, (i => i.name === api.name)); + return versionedApi ? linkFor(v, versionedApi) : undefined; + }); + + content += `
    \n`; + content += `\n`; + + return content; +} + +function produceAttributes(version, api, type) { + let content = ""; + + if (api.deprecations) { + content += ` Deprecated\n`; + } + + return content; +} + +function produceDescription(version, desc, type) { + let content = ""; + + if (! desc.comment) { + return content; + } + + content += `\n`; + content += `
    \n`; + + for (const para of Array.isArray(desc.comment) ? desc.comment : [ desc.comment ]) { + content += ` ${markdown.render(para, { __version: version })}\n`; + } + + content += `
    \n`; + + return content; +} + +function produceList(version, api, type, listType) { + let content = ""; + + if (!api[listType]) { + return content; + } + + const listTypeUpper = listType.charAt(0).toUpperCase() + listType.slice(1); + const listTypeTitle = listTypeUpper.replaceAll(/(.)([A-Z])/g, (match, one, two) => { return one + ' ' + two; }); + + content += `\n`; + content += `

    ${listTypeTitle}

    \n`; + + content += `
    \n`; + content += `
      \n`; + + for (const item of api[listType]) { + content += `
    • \n`; + content += ` ${linkText(version, item)}\n`; + content += `
    • \n`; + } + + content += `
    \n`; + content += `
    \n`; + + return content; +} + +function produceNotes(version, api, type) { + return produceList(version, api, type, 'notes'); +} + +function produceSeeAlso(version, api, type) { + return produceList(version, api, type, 'deprecated'); +} + +function produceSeeAlso(version, api, type) { + return produceList(version, api, type, 'see'); +} + +function produceWarnings(version, api, type) { + return produceList(version, api, type, 'warnings'); +} + +function produceDeprecations(version, api, type) { + return produceList(version, api, type, 'deprecations'); +} + +function produceGitHubLink(version, api, type) { + if (!api || !api.location || !api.location.file) { + return undefined; + } + + let file = api.location.file; + + let link = githubPath + '/blob/' + version + '/' + includePath + '/' + file; + + if (api.location.line) { + link += '#L' + api.location.line; + } + + return link; +} + +function produceSignatureForFunction(version, api, type) { + let content = ""; + let paramCount = 0; + + let prefix = type === 'callback' ? 'typedef' : ''; + const returnType = api.returns?.type || 'int'; + + const githubLink = produceGitHubLink(version, api, type); + + content += `\n`; + + content += `

    Signature

    \n`; + + if (githubLink) { + content += ` \n`; + } + + content += `
    \n`; + + content += ` ${prefix ? prefix + ' ' : ''}${returnType}`; + content += returnType.endsWith('*') ? '' : ' '; + content += `${api.name}(`; + + for (const param of api.params || [ ]) { + content += (paramCount++ > 0) ? ', ' : ''; + + if (!param.type && options.strict) { + throw new Error(`param ${param.name} has no type for function ${api.name}`); + } + else if (!param.type) { + continue; + } + + content += ``; + content += `${param.type}`; + content += param.type.endsWith('*') ? '' : ' '; + + if (param.name) { + content += `${param.name}`; + } + + content += ``; + } + + content += `);\n`; + content += `
    \n`; + + return content; +} + +function produceFunctionParameters(version, api, type) { + let content = ""; + + if (!api.params || api.params.length == 0) { + return content; + } + + content += `\n`; + + content += `

    Parameters

    \n`; + content += `
    \n`; + + for (const param of api.params) { + let direction = param.direction || 'in'; + direction = direction.charAt(0).toUpperCase() + direction.slice(1); + + if (!param.type && options.strict) { + throw new Error(`param ${param.name} has no type for function ${api.name}`); + } + else if (!param.type) { + continue; + } + + content += `
    \n`; + content += `
    \n`; + content += ` ${linkType(version, param.type)}\n`; + content += `
    \n`; + + if (param.extendedType) { + content += `
    \n`; + content += ` ${linkType(version, param.extendedType.type)}\n`; + content += `
    \n`; + } + + content += `
    \n`; + + content += ` ${direction}\n`; + content += `
    \n`; + + if (param.name) { + content += `
    \n`; + content += ` ${param.name}\n`; + content += `
    \n`; + } + + content += `
    \n`; + content += ` ${render(version, param.comment)}\n`; + content += `
    \n`; + content += `
    \n`; + } + + content += `
    \n`; + + return content; +} + +function produceFunctionReturn(version, api, type) { + let content = ""; + + if (api.returns && api.returns.type && api.returns.type !== 'void') { + content += `\n`; + content += `

    Returns

    \n`; + content += `
    \n`; + content += `
    \n`; + content += ` ${linkType(version, api.returns.type)}\n`; + content += `
    \n`; + content += `
    \n`; + content += ` ${render(version, api.returns.comment)}\n`; + content += `
    \n`; + content += `
    \n`; + } + + return content; +} + +function produceSignatureForObject(version, api, type) { + let content = ""; + + const githubLink = produceGitHubLink(version, api, type); + + content += `\n`; + + content += `

    Signature

    \n`; + + if (githubLink) { + content += ` \n`; + } + + content += `
    \n`; + content += ` typedef ${api.referenceName} ${api.name}\n`; + content += `
    \n`; + + return content; +} + +function produceSignatureForStruct(version, api, type) { + let content = ""; + + const githubLink = produceGitHubLink(version, api, type); + + content += `\n`; + + content += `

    Signature

    \n`; + + if (githubLink) { + content += ` \n`; + } + + const typedef = api.name.startsWith('struct') ? '' : 'typedef '; + + content += `
    \n`; + content += ` ${typedef}struct ${api.name} {\n`; + + for (const member of api.members || [ ]) { + content += ``; + content += `${member.type}`; + content += member.type.endsWith('*') ? '' : ' '; + + if (member.name) { + content += `${member.name}`; + } + + content += `\n`; + } + + content += ` };\n`; + content += `
    \n`; + + return content; +} + +function isOctalEnum(version, api, type) { + return api.name === 'git_filemode_t'; +} + +function isFlagsEnum(version, api, type) { + // TODO: also handle the flags metadata instead of always just guessing + if (type !== 'enum') { + return false; + } + + let largest = 0; + + for (const member of api.members) { + if (member.value === undefined) { + return false; + } + + if (member.value && (member.value & (member.value - 1))) { + return false; + } + + largest = member.value; + } + + return (largest > 1); +} + +function flagsOctal(v) { + const n = parseInt(v); + return n ? `0${n.toString(8)}` : 0; +} + +function flagsValue(v) { + if (v === '0') { + return '0'; + } + + return `(1 << ${Math.log2(v)})`; +} + +function produceMembers(version, api, type) { + let content = ""; + let value = 0; + + if (!api.members || api.members.length == 0) { + return ""; + } + + let title = type === 'enum' ? 'Values' : 'Members'; + const isOctal = isOctalEnum(version, api, type); + const isFlags = isFlagsEnum(version, api, type); + + content += `\n`; + + content += `

    ${title}

    \n`; + + const githubLink = api.kind === 'struct' ? undefined : produceGitHubLink(version, api, type); + + if (githubLink) { + content += ` \n`; + } + + content += `
    \n`; + + for (const member of api.members) { + value = member.value ? member.value : value; + + content += `
    \n`; + + if (type === 'struct') { + content += `
    \n`; + content += ` ${linkType(version, member.type)}\n`; + content += `
    \n`; + } + + content += `
    \n`; + content += ` ${member.name}\n`; + content += `
    \n`; + + if (type === 'enum') { + const enumValue = isOctal ? flagsOctal(value) : (isFlags ? flagsValue(value) : value); + + content += `
    \n`; + content += ` ${enumValue}\n`; + content += `
    \n`; + } + + content += `
    \n`; + content += ` ${render(version, member.comment)}\n`; + content += `
    \n`; + content += `
    \n`; + + value++; + } + + content += `
    \n`; + + return content; +} + +function produceReturnedBy(version, api, type) { + return produceList(version, api, type, 'returnedBy'); +} + +function produceParameterTo(version, api, type) { + return produceList(version, api, type, 'parameterTo'); +} + +function produceVersionDeltas(version, api, type) { + let content = ''; + + if (!showVersions) { + return content; + } + + const deltas = versionDeltas[api.name]; + if (!deltas) { + throw new Error(`no version information for ${api.kind} ${api.name}`); + } + + content += `

    Versions

    \n`; + content += `
    \n`; + content += `
      \n`; + + for (const idx in deltas) { + const item = deltas[idx]; + + if (idx == deltas.length - 1) { + content += `
    • \n`; + } else if (item.changed) { + content += `
    • \n`; + } else { + content += `
    • \n`; + } + + content += ` ${item.version}\n`; + content += `
    • \n`; + } + + content += `
    \n`; + content += `
    \n`; + + return content; +} + +async function layout(data) { + let layout; + + if (options.layout) { + layout = await fs.readFile(options.layout); + } + else if (options.jekyllLayout) { + layout = `---\ntitle: {{title}}\nlayout: ${options.jekyllLayout}\n---\n\n{{content}}`; + } + else { + return data.content; + } + + return layout.toString().replaceAll(/{{([a-z]+)}}/g, (match, p1) => data[p1] || ""); +} + +async function produceDocumentationForApi(version, api, type) { + let content = ""; + + content += `
    \n`; + + content += produceBreadcrumb(version, api, type); + content += produceHeader(version, api, type); + content += produceDescription(version, api, type); + content += produceNotes(version, api, type); + content += produceDeprecations(version, api, type); + content += produceSeeAlso(version, api, type); + content += produceWarnings(version, api, type); + content += produceSignature(version, api, type); + content += produceMembers(version, api, type); + content += produceFunctionParameters(version, api, type); + content += produceFunctionReturn(version, api, type); + content += produceReturnedBy(version, api, type); + content += produceParameterTo(version, api, type); + content += produceVersionDeltas(version, api, type); + + content += `
    \n`; + + + const name = (type === 'macro' && api.name.includes('(')) ? + api.name.replace(/\(.*/, '') : api.name; + + const groupDir = `${outputPath}/${version}/${api.group}`; + const filename = `${groupDir}/${name}.html`; + + await fs.mkdir(groupDir, { recursive: true }); + await fs.writeFile(filename, await layout({ + title: `${api.name} (${projectTitle} ${version})`, + content: content + })); +} + +function selectApi(version, cb) { + const allApis = allApisForVersion(version, apiData[version]['groups']); + + for (const name in allApis) { + const api = allApis[name]; + + if (cb(api)) { + return api; + } + } + + return undefined; +} + +function apiFor(version, type) { + return selectApi(version, ((api) => api.name === type)); +} + +function linkFor(version, api) { + const name = (api.kind === 'macro' && api.name.includes('(')) ? + api.name.replace(/\(.*/, '') : api.name; + + return `${linkPrefix}/${version}/${api.group}/${name}.html`; +} + +function linkForCode(version, code, text) { + let api = selectApi(version, ((api) => api.name === code)); + let valueDecl = undefined; + + const apisForVersion = allApisForVersion(version, apiData[version]['groups']); + + if (!api) { + for (const enumDecl of Object.values(apisForVersion).filter(api => api.kind === 'enum')) { + const member = enumDecl.members.filter((m) => m.name === code); + + if (member && member[0]) { + api = enumDecl; + valueDecl = member[0]; + break; + } + } + } + + if (!api) { + return undefined; + } + + const kind = internalKind(version, api); + let link = linkFor(version, api); + + if (valueDecl) { + link += `#${valueDecl.name}`; + } + + if (!text) { + text = `${sanitize(code)}`; + } + + return `${text}`; +} + +function linkType(version, given) { + let type = given; + + if ((content = given.match(/^(?:const\s+)?([A-Za-z0-9_]+)(?:\s+\*+)?/))) { + type = content[1]; + } + + const api = apiFor(version, type); + + if (api) { + return `${given}`; + } + + return given; +} + +function linkText(version, str) { + const api = apiFor(version, str); + + if (api) { + return `${str}`; + } + + return sanitize(str); +} + +function render(version, str) { + let content = [ ]; + + if (!str) { + return ''; + } + + for (const s of Array.isArray(str) ? str : [ str ] ) { + content.push(markdown.render(s, { __version: version }).replaceAll(/\s+/g, ' ')); + } + + return content.join(' '); +} + +function nowrap(text) { + text = text.replaceAll(' ', ' '); + text = `${text}`; + return text; +} + +function sanitize(str) { + let content = [ ]; + + if (!str) { + return ''; + } + + for (const s of Array.isArray(str) ? str : [ str ] ) { + content.push(s.replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('{', '{') + .replaceAll('}', '}')); + } + + return content.join(' '); +} + +function produceSignatureForAlias(version, api, type) { + let content = ""; + + const githubLink = produceGitHubLink(version, api, type); + + content += `

    Signature

    \n`; + + if (githubLink) { + content += ` \n`; + } + + content += `
    \n`; + content += ` typedef ${api.name} ${api.type};`; + content += `
    \n`; + + return content; +} + +function produceSignatureForMacro(version, api, type) { + let content = ""; + + const githubLink = produceGitHubLink(version, api, type); + + content += `

    Signature

    \n`; + + if (githubLink) { + content += ` \n`; + } + + content += `
    \n`; + content += ` #define ${api.name} ${sanitize(api.value)}`; + content += `
    \n`; + + return content; +} + +function produceSignature(version, api, type) { + if (type === 'macro') { + return produceSignatureForMacro(version, api, type); + } + else if (type === 'alias') { + return produceSignatureForAlias(version, api, type); + } + else if (type === 'function' || type === 'callback') { + return produceSignatureForFunction(version, api, type); + } + else if (type === 'object') { + return produceSignatureForObject(version, api, type); + } + else if (type === 'struct') { + return produceSignatureForStruct(version, api, type); + } + else if (type === 'struct' || type === 'enum') { + return ""; + } + else { + throw new Error(`unknown type: ${api.kind}`); + } +} + +function isFunctionPointer(type) { + return type.match(/^(const\s+)?[A-Za-z0-9_]+\s+\*?\(\*/); +} + +function isEnum(type) { + return type.match(/^enum\s+/); +} + +function isStruct(type) { + return type.match(/^struct\s+/); +} + +function internalKind(version, api) { + if (api.kind === 'struct' && api.opaque) { + return 'object'; + } + + return api.kind; +} + +function externalKind(kind) { + if (kind === 'object') { + return 'struct'; + } + + return kind; +} + +async function produceIndexForGroup(version, group, versionApis) { + let content = ""; + + if (versionApis['groups'][group].apis.length == 0) { + return; + } + + const apis = Object.values(versionApis['groups'][group].apis); + + let fileName = group; + if (fileName.endsWith('.h')) { + fileName = fileName.substr(0, fileName.length - 2); + } + + const system = fileName.startsWith('sys/'); + let groupName = system ? fileName.substr(4) : fileName; + + content += `
    \n`; + + content += `
    \n`; + content += ` \n`; + content += `
    \n`; + + content += `
    \n`; + content += `

    ${groupName}

    \n`; + + content += produceVersionPicker(version, "groupHeaderVersionSelect", (v) => { + if (apiData[v]['groups'][group]) { + return `${linkPrefix}/${v}/${groupName}/index.html`; + } + return undefined; + }); + + content += `
    \n`; + + let details = undefined; + + if (versionApis['groups'][group].info?.details) { + details = markdown.render(versionApis['groups'][group].info.details, { __version: version }); + } else if (versionApis['groups'][group].info?.summary) { + details = versionApis['groups'][group].info.summary; + } + + if (details) { + content += `
    \n`; + content += ` ${details}\n`; + content += `
    \n`; + } + + for (const kind of [ 'object', 'struct', 'macro', 'enum', 'callback', 'alias', 'function' ]) { + content += produceIndexForApiKind(version, apis.filter(api => { + if (kind === 'object') { + return api.kind === 'struct' && api.opaque; + } + else if (kind === 'struct') { + return api.kind === 'struct' && !api.opaque; + } + else { + return api.kind === kind; + } + }), kind); + } + + content += `
    \n`; + + const groupsDir = `${outputPath}/${version}/${fileName}`; + const filename = `${groupsDir}/index.html`; + + await fs.mkdir(groupsDir, { recursive: true }); + await fs.writeFile(filename, await layout({ + title: `${groupName} APIs (${projectTitle} ${version})`, + content: content + })); +} + +async function produceDocumentationForApis(version, apiData) { + const apis = allApisForVersion(version, apiData['groups']); + + for (const func of Object.values(apis).filter(api => api.kind === 'function')) { + await produceDocumentationForApi(version, func, 'function'); + } + + for (const struct of Object.values(apis).filter(api => api.kind === 'struct')) { + await produceDocumentationForApi(version, struct, internalKind(version, struct)); + } + + for (const e of Object.values(apis).filter(api => api.kind === 'enum')) { + await produceDocumentationForApi(version, e, 'enum'); + } + + for (const callback of Object.values(apis).filter(api => api.kind === 'callback')) { + await produceDocumentationForApi(version, callback, 'callback'); + } + + for (const alias of Object.values(apis).filter(api => api.kind === 'alias')) { + await produceDocumentationForApi(version, alias, 'alias'); + } + + for (const macro of Object.values(apis).filter(api => api.kind === 'macro')) { + await produceDocumentationForApi(version, macro, 'macro'); + } +} + +function produceIndexForApiKind(version, apis, kind) { + let content = ""; + + if (!apis || !apis.length) { + return content; + } + + let kindUpper = kind.charAt(0).toUpperCase() + kind.slice(1); + kindUpper += (kind === 'alias') ? 'es' : 's'; + + content += `\n`; + content += `

    ${kindUpper}

    \n`; + + content += `
    \n`; + + for (const item of apis) { + if (item.changed) { + content += `
    \n`; + } else { + content += `
    \n`; + } + + content += `
    \n`; + content += ` \n`; + content += ` ${item.name}\n`; + content += ` \n`; + content += `
    \n`; + + let shortComment = Array.isArray(item.comment) ? item.comment[0] : item.comment; + shortComment = shortComment || ''; + + shortComment = shortComment.replace(/\..*/, ''); + + content += `
    \n`; + content += ` ${render(version, shortComment)}\n`; + content += `
    \n`; + content += `
    \n`; + } + + content += `
    \n`; + + return content; +} + +function versionIndexContent(version, apiData) { + let content = ""; + let hasSystem = false; + + content += `
    \n`; + content += `
    \n`; + content += `

    ${projectTitle} ${version}

    \n`; + + content += produceVersionPicker(version, "versionHeaderVersionSelect", + (v) => `${linkPrefix}/${v}/index.html`); + + content += `
    \n`; + + content += `\n`; + content += `

    Groups

    \n`; + content += `
      \n`; + + for (const group of Object.keys(apiData['groups']).sort((a, b) => { + if (a.startsWith('sys/')) { return 1; } + if (b.startsWith('sys/')) { return -1; } + return a.localeCompare(b); + }).map(fn => { + let n = fn; + let sys = false; + + if (n.endsWith('.h')) { + n = n.substr(0, n.length - 2); + } + + if (n.startsWith('sys/')) { + n = n.substr(4); + sys = true; + } + + return { + name: n, filename: fn, system: sys, info: apiData['groups'][fn].info, apis: apiData['groups'][fn] + }; + }).filter(filedata => { + return Object.keys(filedata.apis).length > 0 && !fileDenylist.includes(filedata.filename); + })) { + if (group.system && !hasSystem) { + hasSystem = true; + + content += `
    \n`; + content += `\n`; + content += `

    System Groups (Advanced)

    \n`; + content += `
      \n`; + } + + let link = `${linkPrefix}/${version}/`; + link += group.system ? `sys/` : ''; + link += group.name; + link += `/index.html`; + + content += `
    • \n`; + content += `
      \n`; + content += ` \n`; + content += ` ${group.name}\n`; + content += ` \n`; + content += `
      \n`; + + if (group.info?.summary) { + content += `
      \n`; + content += ` ${group.info.summary}`; + content += `
      \n`; + } + + content += `
    • \n`; + } + + content += `
    \n`; + + content += `
    \n`; + + return content; +} + +async function produceDocumentationIndex(version, apiData) { + const content = versionIndexContent(version, apiData); + + const versionDir = `${outputPath}/${version}`; + const filename = `${versionDir}/index.html`; + + await fs.mkdir(versionDir, { recursive: true }); + await fs.writeFile(filename, await layout({ + title: `APIs (${projectTitle} ${version})`, + content: content + })); +} + +async function documentationIsUpToDateForVersion(version, apiData) { + try { + const existingMetadata = JSON.parse(await fs.readFile(`${outputPath}/${version}/.metadata`)); + return existingMetadata?.commit === apiData.info.commit; + } + catch (e) { + } + + return false; +} + +async function produceDocumentationMetadata(version, apiData) { + const versionDir = `${outputPath}/${version}`; + const filename = `${versionDir}/.metadata`; + + await fs.mkdir(versionDir, { recursive: true }); + await fs.writeFile(filename, JSON.stringify(apiData.info, null, 2) + "\n"); +} + +async function produceDocumentationForVersion(version, apiData) { + if (!options.force && await documentationIsUpToDateForVersion(version, apiData)) { + if (options.verbose) { + console.log(`Documentation exists for ${version} at version ${apiData.info.commit.substr(0, 7)}; skipping...`); + } + + return; + } + + if (options.verbose) { + console.log(`Producing documentation for ${version}...`); + } + + await produceDocumentationForApis(version, apiData); + + for (const group in apiData['groups']) { + await produceIndexForGroup(version, group, apiData); + } + + await produceDocumentationIndex(version, apiData); + + await produceDocumentationMetadata(version, apiData); +} + +function versionDeltaData(version, api) { + const base = { version: version, api: api }; + + if (api.kind === 'function') { + return { + ...base, + returns: api.returns?.type || 'int', + params: api.params?.map((p) => p.type) || [ 'void' ] + }; + } + else if (api.kind === 'enum') { + return { + ...base, + members: api.members?.map((m) => { return { 'name': m.name, 'value': m.value } }) + }; + } + else if (api.kind === 'callback') { + return { ...base, }; + } + else if (api.kind === 'alias') { + return { ...base, }; + } + else if (api.kind === 'struct') { + return { + ...base, + members: api.members?.map((m) => { return { 'name': m.name, 'type': m.type } }) + }; + } + else if (api.kind === 'macro') { + return { + ...base, + name: api.name, + value: api.value + }; + } + else { + throw new Error(`unknown api kind: '${api.kind}'`); + } +} + +function deltasEqual(a, b) { + const unversionedA = { ...a }; + const unversionedB = { ...b }; + + delete unversionedA.version; + delete unversionedA.api; + delete unversionedA.changed; + delete unversionedB.version; + delete unversionedB.api; + delete unversionedB.changed; + + return JSON.stringify(unversionedA) === JSON.stringify(unversionedB); +} + +const apiForVersionCache = { }; +function allApisForVersion(version, apiData) { + if (apiForVersionCache[version]) { + return apiForVersionCache[version]; + } + + let result = { }; + for (const file in apiData['groups']) { + result = { ...result, ...apiData['groups'][file].apis }; + } + + apiForVersionCache[version] = result; + return result; +} + +function seedVersionApis(apiData) { + for (const version in apiData) { + allApisForVersion(version, apiData[version]); + } +} + +function calculateVersionDeltas(apiData) { + for (const version in apiData) { + const apisForVersion = allApisForVersion(version, apiData[version]); + + for (const api in apisForVersion) { + if (!versionDeltas[api]) { + versionDeltas[api] = [ ]; + } + + versionDeltas[api].push(versionDeltaData(version, apisForVersion[api])); + } + } + + for (const api in versionDeltas) { + const count = versionDeltas[api].length; + + versionDeltas[api][count - 1].changed = true; + + for (let i = count - 2; i >= 0; i--) { + versionDeltas[api][i].changed = !deltasEqual(versionDeltas[api][i], versionDeltas[api][i + 1]); + } + } +} + +async function produceMainIndex(versions) { + const versionList = versions.sort(versionSort); + const versionDefault = versionList[versionList.length - 1]; + + if (options.verbose) { + console.log(`Producing documentation index...`); + } + + let content = ""; + + content += `\n`; + content += `\n`; + + content += versionIndexContent(versionDefault, apiData[versionDefault]); + + const filename = `${outputPath}/index.html`; + + await fs.mkdir(outputPath, { recursive: true }); + await fs.writeFile(filename, await layout({ + title: `APIs (${projectTitle} ${versionDefault})`, + content: content + })); +} + +function versionSort(a, b) { + if (a === b) { + return 0; + } + + const aVersion = a.match(/^v(\d+)(?:\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?(?:-(.*))?$/); + const bVersion = b.match(/^v(\d+)(?:\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?(?:-(.*))?$/); + + if (!aVersion && !bVersion) { + return a.localeCompare(b); + } + else if (aVersion && !bVersion) { + return -1; + } + else if (!aVersion && bVersion) { + return 1; + } + + for (let i = 1; i < 5; i++) { + if (!aVersion[i] && !bVersion[i]) { + break; + } + else if (aVersion[i] && !bVersion[i]) { + return 1; + } + else if (!aVersion[i] && bVersion[i]) { + return -1; + } + else if (aVersion[i] !== bVersion[i]) { + return aVersion[i] - bVersion[i]; + } + } + + if (aVersion[5] && !bVersion[5]) { + return -1; + } + else if (!aVersion[5] && bVersion[5]) { + return 1; + } + else if (aVersion[5] && bVersion[5]) { + return aVersion[5].localeCompare(bVersion[5]); + } + + return 0; +} + +program.option('--output ') + .option('--layout ') + .option('--jekyll-layout ') + .option('--verbose') + .option('--force') + .option('--strict'); +program.parse(); + +const options = program.opts(); + +if (program.args.length != 2) { + console.error(`usage: ${path.basename(process.argv[1])} raw_api_dir output_dir`); + process.exit(1); +} + +const docsPath = program.args[0]; +const outputPath = program.args[1]; + +(async () => { + try { + for (const version of (await fs.readdir(docsPath)) + .filter(a => a.endsWith('.json')) + .map(a => a.replace(/\.json$/, '')) + .sort(versionSort) + .reverse()) { + versions.push(version); + } + + for (const version of versions) { + if (options.verbose) { + console.log(`Reading documentation data for ${version}...`); + } + + apiData[version] = JSON.parse(await fs.readFile(`${docsPath}/${version}.json`)); + } + + if (showVersions) { + if (options.verbose) { + console.log(`Calculating version deltas...`); + } + + calculateVersionDeltas(apiData); + } + + for (const version of versions) { + await produceDocumentationForVersion(version, apiData[version]); + } + + await produceMainIndex(versions); + } catch (e) { + console.error(e); + process.exit(1); + } +})(); diff --git a/script/api-docs/generate b/script/api-docs/generate new file mode 100755 index 00000000000..c103cc19822 --- /dev/null +++ b/script/api-docs/generate @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# +# Usage: generate repo_path output_path +# +# Example: generate https://github.com/libgit2/libgit2 path_to_output +# to clone the repository from GitHub and produce documentation; +# the repo_path can also be a local path + +set -eo pipefail + +source_path=$(mktemp -d) +verbose=true +force= + +if [ "$1" = "" ]; then + echo "usage: $0 repo_path output_path" 1>&2 + exit 1 +fi + +repo_path=$1 +output_path=$2 + +function do_checkout { + if [ "$1" = "" ]; then + echo "usage: $0 source_path" 1>&2 + exit 1 + fi + + if [ "${verbose}" ]; then + echo ":: Checking out source trees..." + echo "" + fi + + source_path=$1 + + mkdir -p "${source_path}" + git clone "${repo_path}" "${source_path}/main" --no-checkout + ( cd "${source_path}/main" && git sparse-checkout set --no-cone 'include/*' ) + ( cd "${source_path}/main" && git read-tree origin/main ) + ( cd "${source_path}/main" && git checkout -- include ) + + for tag in $(git --git-dir="${source_path}/main/.git" tag -l); do + git --git-dir="${source_path}/main/.git" worktree add -f "${source_path}/${tag}" "${tag}" --no-checkout + ( cd "${source_path}/${tag}" && git sparse-checkout set --no-cone 'include/*' ) + ( cd "${source_path}/${tag}" && git read-tree HEAD ) + + if [ "${tag}" == "v0.1.0" ]; then + ( cd "${source_path}/${tag}" && git checkout -- src/git ) + elif [ "${tag}" == "v0.2.0" -o "${tag}" == "v0.3.0" ]; then + ( cd "${source_path}/${tag}" && git checkout -- src/git2 ) + else + ( cd "${source_path}/${tag}" && git checkout -- include ) + fi + done +} + +do_checkout ${source_path} + +if [ "${verbose}" ]; then + echo "" + echo ":: Generating raw API documentation..." + echo "" +fi + +for version in ${source_path}/*; do + version=$(echo "${version}" | sed -e "s/.*\///") + commit=$( cd "${source_path}/${version}" && git rev-parse HEAD ) + + if [ -f "${output_path}/api/${version}.json" ]; then + existing_commit=$(jq -r .info.commit < "${output_path}/api/${version}.json") + + if [ "${existing_commit}" == "${commit}" -a ! "${force}" ]; then + if [ "${verbose}" ]; then + echo "Raw API documentation for ${version} exists; skipping..." + fi + + continue + fi + fi + + options="" + if [ "${force}" ]; then + options="${options} --force" + fi + + echo "Generating raw API documentation for ${version}..." + mkdir -p "${output_path}/api" + node ./api-generator.js $options "${source_path}/${version}" > "${output_path}/api/${version}.json" +done + +if [ "${verbose}" ]; then + echo "" + echo ":: Generating HTML documentation..." + echo "" +fi + +options="" +if [ "${verbose}" ]; then + options="${options} --verbose" +fi +if [ "${force}" ]; then + options="${options} --force" +fi + +node ./docs-generator.js --verbose --jekyll-layout default "${output_path}/api" "${output_path}/reference" diff --git a/script/api-docs/package-lock.json b/script/api-docs/package-lock.json new file mode 100644 index 00000000000..32c4e3b6f4b --- /dev/null +++ b/script/api-docs/package-lock.json @@ -0,0 +1,79 @@ +{ + "name": "_generator", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "commander": "^12.1.0", + "markdown-it": "^14.1.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + } + } +} diff --git a/script/api-docs/package.json b/script/api-docs/package.json new file mode 100644 index 00000000000..53ae0705407 --- /dev/null +++ b/script/api-docs/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "commander": "^12.1.0", + "markdown-it": "^14.1.0" + } +} From 93218006121374844478bdc37927de8e3a275920 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 26 Nov 2024 20:00:15 +0000 Subject: [PATCH 700/816] Update documentation generation workflow Ensure that workflows where the main branch exists (eg, anything except PR workflows) don't try to recreate the main branch. Add a concurrency token so that we don't have conflicts generating documentation. --- .github/workflows/documentation.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index a2e45ca5ff2..9ef44bca791 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -7,6 +7,9 @@ on: release: workflow_dispatch: +concurrency: + group: documentation + permissions: contents: read @@ -29,7 +32,11 @@ jobs: ssh-key: ${{ secrets.DOCS_PUBLISH_KEY }} - name: Prepare branches run: | - for a in main $(git branch -r --list 'origin/maint/*' | sed -e "s/^ origin\///"); do + if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then + git branch --track main origin/main + fi + + for a in $(git branch -r --list 'origin/maint/*' | sed -e "s/^ origin\///"); do git branch --track "$a" "origin/$a" done working-directory: source From 0bd5e479b24f2c8614dd10966e15082d377284b2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 26 Nov 2024 20:47:31 +0000 Subject: [PATCH 701/816] Introduce a "validate only" mode for docs generation The API documentation generation is useful (in `--strict` mode) to determine whether all our APIs have sufficient documentation. Add a `--validate-only` mode that will run the validation without emitting the API JSON. This is useful for ensuring that the documentation is complete. --- script/api-docs/.gitignore | 1 + script/api-docs/api-generator.js | 6 +++++- script/api-docs/package-lock.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 script/api-docs/.gitignore diff --git a/script/api-docs/.gitignore b/script/api-docs/.gitignore new file mode 100644 index 00000000000..c2658d7d1b3 --- /dev/null +++ b/script/api-docs/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/script/api-docs/api-generator.js b/script/api-docs/api-generator.js index fffeb5e9c48..5204f491f0e 100755 --- a/script/api-docs/api-generator.js +++ b/script/api-docs/api-generator.js @@ -63,6 +63,7 @@ async function headerPaths(p) { paths.push(...(await fs.readdir(fullPath)). filter((filename) => filename.endsWith('.h')). filter((filename) => !fileIgnoreList.includes(filename)). + filter((filename) => filename !== 'deprecated.h' || !options.deprecateHard). map((filename) => `${fullPath}/${filename}`)); } @@ -1494,6 +1495,7 @@ program.option('--output ') .option('--include ', undefined, joinArguments) .option('--no-includes') .option('--deprecate-hard') + .option('--validate-only') .option('--strict'); program.parse(); @@ -1535,7 +1537,9 @@ if (options['include'] && !options['includes']) { const simplified = simplify(results); simplified['info'] = metadata; - console.log(JSON.stringify(simplified, null, 2)); + if (!options.validateOnly) { + console.log(JSON.stringify(simplified, null, 2)); + } } catch (e) { console.error(e); process.exit(1); diff --git a/script/api-docs/package-lock.json b/script/api-docs/package-lock.json index 32c4e3b6f4b..bd9ca1a4756 100644 --- a/script/api-docs/package-lock.json +++ b/script/api-docs/package-lock.json @@ -1,5 +1,5 @@ { - "name": "_generator", + "name": "api-docs", "lockfileVersion": 3, "requires": true, "packages": { From 8e516778ceee3be37b7a8cacfd4018b6bbbba658 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 26 Nov 2024 20:46:10 +0000 Subject: [PATCH 702/816] Add CI step to validate documentation changes Run our documentation generator in "validate only" mode to ensure that new changes coming in to the repository have documented our changes fully. --- .github/workflows/main.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d18321f5fb0..3616c743d7e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -233,6 +233,17 @@ jobs: name: test-results-${{ matrix.platform.id }} path: build/results_*.xml + documentation: + name: Validate documentation + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + - name: Validate documentation + run: | + (cd script/api-docs && npm install) + script/api-docs/api-generator.js --validate-only --strict --deprecate-hard . + test_results: name: Test results needs: [ build ] From 5353a2cc20141322e23dfb4b2d1ab82914065e8a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 1 May 2024 21:18:24 +0100 Subject: [PATCH 703/816] reflog: remove unused sys functions The `git_reflog_entry__alloc` function is not actually defined, nor used. Remove references to it in the headers. It is not clear why the corresponding `__free` is, or should be, exported. Make it internal to the library. --- include/git2/sys/reflog.h | 21 --------------------- src/libgit2/refdb_fs.c | 1 - src/libgit2/reflog.c | 1 - src/libgit2/reflog.h | 2 ++ 4 files changed, 2 insertions(+), 23 deletions(-) delete mode 100644 include/git2/sys/reflog.h diff --git a/include/git2/sys/reflog.h b/include/git2/sys/reflog.h deleted file mode 100644 index c9d0041b90f..00000000000 --- a/include/git2/sys/reflog.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_sys_git_reflog_h__ -#define INCLUDE_sys_git_reflog_h__ - -#include "git2/common.h" -#include "git2/types.h" -#include "git2/oid.h" - -GIT_BEGIN_DECL - -GIT_EXTERN(git_reflog_entry *) git_reflog_entry__alloc(void); -GIT_EXTERN(void) git_reflog_entry__free(git_reflog_entry *entry); - -GIT_END_DECL - -#endif diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 62727462012..aa42782998b 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -26,7 +26,6 @@ #include #include #include -#include #define DEFAULT_NESTING_LEVEL 5 #define MAX_NESTING_LEVEL 10 diff --git a/src/libgit2/reflog.c b/src/libgit2/reflog.c index 2aebbc5285d..b998172916e 100644 --- a/src/libgit2/reflog.c +++ b/src/libgit2/reflog.c @@ -13,7 +13,6 @@ #include "refdb.h" #include "git2/sys/refdb_backend.h" -#include "git2/sys/reflog.h" void git_reflog_entry__free(git_reflog_entry *entry) { diff --git a/src/libgit2/reflog.h b/src/libgit2/reflog.h index bc98785981a..ab3afdf10fc 100644 --- a/src/libgit2/reflog.h +++ b/src/libgit2/reflog.h @@ -37,4 +37,6 @@ GIT_INLINE(size_t) reflog_inverse_index(size_t idx, size_t total) return (total - 1) - idx; } +void git_reflog_entry__free(git_reflog_entry *entry); + #endif From 338ceb93b64834e399f91431828fea1f1e62a16e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 25 Nov 2024 23:01:33 +0000 Subject: [PATCH 704/816] Improve documentation --- include/git2/annotated_commit.h | 17 ++-- include/git2/apply.h | 33 ++++++-- include/git2/attr.h | 17 +++- include/git2/blame.h | 10 ++- include/git2/blob.h | 97 +++++++++++++++------ include/git2/branch.h | 37 ++++---- include/git2/buffer.h | 10 ++- include/git2/cert.h | 3 +- include/git2/checkout.h | 61 ++++++++++++-- include/git2/cherrypick.h | 13 ++- include/git2/clone.h | 19 ++++- include/git2/commit.h | 74 +++++++++++++++- include/git2/common.h | 10 ++- include/git2/config.h | 78 ++++++++++++----- include/git2/credential.h | 32 ++++++- include/git2/credential_helpers.h | 1 + include/git2/deprecated.h | 118 +++++++++++++++++++++++++- include/git2/describe.h | 14 ++- include/git2/diff.h | 46 ++++++++-- include/git2/email.h | 13 +-- include/git2/errors.h | 55 +++++++----- include/git2/filter.h | 21 +++-- include/git2/global.h | 9 +- include/git2/graph.h | 5 +- include/git2/ignore.h | 10 +++ include/git2/index.h | 69 ++++++++++++--- include/git2/indexer.h | 19 ++++- include/git2/mailmap.h | 8 +- include/git2/merge.h | 16 +++- include/git2/message.h | 4 +- include/git2/net.h | 4 +- include/git2/notes.h | 15 ++-- include/git2/object.h | 17 ++-- include/git2/odb.h | 136 +++++++++++++++++++----------- include/git2/odb_backend.h | 132 +++++++++++++++++------------ include/git2/oid.h | 47 +++++------ include/git2/oidarray.h | 8 +- include/git2/pack.h | 11 ++- include/git2/patch.h | 5 +- include/git2/pathspec.h | 9 ++ include/git2/proxy.h | 10 +++ include/git2/rebase.h | 8 +- include/git2/refdb.h | 4 +- include/git2/reflog.h | 5 +- include/git2/refs.h | 15 ++-- include/git2/refspec.h | 7 +- include/git2/remote.h | 47 +++++++++-- include/git2/repository.h | 49 ++++++----- include/git2/reset.h | 19 ++++- include/git2/revert.h | 13 ++- include/git2/revparse.h | 6 +- include/git2/revwalk.h | 5 +- include/git2/signature.h | 7 +- include/git2/stash.h | 18 +++- include/git2/status.h | 16 ++-- include/git2/strarray.h | 5 +- include/git2/submodule.h | 18 +++- include/git2/sys/alloc.h | 12 +++ include/git2/sys/commit.h | 80 +++++++++++++++++- include/git2/sys/commit_graph.h | 8 +- include/git2/sys/config.h | 19 ++++- include/git2/sys/credential.h | 7 +- include/git2/sys/diff.h | 22 ++++- include/git2/sys/email.h | 2 + include/git2/sys/errors.h | 10 +++ include/git2/sys/filter.h | 69 ++++++++++++++- include/git2/sys/hashsig.h | 11 +++ include/git2/sys/index.h | 5 +- include/git2/sys/mempack.h | 6 +- include/git2/sys/merge.h | 62 ++++++++++++-- include/git2/sys/midx.h | 7 +- include/git2/sys/odb_backend.h | 10 ++- include/git2/sys/openssl.h | 9 +- include/git2/sys/path.h | 13 ++- include/git2/sys/refdb_backend.h | 10 ++- include/git2/sys/refs.h | 5 +- include/git2/sys/remote.h | 3 +- include/git2/sys/repository.h | 25 ++++-- include/git2/sys/stream.h | 9 ++ include/git2/sys/transport.h | 27 +++++- include/git2/tag.h | 4 +- include/git2/trace.h | 12 ++- include/git2/transaction.h | 5 +- include/git2/transport.h | 14 ++- include/git2/tree.h | 21 +++-- include/git2/types.h | 22 ++++- include/git2/version.h | 11 +++ include/git2/worktree.h | 13 ++- 88 files changed, 1638 insertions(+), 450 deletions(-) diff --git a/include/git2/annotated_commit.h b/include/git2/annotated_commit.h index 3b7103f2001..04f3b1c381f 100644 --- a/include/git2/annotated_commit.h +++ b/include/git2/annotated_commit.h @@ -13,9 +13,16 @@ /** * @file git2/annotated_commit.h - * @brief Git annotated commit routines + * @brief A commit and information about how it was looked up by the user. * @defgroup git_annotated_commit Git annotated commit routines * @ingroup Git + * + * An "annotated commit" is a commit that contains information about + * how the commit was resolved, which can be used for maintaining the + * user's "intent" through commands like merge and rebase. For example, + * if a user wants to "merge HEAD" then an annotated commit is used to + * both contain the HEAD commit _and_ the fact that it was resolved as + * the HEAD ref. * @{ */ GIT_BEGIN_DECL @@ -25,7 +32,7 @@ GIT_BEGIN_DECL * The resulting git_annotated_commit must be freed with * `git_annotated_commit_free`. * - * @param out pointer to store the git_annotated_commit result in + * @param[out] out pointer to store the git_annotated_commit result in * @param repo repository that contains the given reference * @param ref reference to use to lookup the git_annotated_commit * @return 0 on success or error code @@ -40,7 +47,7 @@ GIT_EXTERN(int) git_annotated_commit_from_ref( * The resulting git_annotated_commit must be freed with * `git_annotated_commit_free`. * - * @param out pointer to store the git_annotated_commit result in + * @param[out] out pointer to store the git_annotated_commit result in * @param repo repository that contains the given commit * @param branch_name name of the (remote) branch * @param remote_url url of the remote @@ -67,7 +74,7 @@ GIT_EXTERN(int) git_annotated_commit_from_fetchhead( * most specific function (eg `git_annotated_commit_from_ref`) * instead of this one when that data is known. * - * @param out pointer to store the git_annotated_commit result in + * @param[out] out pointer to store the git_annotated_commit result in * @param repo repository that contains the given commit * @param id the commit object id to lookup * @return 0 on success or error code @@ -84,7 +91,7 @@ GIT_EXTERN(int) git_annotated_commit_lookup( * http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for * information on the syntax accepted. * - * @param out pointer to store the git_annotated_commit result in + * @param[out] out pointer to store the git_annotated_commit result in * @param repo repository that contains the given commit * @param revspec the extended sha syntax string to use to lookup the commit * @return 0 on success or error code diff --git a/include/git2/apply.h b/include/git2/apply.h index db652bde0b3..7ab939d1f2d 100644 --- a/include/git2/apply.h +++ b/include/git2/apply.h @@ -14,9 +14,12 @@ /** * @file git2/apply.h - * @brief Git patch application routines + * @brief Apply patches to the working directory or index * @defgroup git_apply Git patch application routines * @ingroup Git + * + * Mechanisms to apply a patch to the index, the working directory, + * or both. * @{ */ GIT_BEGIN_DECL @@ -57,7 +60,15 @@ typedef int GIT_CALLBACK(git_apply_hunk_cb)( const git_diff_hunk *hunk, void *payload); -/** Flags controlling the behavior of git_apply */ +/** + * Flags controlling the behavior of `git_apply`. + * + * When the callback: + * - returns < 0, the apply process will be aborted. + * - returns > 0, the hunk will not be applied, but the apply process + * continues + * - returns 0, the hunk is applied, and the apply process continues. + */ typedef enum { /** * Don't actually make changes, just test that the patch applies. @@ -67,12 +78,19 @@ typedef enum { } git_apply_flags_t; /** - * Apply options structure + * Apply options structure. + * + * When the callback: + * - returns < 0, the apply process will be aborted. + * - returns > 0, the hunk will not be applied, but the apply process + * continues + * - returns 0, the hunk is applied, and the apply process continues. * * Initialize with `GIT_APPLY_OPTIONS_INIT`. Alternatively, you can * use `git_apply_options_init`. * - * @see git_apply_to_tree, git_apply + * @see git_apply_to_tree + * @see git_apply */ typedef struct { unsigned int version; /**< The version */ @@ -83,14 +101,17 @@ typedef struct { /** When applying a patch, callback that will be made per hunk. */ git_apply_hunk_cb hunk_cb; - /** Payload passed to both delta_cb & hunk_cb. */ + /** Payload passed to both `delta_cb` & `hunk_cb`. */ void *payload; - /** Bitmask of git_apply_flags_t */ + /** Bitmask of `git_apply_flags_t` */ unsigned int flags; } git_apply_options; +/** Current version for the `git_apply_options` structure */ #define GIT_APPLY_OPTIONS_VERSION 1 + +/** Static constructor for `git_apply_options` */ #define GIT_APPLY_OPTIONS_INIT {GIT_APPLY_OPTIONS_VERSION} /** diff --git a/include/git2/attr.h b/include/git2/attr.h index 69929b3dfc6..e5216fef99e 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -12,9 +12,13 @@ /** * @file git2/attr.h - * @brief Git attribute management routines + * @brief Attribute management routines * @defgroup git_attr Git attribute management routines * @ingroup Git + * + * Attributes specify additional information about how git should + * handle particular paths - for example, they may indicate whether + * a particular filter is applied, like LFS or line ending conversions. * @{ */ GIT_BEGIN_DECL @@ -114,8 +118,12 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); * use index only for creating archives or for a bare repo (if an * index has been specified for the bare repo). */ + +/** Examine attribute in working directory, then index */ #define GIT_ATTR_CHECK_FILE_THEN_INDEX 0 +/** Examine attribute in index, then working directory */ #define GIT_ATTR_CHECK_INDEX_THEN_FILE 1 +/** Examine attributes only in the index */ #define GIT_ATTR_CHECK_INDEX_ONLY 2 /** @@ -132,8 +140,12 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); * Passing the `GIT_ATTR_CHECK_INCLUDE_COMMIT` flag will use attributes * from a `.gitattributes` file in a specific commit. */ + +/** Ignore system attributes */ #define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2) +/** Honor `.gitattributes` in the HEAD revision */ #define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3) +/** Honor `.gitattributes` in a specific commit */ #define GIT_ATTR_CHECK_INCLUDE_COMMIT (1 << 4) /** @@ -158,7 +170,10 @@ typedef struct { git_oid attr_commit_id; } git_attr_options; +/** Current version for the `git_attr_options` structure */ #define GIT_ATTR_OPTIONS_VERSION 1 + +/** Static constructor for `git_attr_options` */ #define GIT_ATTR_OPTIONS_INIT {GIT_ATTR_OPTIONS_VERSION} /** diff --git a/include/git2/blame.h b/include/git2/blame.h index 2ddd9e077e0..f3e66924c89 100644 --- a/include/git2/blame.h +++ b/include/git2/blame.h @@ -13,9 +13,14 @@ /** * @file git2/blame.h - * @brief Git blame routines + * @brief Specify a file's most recent changes per-line * @defgroup git_blame Git blame routines * @ingroup Git + * + * Producing a "blame" (or "annotated history") decorates individual + * lines in a file with the commit that introduced that particular line + * of changes. This can be useful to indicate when and why a particular + * change was made. * @{ */ GIT_BEGIN_DECL @@ -122,7 +127,10 @@ typedef struct git_blame_options { size_t max_line; } git_blame_options; +/** Current version for the `git_blame_options` structure */ #define GIT_BLAME_OPTIONS_VERSION 1 + +/** Static constructor for `git_blame_options` */ #define GIT_BLAME_OPTIONS_INIT {GIT_BLAME_OPTIONS_VERSION} /** diff --git a/include/git2/blob.h b/include/git2/blob.h index e8f8381321b..0ed168555ec 100644 --- a/include/git2/blob.h +++ b/include/git2/blob.h @@ -15,9 +15,13 @@ /** * @file git2/blob.h - * @brief Git blob load and write routines + * @brief A blob represents a file in a git repository. * @defgroup git_blob Git blob load and write routines * @ingroup Git + * + * A blob represents a file in a git repository. This is the raw data + * as it is stored in the repository itself. Blobs may be "filtered" + * to produce the on-disk content. * @{ */ GIT_BEGIN_DECL @@ -25,12 +29,15 @@ GIT_BEGIN_DECL /** * Lookup a blob object from a repository. * - * @param blob pointer to the looked up blob + * @param[out] blob pointer to the looked up blob * @param repo the repo to use when locating the blob. * @param id identity of the blob to locate. * @return 0 or an error code */ -GIT_EXTERN(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git_oid *id); +GIT_EXTERN(int) git_blob_lookup( + git_blob **blob, + git_repository *repo, + const git_oid *id); /** * Lookup a blob object from a repository, @@ -38,7 +45,7 @@ GIT_EXTERN(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git * * @see git_object_lookup_prefix * - * @param blob pointer to the looked up blob + * @param[out] blob pointer to the looked up blob * @param repo the repo to use when locating the blob. * @param id identity of the blob to locate. * @param len the length of the short identifier @@ -84,7 +91,7 @@ GIT_EXTERN(git_repository *) git_blob_owner(const git_blob *blob); * time. * * @param blob pointer to the blob - * @return the pointer, or NULL on error + * @return @type `unsigned char *` the pointer, or NULL on error */ GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob); @@ -98,6 +105,8 @@ GIT_EXTERN(git_object_size_t) git_blob_rawsize(const git_blob *blob); /** * Flags to control the functionality of `git_blob_filter`. + * + * @flags */ typedef enum { /** When set, filters will not be applied to binary files. */ @@ -128,16 +137,34 @@ typedef enum { * Initialize with `GIT_BLOB_FILTER_OPTIONS_INIT`. Alternatively, you can * use `git_blob_filter_options_init`. * + * @options[version] GIT_BLOB_FILTER_OPTIONS_VERSION + * @options[init_macro] GIT_BLOB_FILTER_OPTIONS_INIT + * @options[init_function] git_blob_filter_options_init */ typedef struct { + /** Version number of the options structure. */ int version; - /** Flags to control the filtering process, see `git_blob_filter_flag_t` above */ + /** + * Flags to control the filtering process, see `git_blob_filter_flag_t` above. + * + * @type[flags] git_blob_filter_flag_t + */ uint32_t flags; #ifdef GIT_DEPRECATE_HARD + /** + * Unused and reserved for ABI compatibility. + * + * @deprecated this value should not be set + */ void *reserved; #else + /** + * This value is unused and reserved for API compatibility. + * + * @deprecated this value should not be set + */ git_oid *commit_id; #endif @@ -148,8 +175,18 @@ typedef struct { git_oid attr_commit_id; } git_blob_filter_options; +/** + * The current version number for the `git_blob_filter_options` structure ABI. + */ #define GIT_BLOB_FILTER_OPTIONS_VERSION 1 -#define GIT_BLOB_FILTER_OPTIONS_INIT {GIT_BLOB_FILTER_OPTIONS_VERSION, GIT_BLOB_FILTER_CHECK_FOR_BINARY} + +/** + * The default values for `git_blob_filter_options`. + */ +#define GIT_BLOB_FILTER_OPTIONS_INIT { \ + GIT_BLOB_FILTER_OPTIONS_VERSION, \ + GIT_BLOB_FILTER_CHECK_FOR_BINARY \ + } /** * Initialize git_blob_filter_options structure @@ -158,10 +195,12 @@ typedef struct { * to creating an instance with `GIT_BLOB_FILTER_OPTIONS_INIT`. * * @param opts The `git_blob_filter_options` struct to initialize. - * @param version The struct version; pass `GIT_BLOB_FILTER_OPTIONS_VERSION`. + * @param version The struct version; pass GIT_BLOB_FILTER_OPTIONS_VERSION * @return Zero on success; -1 on failure. */ -GIT_EXTERN(int) git_blob_filter_options_init(git_blob_filter_options *opts, unsigned int version); +GIT_EXTERN(int) git_blob_filter_options_init( + git_blob_filter_options *opts, + unsigned int version); /** * Get a buffer with the filtered content of a blob. @@ -171,7 +210,7 @@ GIT_EXTERN(int) git_blob_filter_options_init(git_blob_filter_options *opts, unsi * CRLF filtering or other types of changes depending on the file * attributes set for the blob and the content detected in it. * - * The output is written into a `git_buf` which the caller must free + * The output is written into a `git_buf` which the caller must dispose * when done (via `git_buf_dispose`). * * If no filters need to be applied, then the `out` buffer will just @@ -183,7 +222,7 @@ GIT_EXTERN(int) git_blob_filter_options_init(git_blob_filter_options *opts, unsi * @param blob Pointer to the blob * @param as_path Path used for file attribute lookups, etc. * @param opts Options to use for filtering the blob - * @return 0 on success or an error code + * @return @type[enum] git_error_code 0 on success or an error code */ GIT_EXTERN(int) git_blob_filter( git_buf *out, @@ -192,10 +231,10 @@ GIT_EXTERN(int) git_blob_filter( git_blob_filter_options *opts); /** - * Read a file from the working folder of a repository - * and write it to the Object Database as a loose blob + * Read a file from the working folder of a repository and write it + * to the object database. * - * @param id return the id of the written blob + * @param[out] id return the id of the written blob * @param repo repository where the blob will be written. * this repository cannot be bare * @param relative_path file from which the blob will be created, @@ -205,19 +244,23 @@ GIT_EXTERN(int) git_blob_filter( GIT_EXTERN(int) git_blob_create_from_workdir(git_oid *id, git_repository *repo, const char *relative_path); /** - * Read a file from the filesystem and write its content - * to the Object Database as a loose blob + * Read a file from the filesystem (not necessarily inside the + * working folder of the repository) and write it to the object + * database. * - * @param id return the id of the written blob + * @param[out] id return the id of the written blob * @param repo repository where the blob will be written. * this repository can be bare or not * @param path file from which the blob will be created * @return 0 or an error code */ -GIT_EXTERN(int) git_blob_create_from_disk(git_oid *id, git_repository *repo, const char *path); +GIT_EXTERN(int) git_blob_create_from_disk( + git_oid *id, + git_repository *repo, + const char *path); /** - * Create a stream to write a new blob into the object db + * Create a stream to write a new blob into the object database. * * This function may need to buffer the data on disk and will in * general not be the right choice if you know the size of the data @@ -234,7 +277,7 @@ GIT_EXTERN(int) git_blob_create_from_disk(git_oid *id, git_repository *repo, con * what git filters should be applied to the object before it is written * to the object database. * - * @param out the stream into which to write + * @param[out] out the stream into which to write * @param repo Repository where the blob will be written. * This repository can be bare or not. * @param hintpath If not NULL, will be used to select data filters @@ -247,11 +290,11 @@ GIT_EXTERN(int) git_blob_create_from_stream( const char *hintpath); /** - * Close the stream and write the blob to the object db + * Close the stream and finalize writing the blob to the object database. * * The stream will be closed and freed. * - * @param out the id of the new blob + * @param[out] out the id of the new blob * @param stream the stream to close * @return 0 or an error code */ @@ -260,9 +303,9 @@ GIT_EXTERN(int) git_blob_create_from_stream_commit( git_writestream *stream); /** - * Write an in-memory buffer to the ODB as a blob + * Write an in-memory buffer to the object database as a blob. * - * @param id return the id of the written blob + * @param[out] id return the id of the written blob * @param repo repository where the blob will be written * @param buffer data to be written into the blob * @param len length of the data @@ -272,14 +315,14 @@ GIT_EXTERN(int) git_blob_create_from_buffer( git_oid *id, git_repository *repo, const void *buffer, size_t len); /** - * Determine if the blob content is most certainly binary or not. + * Determine if the blob content is most likely binary or not. * * The heuristic used to guess if a file is binary is taken from core git: * Searching for NUL bytes and looking for a reasonable ratio of printable * to non-printable characters among the first 8000 bytes. * * @param blob The blob which content should be analyzed - * @return 1 if the content of the blob is detected + * @return @type bool 1 if the content of the blob is detected * as binary; 0 otherwise. */ GIT_EXTERN(int) git_blob_is_binary(const git_blob *blob); @@ -300,7 +343,7 @@ GIT_EXTERN(int) git_blob_data_is_binary(const char *data, size_t len); * Create an in-memory copy of a blob. The copy must be explicitly * free'd or it will leak. * - * @param out Pointer to store the copy of the object + * @param[out] out Pointer to store the copy of the object * @param source Original object to copy * @return 0. */ diff --git a/include/git2/branch.h b/include/git2/branch.h index 27c6fa15727..56d737d0fb0 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -13,9 +13,15 @@ /** * @file git2/branch.h - * @brief Git branch parsing routines + * @brief Branch creation and handling * @defgroup git_branch Git branch management * @ingroup Git + * + * A branch is a specific type of reference, at any particular time, + * a git working directory typically is said to have a branch "checked out", + * meaning that commits that are created will be made "on" a branch. + * This occurs by updating the branch reference to point to the new + * commit. The checked out branch is indicated by the `HEAD` meta-ref. * @{ */ GIT_BEGIN_DECL @@ -33,18 +39,13 @@ GIT_BEGIN_DECL * See `git_tag_create()` for rules about valid names. * * @param out Pointer where to store the underlying reference. - * * @param repo the repository to create the branch in. - * * @param branch_name Name for the branch; this name is - * validated for consistency. It should also not conflict with - * an already existing branch name. - * + * validated for consistency. It should also not conflict with + * an already existing branch name. * @param target Commit to which this branch should point. This object - * must belong to the given `repo`. - * + * must belong to the given `repo`. * @param force Overwrite existing branch. - * * @return 0, GIT_EINVALIDSPEC or an error code. * A proper reference is written in the refs/heads namespace * pointing to the provided target commit. @@ -63,15 +64,21 @@ GIT_EXTERN(int) git_branch_create( * commit, which lets you specify which extended sha syntax string was * specified by a user, allowing for more exact reflog messages. * - * See the documentation for `git_branch_create()`. - * - * @see git_branch_create + * @param ref_out Pointer where to store the underlying reference. + * @param repo the repository to create the branch in. + * @param branch_name Name for the branch; this name is + * validated for consistency. It should also not conflict with + * an already existing branch name. + * @param target Annotated commit to which this branch should point. This + * object must belong to the given `repo`. + * @param force Overwrite existing branch. + * @return 0, GIT_EINVALIDSPEC or an error code. */ GIT_EXTERN(int) git_branch_create_from_annotated( git_reference **ref_out, - git_repository *repository, + git_repository *repo, const char *branch_name, - const git_annotated_commit *commit, + const git_annotated_commit *target, int force); /** @@ -222,7 +229,7 @@ GIT_EXTERN(int) git_branch_upstream( * @param branch the branch to configure * @param branch_name remote-tracking or local branch to set as upstream. * - * @return 0 on success; GIT_ENOTFOUND if there's no branch named `branch_name` + * @return @type git_error_t 0 on success; GIT_ENOTFOUND if there's no branch named `branch_name` * or an error code */ GIT_EXTERN(int) git_branch_set_upstream( diff --git a/include/git2/buffer.h b/include/git2/buffer.h index 9fa97203457..3fe4f854857 100644 --- a/include/git2/buffer.h +++ b/include/git2/buffer.h @@ -11,9 +11,12 @@ /** * @file git2/buffer.h - * @brief Buffer export structure - * + * @brief A data structure to return data to callers * @ingroup Git + * + * The `git_buf` buffer is used to return arbitrary data - typically + * strings - to callers. Callers are responsible for freeing the memory + * in a buffer with the `git_buf_dispose` function. * @{ */ GIT_BEGIN_DECL @@ -67,8 +70,7 @@ typedef struct { */ GIT_EXTERN(void) git_buf_dispose(git_buf *buffer); -GIT_END_DECL - /** @} */ +GIT_END_DECL #endif diff --git a/include/git2/cert.h b/include/git2/cert.h index 05213a57192..7b91b638d4f 100644 --- a/include/git2/cert.h +++ b/include/git2/cert.h @@ -12,7 +12,7 @@ /** * @file git2/cert.h - * @brief Git certificate objects + * @brief TLS and SSH certificate handling * @defgroup git_cert Certificate objects * @ingroup Git * @{ @@ -169,4 +169,5 @@ typedef struct { /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 3705a8d7bb3..bdea928459a 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -13,9 +13,13 @@ /** * @file git2/checkout.h - * @brief Git checkout routines + * @brief Update the contents of the working directory * @defgroup git_checkout Git checkout routines * @ingroup Git + * + * Update the contents of the working directory, or a subset of the + * files in the working directory, to point to the data in the index + * or a specific commit. * @{ */ GIT_BEGIN_DECL @@ -103,6 +107,8 @@ GIT_BEGIN_DECL * files or folders that fold to the same name on case insensitive * filesystems. This can cause files to retain their existing names * and write through existing symbolic links. + * + * @flags */ typedef enum { /** @@ -212,6 +218,8 @@ typedef enum { * Notification callbacks are made prior to modifying any files on disk, * so canceling on any notification will still happen prior to any files * being modified. + * + * @flags */ typedef enum { GIT_CHECKOUT_NOTIFY_NONE = 0, @@ -253,7 +261,17 @@ typedef struct { size_t chmod_calls; } git_checkout_perfdata; -/** Checkout notification callback function */ +/** + * Checkout notification callback function. + * + * @param why the notification reason + * @param path the path to the file being checked out + * @param baseline the baseline's diff file information + * @param target the checkout target diff file information + * @param workdir the working directory diff file information + * @param payload the user-supplied callback payload + * @return 0 on success, or an error code + */ typedef int GIT_CALLBACK(git_checkout_notify_cb)( git_checkout_notify_t why, const char *path, @@ -262,14 +280,26 @@ typedef int GIT_CALLBACK(git_checkout_notify_cb)( const git_diff_file *workdir, void *payload); -/** Checkout progress notification function */ +/** + * Checkout progress notification function. + * + * @param path the path to the file being checked out + * @param completed_steps number of checkout steps completed + * @param total_steps number of total steps in the checkout process + * @param payload the user-supplied callback payload + */ typedef void GIT_CALLBACK(git_checkout_progress_cb)( const char *path, size_t completed_steps, size_t total_steps, void *payload); -/** Checkout perfdata notification function */ +/** + * Checkout performance data reporting function. + * + * @param perfdata the performance data for the checkout + * @param payload the user-supplied callback payload + */ typedef void GIT_CALLBACK(git_checkout_perfdata_cb)( const git_checkout_perfdata *perfdata, void *payload); @@ -280,10 +310,18 @@ typedef void GIT_CALLBACK(git_checkout_perfdata_cb)( * Initialize with `GIT_CHECKOUT_OPTIONS_INIT`. Alternatively, you can * use `git_checkout_options_init`. * + * @options[version] GIT_CHECKOUT_OPTIONS_VERSION + * @options[init_macro] GIT_CHECKOUT_OPTIONS_INIT + * @options[init_function] git_checkout_options_init */ typedef struct git_checkout_options { unsigned int version; /**< The version */ + /** + * Checkout strategy. Default is a safe checkout. + * + * @type[flags] git_checkout_strategy_t + */ unsigned int checkout_strategy; /**< default will be a safe checkout */ int disable_filters; /**< don't apply filters like CRLF conversion */ @@ -291,7 +329,13 @@ typedef struct git_checkout_options { unsigned int file_mode; /**< default is 0644 or 0755 as dictated by blob */ int file_open_flags; /**< default is O_CREAT | O_TRUNC | O_WRONLY */ - unsigned int notify_flags; /**< see `git_checkout_notify_t` above */ + /** + * Checkout notification flags specify what operations the notify + * callback is invoked for. + * + * @type[flags] git_checkout_notify_t + */ + unsigned int notify_flags; /** * Optional callback to get notifications on specific file states. @@ -346,8 +390,12 @@ typedef struct git_checkout_options { void *perfdata_payload; } git_checkout_options; + +/** Current version for the `git_checkout_options` structure */ #define GIT_CHECKOUT_OPTIONS_VERSION 1 -#define GIT_CHECKOUT_OPTIONS_INIT {GIT_CHECKOUT_OPTIONS_VERSION} + +/** Static constructor for `git_checkout_options` */ +#define GIT_CHECKOUT_OPTIONS_INIT { GIT_CHECKOUT_OPTIONS_VERSION } /** * Initialize git_checkout_options structure @@ -416,4 +464,5 @@ GIT_EXTERN(int) git_checkout_tree( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/cherrypick.h b/include/git2/cherrypick.h index 0e6a252e6f1..e6cf99ea51d 100644 --- a/include/git2/cherrypick.h +++ b/include/git2/cherrypick.h @@ -13,9 +13,12 @@ /** * @file git2/cherrypick.h - * @brief Git cherry-pick routines + * @brief Cherry-pick the contents of an individual commit * @defgroup git_cherrypick Git cherry-pick routines * @ingroup Git + * + * "Cherry-pick" will attempts to re-apply the changes in an + * individual commit to the current index and working directory. * @{ */ GIT_BEGIN_DECL @@ -33,8 +36,13 @@ typedef struct { git_checkout_options checkout_opts; /**< Options for the checkout */ } git_cherrypick_options; +/** Current version for the `git_cherrypick_options` structure */ #define GIT_CHERRYPICK_OPTIONS_VERSION 1 -#define GIT_CHERRYPICK_OPTIONS_INIT {GIT_CHERRYPICK_OPTIONS_VERSION, 0, GIT_MERGE_OPTIONS_INIT, GIT_CHECKOUT_OPTIONS_INIT} + +/** Static constructor for `git_cherrypick_options` */ +#define GIT_CHERRYPICK_OPTIONS_INIT { \ + GIT_CHERRYPICK_OPTIONS_VERSION, 0, \ + GIT_MERGE_OPTIONS_INIT, GIT_CHECKOUT_OPTIONS_INIT } /** * Initialize git_cherrypick_options structure @@ -89,4 +97,3 @@ GIT_EXTERN(int) git_cherrypick( GIT_END_DECL #endif - diff --git a/include/git2/clone.h b/include/git2/clone.h index 0e3012eea6a..0d06a41df1f 100644 --- a/include/git2/clone.h +++ b/include/git2/clone.h @@ -17,9 +17,13 @@ /** * @file git2/clone.h - * @brief Git cloning routines + * @brief Clone a remote repository to the local disk * @defgroup git_clone Git cloning routines * @ingroup Git + * + * Clone will take a remote repository - located on a remote server + * accessible by HTTPS or SSH, or a repository located elsewhere on + * the local disk - and place a copy in the given local path. * @{ */ GIT_BEGIN_DECL @@ -59,7 +63,7 @@ typedef enum { * Callers of git_clone may provide a function matching this signature to override * the remote creation and customization process during a clone operation. * - * @param out the resulting remote + * @param[out] out the resulting remote * @param repo the repository in which to create the remote * @param name the remote's name * @param url the remote's url @@ -81,7 +85,7 @@ typedef int GIT_CALLBACK(git_remote_create_cb)( * to override the repository creation and customization process * during a clone operation. * - * @param out the resulting repository + * @param[out] out the resulting repository * @param path path in which to create the repository * @param bare whether the repository is bare. This is the value from the clone options * @param payload payload specified by the options @@ -99,6 +103,9 @@ typedef int GIT_CALLBACK(git_repository_create_cb)( * Initialize with `GIT_CLONE_OPTIONS_INIT`. Alternatively, you can * use `git_clone_options_init`. * + * @options[version] GIT_CLONE_OPTIONS_VERSION + * @options[init_macro] GIT_CLONE_OPTIONS_INIT + * @options[init_function] git_clone_options_init */ typedef struct git_clone_options { unsigned int version; @@ -163,7 +170,10 @@ typedef struct git_clone_options { void *remote_cb_payload; } git_clone_options; +/** Current version for the `git_clone_options` structure */ #define GIT_CLONE_OPTIONS_VERSION 1 + +/** Static constructor for `git_clone_options` */ #define GIT_CLONE_OPTIONS_INIT \ { GIT_CLONE_OPTIONS_VERSION, \ GIT_CHECKOUT_OPTIONS_INIT, \ @@ -190,7 +200,7 @@ GIT_EXTERN(int) git_clone_options_init( * git's defaults. You can use the options in the callback to * customize how these are created. * - * @param out pointer that will receive the resulting repository object + * @param[out] out pointer that will receive the resulting repository object * @param url the remote repository to clone * @param local_path local directory to clone to * @param options configuration options for the clone. If NULL, the @@ -207,4 +217,5 @@ GIT_EXTERN(int) git_clone( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/commit.h b/include/git2/commit.h index 88c21e0c973..b998e188974 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -14,9 +14,13 @@ /** * @file git2/commit.h - * @brief Git commit parsing, formatting routines + * @brief A representation of a set of changes in the repository * @defgroup git_commit Git commit parsing, formatting routines * @ingroup Git + * + * A commit represents a set of changes made to the files within a + * repository, and metadata about who made the changes, and when the + * changes were made. * @{ */ GIT_BEGIN_DECL @@ -380,7 +384,38 @@ GIT_EXTERN(int) git_commit_create( * * All other parameters remain the same as `git_commit_create()`. * - * @see git_commit_create + * @param id Pointer in which to store the OID of the newly created commit + * + * @param repo Repository where to store the commit + * + * @param update_ref If not NULL, name of the reference that + * will be updated to point to this commit. If the reference + * is not direct, it will be resolved to a direct reference. + * Use "HEAD" to update the HEAD of the current branch and + * make it point to this commit. If the reference doesn't + * exist yet, it will be created. If it does exist, the first + * parent must be the tip of this branch. + * + * @param author Signature with author and author time of commit + * + * @param committer Signature with committer and * commit time of commit + * + * @param message_encoding The encoding for the message in the + * commit, represented with a standard encoding name. + * E.g. "UTF-8". If NULL, no encoding header is written and + * UTF-8 is assumed. + * + * @param message Full message for this commit + * + * @param tree An instance of a `git_tree` object that will + * be used as the tree for the commit. This tree object must + * also be owned by the given `repo`. + * + * @param parent_count Number of parents for this commit + * + * @return 0 or an error code + * The created commit will be written to the Object Database and + * the given reference will be updated to point to it */ GIT_EXTERN(int) git_commit_create_v( git_oid *id, @@ -416,7 +451,10 @@ typedef struct { const char *message_encoding; } git_commit_create_options; +/** Current version for the `git_commit_create_options` structure */ #define GIT_COMMIT_CREATE_OPTIONS_VERSION 1 + +/** Static constructor for `git_commit_create_options` */ #define GIT_COMMIT_CREATE_OPTIONS_INIT { GIT_COMMIT_CREATE_OPTIONS_VERSION } /** @@ -456,7 +494,36 @@ GIT_EXTERN(int) git_commit_create_from_stage( * * All parameters have the same meanings as in `git_commit_create()`. * - * @see git_commit_create + * @param id Pointer in which to store the OID of the newly created commit + * + * @param commit_to_amend The commit to amend + * + * @param update_ref If not NULL, name of the reference that + * will be updated to point to this commit. If the reference + * is not direct, it will be resolved to a direct reference. + * Use "HEAD" to update the HEAD of the current branch and + * make it point to this commit. If the reference doesn't + * exist yet, it will be created. If it does exist, the first + * parent must be the tip of this branch. + * + * @param author Signature with author and author time of commit + * + * @param committer Signature with committer and * commit time of commit + * + * @param message_encoding The encoding for the message in the + * commit, represented with a standard encoding name. + * E.g. "UTF-8". If NULL, no encoding header is written and + * UTF-8 is assumed. + * + * @param message Full message for this commit + * + * @param tree An instance of a `git_tree` object that will + * be used as the tree for the commit. This tree object must + * also be owned by the given `repo`. + * + * @return 0 or an error code + * The created commit will be written to the Object Database and + * the given reference will be updated to point to it */ GIT_EXTERN(int) git_commit_amend( git_oid *id, @@ -604,4 +671,5 @@ GIT_EXTERN(void) git_commitarray_dispose(git_commitarray *array); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/common.h b/include/git2/common.h index 8d015704439..56847e68165 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -11,7 +11,9 @@ #include #ifdef __cplusplus + /** Start declarations in C mode for C++ compatibility */ # define GIT_BEGIN_DECL extern "C" { + /** End declarations in C mode */ # define GIT_END_DECL } #else /** Start declarations in C mode */ @@ -71,6 +73,7 @@ typedef size_t size_t; # define GIT_FORMAT_PRINTF(a,b) /* empty */ #endif +/** Defined when building on Windows (but not via cygwin) */ #if (defined(_WIN32)) && !defined(__CYGWIN__) #define GIT_WIN32 1 #endif @@ -81,9 +84,13 @@ typedef size_t size_t; /** * @file git2/common.h - * @brief Git common platform definitions + * @brief Base platform functionality * @defgroup git_common Git common platform definitions * @ingroup Git + * + * Common platform functionality including introspecting libgit2 + * itself - information like how it was built, and the current + * running version. * @{ */ @@ -538,7 +545,6 @@ typedef enum { * > to a remote server. Set to 0 to use the system default. * * @param option Option key - * @param ... value to set the option * @return 0 on success, <0 on failure */ GIT_EXTERN(int) git_libgit2_opts(int option, ...); diff --git a/include/git2/config.h b/include/git2/config.h index 9a425aa0b13..f9c26675403 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -13,9 +13,13 @@ /** * @file git2/config.h - * @brief Git config management routines + * @brief Per-repository, per-user or per-system configuration * @defgroup git_config Git config management routines * @ingroup Git + * + * Git configuration affects the operation of the version control + * system, and can be specified on a per-repository basis, in user + * settings, or at the system level. * @{ */ GIT_BEGIN_DECL @@ -38,37 +42,57 @@ GIT_BEGIN_DECL * * git_config_open_default() and git_repository_config() honor those * priority levels as well. + * + * @see git_config_open_default + * @see git_repository_config */ typedef enum { - /** System-wide on Windows, for compatibility with portable git */ + /** + * System-wide on Windows, for compatibility with "Portable Git". + */ GIT_CONFIG_LEVEL_PROGRAMDATA = 1, - /** System-wide configuration file; /etc/gitconfig on Linux systems */ + /** + * System-wide configuration file; `/etc/gitconfig` on Linux. + */ GIT_CONFIG_LEVEL_SYSTEM = 2, - /** XDG compatible configuration file; typically ~/.config/git/config */ + /** + * XDG compatible configuration file; typically + * `~/.config/git/config`. + */ GIT_CONFIG_LEVEL_XDG = 3, - /** User-specific configuration file (also called Global configuration - * file); typically ~/.gitconfig + /** + * Global configuration file is the user-specific configuration; + * typically `~/.gitconfig`. */ GIT_CONFIG_LEVEL_GLOBAL = 4, - /** Repository specific configuration file; $WORK_DIR/.git/config on - * non-bare repos + /** + * Local configuration, the repository-specific configuration file; + * typically `$GIT_DIR/config`. */ GIT_CONFIG_LEVEL_LOCAL = 5, - /** Worktree specific configuration file; $GIT_DIR/config.worktree + /** + * Worktree-specific configuration; typically + * `$GIT_DIR/config.worktree`. */ GIT_CONFIG_LEVEL_WORKTREE = 6, - /** Application specific configuration file; freely defined by applications + /** + * Application-specific configuration file. Callers into libgit2 + * can add their own configuration beginning at this level. */ GIT_CONFIG_LEVEL_APP = 7, - /** Represents the highest level available config file (i.e. the most - * specific config file available that actually is loaded) + /** + * Not a configuration level; callers can use this value when + * querying configuration levels to specify that they want to + * have data from the highest-level currently configuration. + * This can be used to indicate that callers want the most + * specific config file available that actually is loaded. */ GIT_CONFIG_HIGHEST_LEVEL = -1 } git_config_level_t; @@ -77,13 +101,13 @@ typedef enum { * An entry in a configuration file */ typedef struct git_config_entry { - /** Name of the configuration entry (normalized) */ + /** Name of the configuration entry (normalized). */ const char *name; - /** Literal (string) value of the entry */ + /** Literal (string) value of the entry. */ const char *value; - /** The type of backend that this entry exists in (eg, "file") */ + /** The type of backend that this entry exists in (eg, "file"). */ const char *backend_type; /** @@ -92,22 +116,22 @@ typedef struct git_config_entry { */ const char *origin_path; - /** Depth of includes where this variable was found */ + /** Depth of includes where this variable was found. */ unsigned int include_depth; - /** Configuration level for the file this was found in */ + /** Configuration level for the file this was found in. */ git_config_level_t level; } git_config_entry; /** - * Free a config entry + * Free a config entry. * * @param entry The entry to free. */ GIT_EXTERN(void) git_config_entry_free(git_config_entry *entry); /** - * A config enumeration callback + * A config enumeration callback. * * @param entry the entry currently being enumerated * @param payload a user-specified pointer @@ -116,7 +140,7 @@ GIT_EXTERN(void) git_config_entry_free(git_config_entry *entry); typedef int GIT_CALLBACK(git_config_foreach_cb)(const git_config_entry *entry, void *payload); /** - * An opaque structure for a configuration iterator + * An opaque structure for a configuration iterator. */ typedef struct git_config_iterator git_config_iterator; @@ -241,9 +265,9 @@ GIT_EXTERN(int) git_config_new(git_config **out); * @param cfg the configuration to add the file to * @param path path to the configuration file to add * @param level the priority level of the backend - * @param force replace config file at the given priority level * @param repo optional repository to allow parsing of * conditional includes + * @param force replace config file at the given priority level * @return 0 on success, GIT_EEXISTS when adding more than one file * for a given priority level (and force_replace set to 0), * GIT_ENOTFOUND when the file doesn't exist or error code @@ -305,6 +329,17 @@ GIT_EXTERN(int) git_config_open_level( */ GIT_EXTERN(int) git_config_open_global(git_config **out, git_config *config); +/** + * Set the write order for configuration backends. By default, the + * write ordering does not match the read ordering; for example, the + * worktree configuration is a high-priority for reading, but is not + * written to unless explicitly chosen. + * + * @param cfg the configuration to change write order of + * @param levels the ordering of levels for writing + * @param len the length of the levels array + * @return 0 or an error code + */ GIT_EXTERN(int) git_config_set_writeorder( git_config *cfg, git_config_level_t *levels, @@ -813,4 +848,5 @@ GIT_EXTERN(int) git_config_lock(git_transaction **tx, git_config *cfg); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/credential.h b/include/git2/credential.h index 7a04bc06479..33755ca916d 100644 --- a/include/git2/credential.h +++ b/include/git2/credential.h @@ -11,9 +11,12 @@ /** * @file git2/credential.h - * @brief Git authentication & credential management + * @brief Authentication and credential management * @defgroup git_credential Authentication & credential management * @ingroup Git + * + * Credentials specify how to authenticate to a remote system + * over HTTPS or SSH. * @{ */ GIT_BEGIN_DECL @@ -119,7 +122,7 @@ typedef struct git_credential_ssh_custom git_credential_ssh_custom; * an error. As such, it's easy to get in a loop if you fail to stop providing * the same incorrect credentials. * - * @param out The newly created credential object. + * @param[out] out The newly created credential object. * @param url The resource for which we are demanding a credential. * @param username_from_url The username that was embedded in a "user\@host" * remote url, or NULL if not included. @@ -241,6 +244,18 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT LIBSSH2_USERAUTH_KBDINT_PROMPT; typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE LIBSSH2_USERAUTH_KBDINT_RESPONSE; #endif +/** + * Callback for interactive SSH credentials. + * + * @param name the name + * @param name_len the length of the name + * @param instruction the authentication instruction + * @param instruction_len the length of the instruction + * @param num_prompts the number of prompts + * @param prompts the prompts + * @param responses the responses + * @param abstract the abstract + */ typedef void GIT_CALLBACK(git_credential_ssh_interactive_cb)( const char *name, int name_len, @@ -278,6 +293,18 @@ GIT_EXTERN(int) git_credential_ssh_key_from_agent( git_credential **out, const char *username); +/** + * Callback for credential signing. + * + * @param session the libssh2 session + * @param sig the signature + * @param sig_len the length of the signature + * @param data the data + * @param data_len the length of the data + * @param abstract the abstract + * @return 0 for success, < 0 to indicate an error, > 0 to indicate + * no credential was acquired + */ typedef int GIT_CALLBACK(git_credential_sign_cb)( LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, @@ -312,4 +339,5 @@ GIT_EXTERN(int) git_credential_ssh_custom_new( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/credential_helpers.h b/include/git2/credential_helpers.h index f0fb07041d9..706558d5bd0 100644 --- a/include/git2/credential_helpers.h +++ b/include/git2/credential_helpers.h @@ -50,4 +50,5 @@ GIT_EXTERN(int) git_credential_userpass( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/deprecated.h b/include/git2/deprecated.h index 49ac9c87f7d..b8b0238da66 100644 --- a/include/git2/deprecated.h +++ b/include/git2/deprecated.h @@ -52,7 +52,7 @@ /** * @file git2/deprecated.h - * @brief libgit2 deprecated functions and values + * @brief Deprecated functions and values * @ingroup Git * @{ */ @@ -69,15 +69,23 @@ GIT_BEGIN_DECL */ /**@{*/ +/** @deprecated use GIT_ATTR_VALUE_UNSPECIFIED */ #define GIT_ATTR_UNSPECIFIED_T GIT_ATTR_VALUE_UNSPECIFIED +/** @deprecated use GIT_ATTR_VALUE_TRUE */ #define GIT_ATTR_TRUE_T GIT_ATTR_VALUE_TRUE +/** @deprecated use GIT_ATTR_VALUE_FALSE */ #define GIT_ATTR_FALSE_T GIT_ATTR_VALUE_FALSE +/** @deprecated use GIT_ATTR_VALUE_STRING */ #define GIT_ATTR_VALUE_T GIT_ATTR_VALUE_STRING +/** @deprecated use GIT_ATTR_IS_TRUE */ #define GIT_ATTR_TRUE(attr) GIT_ATTR_IS_TRUE(attr) +/** @deprecated use GIT_ATTR_IS_FALSE */ #define GIT_ATTR_FALSE(attr) GIT_ATTR_IS_FALSE(attr) +/** @deprecated use GIT_ATTR_IS_UNSPECIFIED */ #define GIT_ATTR_UNSPECIFIED(attr) GIT_ATTR_IS_UNSPECIFIED(attr) +/** @deprecated use git_attr_value_t */ typedef git_attr_value_t git_attr_t; /**@}*/ @@ -93,6 +101,7 @@ typedef git_attr_value_t git_attr_t; */ /**@{*/ +/** @deprecated use GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD */ #define GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD GIT_EXTERN(int) git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path); @@ -285,11 +294,16 @@ typedef int (*git_commit_signing_cb)( */ /**@{*/ +/** @deprecated use GIT_CONFIGMAP_FALSE */ #define GIT_CVAR_FALSE GIT_CONFIGMAP_FALSE +/** @deprecated use GIT_CONFIGMAP_TRUE */ #define GIT_CVAR_TRUE GIT_CONFIGMAP_TRUE +/** @deprecated use GIT_CONFIGMAP_INT32 */ #define GIT_CVAR_INT32 GIT_CONFIGMAP_INT32 +/** @deprecated use GIT_CONFIGMAP_STRING */ #define GIT_CVAR_STRING GIT_CONFIGMAP_STRING +/** @deprecated use git_cvar_map */ typedef git_configmap git_cvar_map; /**@}*/ @@ -314,11 +328,12 @@ typedef enum { /** Don't insert "[PATCH]" in the subject header*/ GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = (1 << 0) - } git_diff_format_email_flags_t; /** * Options for controlling the formatting of the generated e-mail. + * + * @deprecated use `git_email_create_options` */ typedef struct { unsigned int version; @@ -345,7 +360,9 @@ typedef struct { const git_signature *author; } git_diff_format_email_options; +/** @deprecated use `git_email_create_options` */ #define GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION 1 +/** @deprecated use `git_email_create_options` */ #define GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT {GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, 0, 1, 1, NULL, NULL, NULL, NULL} /** @@ -401,41 +418,75 @@ GIT_EXTERN(int) git_diff_format_email_options_init( */ /**@{*/ +/** @deprecated use `GIT_ERROR_NONE` */ #define GITERR_NONE GIT_ERROR_NONE +/** @deprecated use `GIT_ERROR_NOMEMORY` */ #define GITERR_NOMEMORY GIT_ERROR_NOMEMORY +/** @deprecated use `GIT_ERROR_OS` */ #define GITERR_OS GIT_ERROR_OS +/** @deprecated use `GIT_ERROR_INVALID` */ #define GITERR_INVALID GIT_ERROR_INVALID +/** @deprecated use `GIT_ERROR_REFERENCE` */ #define GITERR_REFERENCE GIT_ERROR_REFERENCE +/** @deprecated use `GIT_ERROR_ZLIB` */ #define GITERR_ZLIB GIT_ERROR_ZLIB +/** @deprecated use `GIT_ERROR_REPOSITORY` */ #define GITERR_REPOSITORY GIT_ERROR_REPOSITORY +/** @deprecated use `GIT_ERROR_CONFIG` */ #define GITERR_CONFIG GIT_ERROR_CONFIG +/** @deprecated use `GIT_ERROR_REGEX` */ #define GITERR_REGEX GIT_ERROR_REGEX +/** @deprecated use `GIT_ERROR_ODB` */ #define GITERR_ODB GIT_ERROR_ODB +/** @deprecated use `GIT_ERROR_INDEX` */ #define GITERR_INDEX GIT_ERROR_INDEX +/** @deprecated use `GIT_ERROR_OBJECT` */ #define GITERR_OBJECT GIT_ERROR_OBJECT +/** @deprecated use `GIT_ERROR_NET` */ #define GITERR_NET GIT_ERROR_NET +/** @deprecated use `GIT_ERROR_TAG` */ #define GITERR_TAG GIT_ERROR_TAG +/** @deprecated use `GIT_ERROR_TREE` */ #define GITERR_TREE GIT_ERROR_TREE +/** @deprecated use `GIT_ERROR_INDEXER` */ #define GITERR_INDEXER GIT_ERROR_INDEXER +/** @deprecated use `GIT_ERROR_SSL` */ #define GITERR_SSL GIT_ERROR_SSL +/** @deprecated use `GIT_ERROR_SUBMODULE` */ #define GITERR_SUBMODULE GIT_ERROR_SUBMODULE +/** @deprecated use `GIT_ERROR_THREAD` */ #define GITERR_THREAD GIT_ERROR_THREAD +/** @deprecated use `GIT_ERROR_STASH` */ #define GITERR_STASH GIT_ERROR_STASH +/** @deprecated use `GIT_ERROR_CHECKOUT` */ #define GITERR_CHECKOUT GIT_ERROR_CHECKOUT +/** @deprecated use `GIT_ERROR_FETCHHEAD` */ #define GITERR_FETCHHEAD GIT_ERROR_FETCHHEAD +/** @deprecated use `GIT_ERROR_MERGE` */ #define GITERR_MERGE GIT_ERROR_MERGE +/** @deprecated use `GIT_ERROR_SSH` */ #define GITERR_SSH GIT_ERROR_SSH +/** @deprecated use `GIT_ERROR_FILTER` */ #define GITERR_FILTER GIT_ERROR_FILTER +/** @deprecated use `GIT_ERROR_REVERT` */ #define GITERR_REVERT GIT_ERROR_REVERT +/** @deprecated use `GIT_ERROR_CALLBACK` */ #define GITERR_CALLBACK GIT_ERROR_CALLBACK +/** @deprecated use `GIT_ERROR_CHERRYPICK` */ #define GITERR_CHERRYPICK GIT_ERROR_CHERRYPICK +/** @deprecated use `GIT_ERROR_DESCRIBE` */ #define GITERR_DESCRIBE GIT_ERROR_DESCRIBE +/** @deprecated use `GIT_ERROR_REBASE` */ #define GITERR_REBASE GIT_ERROR_REBASE +/** @deprecated use `GIT_ERROR_FILESYSTEM` */ #define GITERR_FILESYSTEM GIT_ERROR_FILESYSTEM +/** @deprecated use `GIT_ERROR_PATCH` */ #define GITERR_PATCH GIT_ERROR_PATCH +/** @deprecated use `GIT_ERROR_WORKTREE` */ #define GITERR_WORKTREE GIT_ERROR_WORKTREE +/** @deprecated use `GIT_ERROR_SHA1` */ #define GITERR_SHA1 GIT_ERROR_SHA1 - +/** @deprecated use `GIT_ERROR_SHA` */ #define GIT_ERROR_SHA1 GIT_ERROR_SHA /** @@ -500,37 +551,63 @@ GIT_EXTERN(void) giterr_set_oom(void); */ /**@{*/ +/* The git_idxentry_extended_flag_t enum */ +/** @deprecated use `GIT_INDEX_ENTRY_NAMEMASK` */ #define GIT_IDXENTRY_NAMEMASK GIT_INDEX_ENTRY_NAMEMASK +/** @deprecated use `GIT_INDEX_ENTRY_STAGEMASK` */ #define GIT_IDXENTRY_STAGEMASK GIT_INDEX_ENTRY_STAGEMASK +/** @deprecated use `GIT_INDEX_ENTRY_STAGESHIFT` */ #define GIT_IDXENTRY_STAGESHIFT GIT_INDEX_ENTRY_STAGESHIFT /* The git_indxentry_flag_t enum */ +/** @deprecated use `GIT_INDEX_ENTRY_EXTENDED` */ #define GIT_IDXENTRY_EXTENDED GIT_INDEX_ENTRY_EXTENDED +/** @deprecated use `GIT_INDEX_ENTRY_VALID` */ #define GIT_IDXENTRY_VALID GIT_INDEX_ENTRY_VALID +/** @deprecated use `GIT_INDEX_ENTRY_STAGE` */ #define GIT_IDXENTRY_STAGE(E) GIT_INDEX_ENTRY_STAGE(E) +/** @deprecated use `GIT_INDEX_ENTRY_STAGE_SET` */ #define GIT_IDXENTRY_STAGE_SET(E,S) GIT_INDEX_ENTRY_STAGE_SET(E,S) /* The git_idxentry_extended_flag_t enum */ +/** @deprecated use `GIT_INDEX_ENTRY_INTENT_TO_ADD` */ #define GIT_IDXENTRY_INTENT_TO_ADD GIT_INDEX_ENTRY_INTENT_TO_ADD +/** @deprecated use `GIT_INDEX_ENTRY_SKIP_WORKTREE` */ #define GIT_IDXENTRY_SKIP_WORKTREE GIT_INDEX_ENTRY_SKIP_WORKTREE +/** @deprecated use `GIT_INDEX_ENTRY_INTENT_TO_ADD | GIT_INDEX_ENTRY_SKIP_WORKTREE` */ #define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_INDEX_ENTRY_INTENT_TO_ADD | GIT_INDEX_ENTRY_SKIP_WORKTREE) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_EXTENDED2 (1 << 15) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_UPDATE (1 << 0) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_REMOVE (1 << 1) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_UPTODATE (1 << 2) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_ADDED (1 << 3) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_HASHED (1 << 4) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_UNHASHED (1 << 5) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_WT_REMOVE (1 << 6) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_CONFLICTED (1 << 7) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_UNPACKED (1 << 8) +/** @deprecated this value is not public */ #define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) /* The git_index_capability_t enum */ +/** @deprecated use `GIT_INDEX_CAPABILITY_IGNORE_CASE` */ #define GIT_INDEXCAP_IGNORE_CASE GIT_INDEX_CAPABILITY_IGNORE_CASE +/** @deprecated use `GIT_INDEX_CAPABILITY_NO_FILEMODE` */ #define GIT_INDEXCAP_NO_FILEMODE GIT_INDEX_CAPABILITY_NO_FILEMODE +/** @deprecated use `GIT_INDEX_CAPABILITY_NO_SYMLINKS` */ #define GIT_INDEXCAP_NO_SYMLINKS GIT_INDEX_CAPABILITY_NO_SYMLINKS +/** @deprecated use `GIT_INDEX_CAPABILITY_FROM_OWNER` */ #define GIT_INDEXCAP_FROM_OWNER GIT_INDEX_CAPABILITY_FROM_OWNER GIT_EXTERN(int) git_index_add_frombuffer( @@ -550,17 +627,28 @@ GIT_EXTERN(int) git_index_add_frombuffer( */ /**@{*/ +/** @deprecate use `git_object_t` */ #define git_otype git_object_t +/** @deprecate use `GIT_OBJECT_ANY` */ #define GIT_OBJ_ANY GIT_OBJECT_ANY +/** @deprecate use `GIT_OBJECT_INVALID` */ #define GIT_OBJ_BAD GIT_OBJECT_INVALID +/** @deprecated this value is not public */ #define GIT_OBJ__EXT1 0 +/** @deprecate use `GIT_OBJECT_COMMIT` */ #define GIT_OBJ_COMMIT GIT_OBJECT_COMMIT +/** @deprecate use `GIT_OBJECT_TREE` */ #define GIT_OBJ_TREE GIT_OBJECT_TREE +/** @deprecate use `GIT_OBJECT_BLOB` */ #define GIT_OBJ_BLOB GIT_OBJECT_BLOB +/** @deprecate use `GIT_OBJECT_TAG` */ #define GIT_OBJ_TAG GIT_OBJECT_TAG +/** @deprecated this value is not public */ #define GIT_OBJ__EXT2 5 +/** @deprecate use `GIT_OBJECT_OFS_DELTA` */ #define GIT_OBJ_OFS_DELTA GIT_OBJECT_OFS_DELTA +/** @deprecate use `GIT_OBJECT_REF_DELTA` */ #define GIT_OBJ_REF_DELTA GIT_OBJECT_REF_DELTA /** @@ -612,17 +700,27 @@ GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name); /**@{*/ /** Basic type of any Git reference. */ +/** @deprecate use `git_reference_t` */ #define git_ref_t git_reference_t +/** @deprecate use `git_reference_format_t` */ #define git_reference_normalize_t git_reference_format_t +/** @deprecate use `GIT_REFERENCE_INVALID` */ #define GIT_REF_INVALID GIT_REFERENCE_INVALID +/** @deprecate use `GIT_REFERENCE_DIRECT` */ #define GIT_REF_OID GIT_REFERENCE_DIRECT +/** @deprecate use `GIT_REFERENCE_SYMBOLIC` */ #define GIT_REF_SYMBOLIC GIT_REFERENCE_SYMBOLIC +/** @deprecate use `GIT_REFERENCE_ALL` */ #define GIT_REF_LISTALL GIT_REFERENCE_ALL +/** @deprecate use `GIT_REFERENCE_FORMAT_NORMAL` */ #define GIT_REF_FORMAT_NORMAL GIT_REFERENCE_FORMAT_NORMAL +/** @deprecate use `GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL` */ #define GIT_REF_FORMAT_ALLOW_ONELEVEL GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL +/** @deprecate use `GIT_REFERENCE_FORMAT_REFSPEC_PATTERN` */ #define GIT_REF_FORMAT_REFSPEC_PATTERN GIT_REFERENCE_FORMAT_REFSPEC_PATTERN +/** @deprecate use `GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND` */ #define GIT_REF_FORMAT_REFSPEC_SHORTHAND GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND /** @@ -663,8 +761,11 @@ GIT_EXTERN(int) git_tag_create_frombuffer( typedef git_revspec_t git_revparse_mode_t; +/** @deprecated use `GIT_REVSPEC_SINGLE` */ #define GIT_REVPARSE_SINGLE GIT_REVSPEC_SINGLE +/** @deprecated use `GIT_REVSPEC_RANGE` */ #define GIT_REVPARSE_RANGE GIT_REVSPEC_RANGE +/** @deprecated use `GIT_REVSPEC_MERGE_BASE` */ #define GIT_REVPARSE_MERGE_BASE GIT_REVSPEC_MERGE_BASE /**@}*/ @@ -693,14 +794,22 @@ typedef git_credential_sign_cb git_cred_sign_cb; typedef git_credential_ssh_interactive_cb git_cred_ssh_interactive_callback; typedef git_credential_ssh_interactive_cb git_cred_ssh_interactive_cb; +/** @deprecated use `git_credential_t` */ #define git_credtype_t git_credential_t +/** @deprecated use `GIT_CREDENTIAL_USERPASS_PLAINTEXT` */ #define GIT_CREDTYPE_USERPASS_PLAINTEXT GIT_CREDENTIAL_USERPASS_PLAINTEXT +/** @deprecated use `GIT_CREDENTIAL_SSH_KEY` */ #define GIT_CREDTYPE_SSH_KEY GIT_CREDENTIAL_SSH_KEY +/** @deprecated use `GIT_CREDENTIAL_SSH_CUSTOM` */ #define GIT_CREDTYPE_SSH_CUSTOM GIT_CREDENTIAL_SSH_CUSTOM +/** @deprecated use `GIT_CREDENTIAL_DEFAULT` */ #define GIT_CREDTYPE_DEFAULT GIT_CREDENTIAL_DEFAULT +/** @deprecated use `GIT_CREDENTIAL_SSH_INTERACTIVE` */ #define GIT_CREDTYPE_SSH_INTERACTIVE GIT_CREDENTIAL_SSH_INTERACTIVE +/** @deprecated use `GIT_CREDENTIAL_USERNAME` */ #define GIT_CREDTYPE_USERNAME GIT_CREDENTIAL_USERNAME +/** @deprecated use `GIT_CREDENTIAL_SSH_MEMORY` */ #define GIT_CREDTYPE_SSH_MEMORY GIT_CREDENTIAL_SSH_MEMORY GIT_EXTERN(void) git_cred_free(git_credential *cred); @@ -778,8 +887,11 @@ typedef git_trace_cb git_trace_callback; /**@{*/ #ifndef GIT_EXPERIMENTAL_SHA256 +/** Deprecated OID "raw size" definition */ # define GIT_OID_RAWSZ GIT_OID_SHA1_SIZE +/** Deprecated OID "hex size" definition */ # define GIT_OID_HEXSZ GIT_OID_SHA1_HEXSIZE +/** Deprecated OID "hex zero" definition */ # define GIT_OID_HEX_ZERO GIT_OID_SHA1_HEXZERO #endif diff --git a/include/git2/describe.h b/include/git2/describe.h index 7a796f1309c..938c470d272 100644 --- a/include/git2/describe.h +++ b/include/git2/describe.h @@ -13,10 +13,14 @@ /** * @file git2/describe.h - * @brief Git describing routines + * @brief Describe a commit in reference to tags * @defgroup git_describe Git describing routines * @ingroup Git * @{ + * + * Describe a commit, showing information about how the current commit + * relates to the tags. This can be useful for showing how the current + * commit has changed from a particular tagged version of the repository. */ GIT_BEGIN_DECL @@ -60,10 +64,15 @@ typedef struct git_describe_options { int show_commit_oid_as_fallback; } git_describe_options; +/** Default maximum candidate tags */ #define GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS 10 +/** Default abbreviated size */ #define GIT_DESCRIBE_DEFAULT_ABBREVIATED_SIZE 7 +/** Current version for the `git_describe_options` structure */ #define GIT_DESCRIBE_OPTIONS_VERSION 1 + +/** Static constructor for `git_describe_options` */ #define GIT_DESCRIBE_OPTIONS_INIT { \ GIT_DESCRIBE_OPTIONS_VERSION, \ GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS, \ @@ -110,7 +119,10 @@ typedef struct { const char *dirty_suffix; } git_describe_format_options; +/** Current version for the `git_describe_format_options` structure */ #define GIT_DESCRIBE_FORMAT_OPTIONS_VERSION 1 + +/** Static constructor for `git_describe_format_options` */ #define GIT_DESCRIBE_FORMAT_OPTIONS_INIT { \ GIT_DESCRIBE_FORMAT_OPTIONS_VERSION, \ GIT_DESCRIBE_DEFAULT_ABBREVIATED_SIZE, \ diff --git a/include/git2/diff.h b/include/git2/diff.h index 384b6e74570..b12e8ab2754 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -15,7 +15,7 @@ /** * @file git2/diff.h - * @brief Git tree and file differencing routines. + * @brief Indicate the differences between two versions of the repository * @ingroup Git * @{ */ @@ -342,6 +342,12 @@ typedef struct { * diff process continues. * - returns 0, the delta is inserted into the diff, and the diff process * continues. + * + * @param diff_so_far the diff structure as it currently exists + * @param delta_to_add the delta that is to be added + * @param matched_pathspec the pathspec + * @param payload the user-specified callback payload + * @return 0 on success, 1 to skip this delta, or an error code */ typedef int GIT_CALLBACK(git_diff_notify_cb)( const git_diff *diff_so_far, @@ -357,7 +363,8 @@ typedef int GIT_CALLBACK(git_diff_notify_cb)( * @param diff_so_far The diff being generated. * @param old_path The path to the old file or NULL. * @param new_path The path to the new file or NULL. - * @return Non-zero to abort the diff. + * @param payload the user-specified callback payload + * @return 0 or an error code */ typedef int GIT_CALLBACK(git_diff_progress_cb)( const git_diff *diff_so_far, @@ -463,10 +470,10 @@ typedef struct { const char *new_prefix; } git_diff_options; -/* The current version of the diff options structure */ +/** The current version of the diff options structure */ #define GIT_DIFF_OPTIONS_VERSION 1 -/* Stack initializer for diff options. Alternatively use +/** Stack initializer for diff options. Alternatively use * `git_diff_options_init` programmatic initialization. */ #define GIT_DIFF_OPTIONS_INIT \ @@ -492,12 +499,14 @@ GIT_EXTERN(int) git_diff_options_init( * @param delta A pointer to the delta data for the file * @param progress Goes from 0 to 1 over the diff * @param payload User-specified pointer from foreach function + * @return 0 or an error code */ typedef int GIT_CALLBACK(git_diff_file_cb)( const git_diff_delta *delta, float progress, void *payload); +/** Maximum size of the hunk header */ #define GIT_DIFF_HUNK_HEADER_SIZE 128 /** @@ -558,6 +567,11 @@ typedef struct { /** * When iterating over a diff, callback that will be made for * binary content within the diff. + * + * @param delta the delta + * @param binary the binary content + * @param payload the user-specified callback payload + * @return 0 or an error code */ typedef int GIT_CALLBACK(git_diff_binary_cb)( const git_diff_delta *delta, @@ -584,6 +598,11 @@ typedef struct { /** * When iterating over a diff, callback that will be made per hunk. + * + * @param delta the delta + * @param hunk the hunk + * @param payload the user-specified callback payload + * @return 0 or an error code */ typedef int GIT_CALLBACK(git_diff_hunk_cb)( const git_diff_delta *delta, @@ -645,6 +664,12 @@ typedef struct { * When printing a diff, callback that will be made to output each line * of text. This uses some extra GIT_DIFF_LINE_... constants for output * of lines of file and hunk headers. + * + * @param delta the delta that contains the line + * @param hunk the hunk that contains the line + * @param line the line in the diff + * @param payload the user-specified callback payload + * @return 0 or an error code */ typedef int GIT_CALLBACK(git_diff_line_cb)( const git_diff_delta *delta, /**< delta that contains this data */ @@ -802,7 +827,10 @@ typedef struct { git_diff_similarity_metric *metric; } git_diff_find_options; +/** Current version for the `git_diff_find_options` structure */ #define GIT_DIFF_FIND_OPTIONS_VERSION 1 + +/** Static constructor for `git_diff_find_options` */ #define GIT_DIFF_FIND_OPTIONS_INIT {GIT_DIFF_FIND_OPTIONS_VERSION} /** @@ -1296,10 +1324,10 @@ typedef struct { git_oid_t oid_type; } git_diff_parse_options; -/* The current version of the diff parse options structure */ +/** The current version of the diff parse options structure */ #define GIT_DIFF_PARSE_OPTIONS_VERSION 1 -/* Stack initializer for diff parse options. Alternatively use +/** Stack initializer for diff parse options. Alternatively use * `git_diff_parse_options_init` programmatic initialization. */ #define GIT_DIFF_PARSE_OPTIONS_INIT \ @@ -1432,7 +1460,10 @@ typedef struct git_diff_patchid_options { unsigned int version; } git_diff_patchid_options; +/** Current version for the `git_diff_patchid_options` structure */ #define GIT_DIFF_PATCHID_OPTIONS_VERSION 1 + +/** Static constructor for `git_diff_patchid_options` */ #define GIT_DIFF_PATCHID_OPTIONS_INIT { GIT_DIFF_PATCHID_OPTIONS_VERSION } /** @@ -1470,8 +1501,7 @@ GIT_EXTERN(int) git_diff_patchid_options_init( */ GIT_EXTERN(int) git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts); -GIT_END_DECL - /** @} */ +GIT_END_DECL #endif diff --git a/include/git2/email.h b/include/git2/email.h index 08b573e8c68..ad37e424985 100644 --- a/include/git2/email.h +++ b/include/git2/email.h @@ -12,7 +12,7 @@ /** * @file git2/email.h - * @brief Git email formatting and application routines. + * @brief Produce email-ready patches * @ingroup Git * @{ */ @@ -71,11 +71,14 @@ typedef struct { size_t reroll_number; } git_email_create_options; -/* +/** Current version for the `git_email_create_options` structure */ +#define GIT_EMAIL_CREATE_OPTIONS_VERSION 1 + +/** Static constructor for `git_email_create_options` + * * By default, our options include rename detection and binary * diffs to match `git format-patch`. */ -#define GIT_EMAIL_CREATE_OPTIONS_VERSION 1 #define GIT_EMAIL_CREATE_OPTIONS_INIT \ { \ GIT_EMAIL_CREATE_OPTIONS_VERSION, \ @@ -91,14 +94,14 @@ typedef struct { * @param out buffer to store the e-mail patch in * @param commit commit to create a patch for * @param opts email creation options + * @return 0 or an error code */ GIT_EXTERN(int) git_email_create_from_commit( git_buf *out, git_commit *commit, const git_email_create_options *opts); -GIT_END_DECL - /** @} */ +GIT_END_DECL #endif diff --git a/include/git2/errors.h b/include/git2/errors.h index 52fa5f0720d..11413907e7c 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -11,7 +11,7 @@ /** * @file git2/errors.h - * @brief Git error handling routines and variables + * @brief Error handling routines and variables * @ingroup Git * @{ */ @@ -19,13 +19,20 @@ GIT_BEGIN_DECL /** Generic return codes */ typedef enum { - GIT_OK = 0, /**< No error */ + /** + * No error occurred; the call was successful. + */ + GIT_OK = 0, + + /** + * An error occurred; call `git_error_last` for more information. + */ + GIT_ERROR = -1, - GIT_ERROR = -1, /**< Generic error */ - GIT_ENOTFOUND = -3, /**< Requested object could not be found */ - GIT_EEXISTS = -4, /**< Object exists preventing operation */ - GIT_EAMBIGUOUS = -5, /**< More than one object matches */ - GIT_EBUFS = -6, /**< Output buffer too short to hold data */ + GIT_ENOTFOUND = -3, /**< Requested object could not be found. */ + GIT_EEXISTS = -4, /**< Object exists preventing operation. */ + GIT_EAMBIGUOUS = -5, /**< More than one object matches. */ + GIT_EBUFS = -6, /**< Output buffer too short to hold data. */ /** * GIT_EUSER is a special error that is never generated by libgit2 @@ -34,10 +41,10 @@ typedef enum { */ GIT_EUSER = -7, - GIT_EBAREREPO = -8, /**< Operation not allowed on bare repository */ - GIT_EUNBORNBRANCH = -9, /**< HEAD refers to branch with no commits */ - GIT_EUNMERGED = -10, /**< Merge in progress prevented operation */ - GIT_ENONFASTFORWARD = -11, /**< Reference was not fast-forwardable */ + GIT_EBAREREPO = -8, /**< Operation not allowed on bare repository. */ + GIT_EUNBORNBRANCH = -9, /**< HEAD refers to branch with no commits. */ + GIT_EUNMERGED = -10, /**< Merge in progress prevented operation */ + GIT_ENONFASTFORWARD = -11, /**< Reference was not fast-forwardable */ GIT_EINVALIDSPEC = -12, /**< Name/ref spec was not in a valid format */ GIT_ECONFLICT = -13, /**< Checkout conflicts prevented operation */ GIT_ELOCKED = -14, /**< Lock file prevented operation */ @@ -66,17 +73,9 @@ typedef enum { } git_error_code; /** - * Structure to store extra details of the last error that occurred. - * - * This is kept on a per-thread basis if GIT_THREADS was defined when the - * library was build, otherwise one is kept globally for the library + * Error classes are the category of error. They reflect the area of the + * code where an error occurred. */ -typedef struct { - char *message; - int klass; -} git_error; - -/** Error classes */ typedef enum { GIT_ERROR_NONE = 0, GIT_ERROR_NOMEMORY, @@ -117,6 +116,17 @@ typedef enum { GIT_ERROR_GRAFTS } git_error_t; +/** + * Structure to store extra details of the last error that occurred. + * + * This is kept on a per-thread basis if GIT_THREADS was defined when the + * library was build, otherwise one is kept globally for the library + */ +typedef struct { + char *message; /**< The error message for the last error. */ + int klass; /**< The category of the last error. @type git_error_t */ +} git_error; + /** * Return the last `git_error` object that was generated for the * current thread. @@ -134,10 +144,11 @@ typedef enum { * The memory for this object is managed by libgit2. It should not * be freed. * - * @return A git_error object. + * @return A pointer to a `git_error` object that describes the error. */ GIT_EXTERN(const git_error *) git_error_last(void); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/filter.h b/include/git2/filter.h index 79bf14ce5b7..cf6c5f59d97 100644 --- a/include/git2/filter.h +++ b/include/git2/filter.h @@ -14,9 +14,15 @@ /** * @file git2/filter.h - * @brief Git filter APIs - * + * @brief Filters modify files during checkout or commit * @ingroup Git + * + * During checkout, filters update a file from a "canonical" state to + * a format appropriate for the local filesystem; during commit, filters + * produce the canonical state. For example, on Windows, the line ending + * filters _may_ take a canonical state (with Unix-style newlines) in + * the repository, and place the contents on-disk with Windows-style + * `\r\n` line endings. * @{ */ GIT_BEGIN_DECL @@ -79,8 +85,11 @@ typedef struct { git_oid attr_commit_id; } git_filter_options; - #define GIT_FILTER_OPTIONS_VERSION 1 - #define GIT_FILTER_OPTIONS_INIT {GIT_FILTER_OPTIONS_VERSION} +/** Current version for the `git_filter_options` structure */ +#define GIT_FILTER_OPTIONS_VERSION 1 + +/** Static constructor for `git_filter_options` */ +#define GIT_FILTER_OPTIONS_INIT {GIT_FILTER_OPTIONS_VERSION} /** * A filter that can transform file data @@ -268,9 +277,7 @@ GIT_EXTERN(int) git_filter_list_stream_blob( */ GIT_EXTERN(void) git_filter_list_free(git_filter_list *filters); - -GIT_END_DECL - /** @} */ +GIT_END_DECL #endif diff --git a/include/git2/global.h b/include/git2/global.h index 2a87e10c6c8..f15eb2d2880 100644 --- a/include/git2/global.h +++ b/include/git2/global.h @@ -9,6 +9,12 @@ #include "common.h" +/** + * @file git2/global.h + * @brief libgit2 library initializer and shutdown functionality + * @ingroup Git + * @{ + */ GIT_BEGIN_DECL /** @@ -32,7 +38,7 @@ GIT_EXTERN(int) git_libgit2_init(void); * many times as `git_libgit2_init()` was called - it will return the * number of remainining initializations that have not been shutdown * (after this one). - * + * * @return the number of remaining initializations of the library, or an * error code. */ @@ -40,5 +46,6 @@ GIT_EXTERN(int) git_libgit2_shutdown(void); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/graph.h b/include/git2/graph.h index 56edb2f87f9..1792020a4be 100644 --- a/include/git2/graph.h +++ b/include/git2/graph.h @@ -13,7 +13,7 @@ /** * @file git2/graph.h - * @brief Git graph traversal routines + * @brief Graph traversal routines * @defgroup git_revwalk Git graph traversal routines * @ingroup Git * @{ @@ -61,8 +61,8 @@ GIT_EXTERN(int) git_graph_descendant_of( * * @param repo the repository where the commits exist * @param commit a previously loaded commit - * @param length the number of commits in the provided `descendant_array` * @param descendant_array oids of the commits + * @param length the number of commits in the provided `descendant_array` * @return 1 if the given commit is an ancestor of any of the given potential * descendants, 0 if not, error code otherwise. */ @@ -74,4 +74,5 @@ GIT_EXTERN(int) git_graph_reachable_from_any( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/ignore.h b/include/git2/ignore.h index 4c441c63384..730f2214ba5 100644 --- a/include/git2/ignore.h +++ b/include/git2/ignore.h @@ -10,6 +10,15 @@ #include "common.h" #include "types.h" +/** + * @file git2/ignore.h + * @brief Ignore particular untracked files + * @ingroup Git + * @{ + * + * When examining the repository status, git can optionally ignore + * specified untracked files. + */ GIT_BEGIN_DECL /** @@ -73,6 +82,7 @@ GIT_EXTERN(int) git_ignore_path_is_ignored( git_repository *repo, const char *path); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/index.h b/include/git2/index.h index 6e806371bf4..9f3efe1fc7e 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -15,9 +15,14 @@ /** * @file git2/index.h - * @brief Git index parsing and manipulation routines + * @brief Index (aka "cache" aka "staging area") * @defgroup git_index Git index parsing and manipulation routines * @ingroup Git + * + * The index (or "cache", or "staging area") is the contents of the + * next commit. In addition, the index stores other data, such as + * conflicts that occurred during the last merge operation, and + * the "treecache" to speed up various on-disk operations. * @{ */ GIT_BEGIN_DECL @@ -77,8 +82,11 @@ typedef struct git_index_entry { * data in the `flags`. */ +/** Mask for name length */ #define GIT_INDEX_ENTRY_NAMEMASK (0x0fff) +/** Mask for index entry stage */ #define GIT_INDEX_ENTRY_STAGEMASK (0x3000) +/** Shift bits for index entry */ #define GIT_INDEX_ENTRY_STAGESHIFT 12 /** @@ -89,9 +97,17 @@ typedef enum { GIT_INDEX_ENTRY_VALID = (0x8000) } git_index_entry_flag_t; +/** + * Macro to get the stage value (0 for the "main index", or a conflict + * value) from an index entry. + */ #define GIT_INDEX_ENTRY_STAGE(E) \ (((E)->flags & GIT_INDEX_ENTRY_STAGEMASK) >> GIT_INDEX_ENTRY_STAGESHIFT) +/** + * Macro to set the stage value (0 for the "main index", or a conflict + * value) for an index entry. + */ #define GIT_INDEX_ENTRY_STAGE_SET(E,S) do { \ (E)->flags = ((E)->flags & ~GIT_INDEX_ENTRY_STAGEMASK) | \ (((S) & 0x03) << GIT_INDEX_ENTRY_STAGESHIFT); } while (0) @@ -131,7 +147,14 @@ typedef enum { } git_index_capability_t; -/** Callback for APIs that add/remove/update files matching pathspec */ +/** + * Callback for APIs that add/remove/update files matching pathspec + * + * @param path the path + * @param matched_pathspec the given pathspec + * @param payload the user-specified payload + * @return 0 to continue with the index operation, positive number to skip this file for the index operation, negative number on failure + */ typedef int GIT_CALLBACK(git_index_matched_path_cb)( const char *path, const char *matched_pathspec, void *payload); @@ -166,6 +189,30 @@ typedef enum { GIT_INDEX_STAGE_THEIRS = 3 } git_index_stage_t; +#ifdef GIT_EXPERIMENTAL_SHA256 + +/** + * Creates a new bare Git index object, without a repository to back + * it. This index object is capable of storing SHA256 objects. + * + * @param index_out the pointer for the new index + * @param index_path the path to the index file in disk + * @param oid_type the object ID type to use for the repository + * @return 0 or an error code + */ +GIT_EXTERN(int) git_index_open(git_index **index_out, const char *index_path, git_oid_t oid_type); + +/** + * Create an in-memory index object. + * + * @param index_out the pointer for the new index + * @param oid_type the object ID type to use for the repository + * @return 0 or an error code + */ +GIT_EXTERN(int) git_index_new(git_index **index_out, git_oid_t oid_type); + +#else + /** * Create a new bare Git index object as a memory representation * of the Git index file in 'index_path', without a repository @@ -180,16 +227,11 @@ typedef enum { * * The index must be freed once it's no longer in use. * - * @param out the pointer for the new index + * @param index_out the pointer for the new index * @param index_path the path to the index file in disk * @return 0 or an error code */ - -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path, git_oid_t oid_type); -#else -GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path); -#endif +GIT_EXTERN(int) git_index_open(git_index **index_out, const char *index_path); /** * Create an in-memory index object. @@ -199,13 +241,11 @@ GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path); * * The index must be freed once it's no longer in use. * - * @param out the pointer for the new index + * @param index_out the pointer for the new index * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_index_new(git_index **out, git_oid_t oid_type); -#else -GIT_EXTERN(int) git_index_new(git_index **out); +GIT_EXTERN(int) git_index_new(git_index **index_out); + #endif /** @@ -845,4 +885,5 @@ GIT_EXTERN(void) git_index_conflict_iterator_free( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/indexer.h b/include/git2/indexer.h index 630eef93456..d47ce2c1885 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -4,13 +4,23 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef _INCLUDE_git_indexer_h__ -#define _INCLUDE_git_indexer_h__ +#ifndef INCLUDE_git_indexer_h__ +#define INCLUDE_git_indexer_h__ #include "common.h" #include "types.h" #include "oid.h" +/** + * @file git2/indexer.h + * @brief Packfile indexing + * @ingroup Git + * @{ + * + * Indexing is the operation of taking a packfile - which is simply a + * collection of unordered commits - and producing an "index" so that + * one can lookup a commit in the packfile by object ID. + */ GIT_BEGIN_DECL /** A git indexer object */ @@ -53,6 +63,7 @@ typedef struct git_indexer_progress { * * @param stats Structure containing information about the state of the transfer * @param payload Payload provided by caller + * @return 0 on success or an error code */ typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *stats, void *payload); @@ -85,7 +96,10 @@ typedef struct git_indexer_options { unsigned char verify; } git_indexer_options; +/** Current version for the `git_indexer_options` structure */ #define GIT_INDEXER_OPTIONS_VERSION 1 + +/** Static constructor for `git_indexer_options` */ #define GIT_INDEXER_OPTIONS_INIT { GIT_INDEXER_OPTIONS_VERSION } /** @@ -190,6 +204,7 @@ GIT_EXTERN(const char *) git_indexer_name(const git_indexer *idx); */ GIT_EXTERN(void) git_indexer_free(git_indexer *idx); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/mailmap.h b/include/git2/mailmap.h index 7c3f60fcc82..fd6ae7170c2 100644 --- a/include/git2/mailmap.h +++ b/include/git2/mailmap.h @@ -13,10 +13,15 @@ /** * @file git2/mailmap.h - * @brief Mailmap parsing routines + * @brief Mailmaps provide alternate email addresses for users * @defgroup git_mailmap Git mailmap routines * @ingroup Git * @{ + * + * A mailmap can be used to specify alternate email addresses for + * repository committers or authors. This allows systems to map + * commits made using different email addresses to the same logical + * person. */ GIT_BEGIN_DECL @@ -112,4 +117,5 @@ GIT_EXTERN(int) git_mailmap_resolve_signature( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/merge.h b/include/git2/merge.h index 11f84f1fb8a..be3b065b8a2 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -17,9 +17,12 @@ /** * @file git2/merge.h - * @brief Git merge routines + * @brief Merge re-joins diverging branches of history * @defgroup git_merge Git merge routines * @ingroup Git + * + * Merge will take two commits and attempt to produce a commit that + * includes the changes that were made in both branches. * @{ */ GIT_BEGIN_DECL @@ -45,7 +48,10 @@ typedef struct { unsigned int mode; } git_merge_file_input; +/** Current version for the `git_merge_file_input_options` structure */ #define GIT_MERGE_FILE_INPUT_VERSION 1 + +/** Static constructor for `git_merge_file_input_options` */ #define GIT_MERGE_FILE_INPUT_INIT {GIT_MERGE_FILE_INPUT_VERSION} /** @@ -180,6 +186,7 @@ typedef enum { GIT_MERGE_FILE_ACCEPT_CONFLICTS = (1 << 9) } git_merge_file_flag_t; +/** Default size for conflict markers */ #define GIT_MERGE_CONFLICT_MARKER_SIZE 7 /** @@ -217,7 +224,10 @@ typedef struct { unsigned short marker_size; } git_merge_file_options; +/** Current version for the `git_merge_file_options` structure */ #define GIT_MERGE_FILE_OPTIONS_VERSION 1 + +/** Static constructor for `git_merge_file_options` */ #define GIT_MERGE_FILE_OPTIONS_INIT {GIT_MERGE_FILE_OPTIONS_VERSION} /** @@ -312,7 +322,10 @@ typedef struct { uint32_t file_flags; } git_merge_options; +/** Current version for the `git_merge_options` structure */ #define GIT_MERGE_OPTIONS_VERSION 1 + +/** Static constructor for `git_merge_options` */ #define GIT_MERGE_OPTIONS_INIT { \ GIT_MERGE_OPTIONS_VERSION, GIT_MERGE_FIND_RENAMES } @@ -654,4 +667,5 @@ GIT_EXTERN(int) git_merge( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/message.h b/include/git2/message.h index cd3ddf730e0..874d027f23f 100644 --- a/include/git2/message.h +++ b/include/git2/message.h @@ -12,7 +12,7 @@ /** * @file git2/message.h - * @brief Git message management routines + * @brief Commit messages * @ingroup Git * @{ */ @@ -83,4 +83,4 @@ GIT_EXTERN(void) git_message_trailer_array_free(git_message_trailer_array *arr); /** @} */ GIT_END_DECL -#endif /* INCLUDE_git_message_h__ */ +#endif diff --git a/include/git2/net.h b/include/git2/net.h index 8103eafbfda..93bdac4995f 100644 --- a/include/git2/net.h +++ b/include/git2/net.h @@ -13,12 +13,13 @@ /** * @file git2/net.h - * @brief Git networking declarations + * @brief Low-level networking functionality * @ingroup Git * @{ */ GIT_BEGIN_DECL +/** Default git protocol port number */ #define GIT_DEFAULT_PORT "9418" /** @@ -51,4 +52,5 @@ struct git_remote_head { /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/notes.h b/include/git2/notes.h index c135881a7c8..3784d5f5222 100644 --- a/include/git2/notes.h +++ b/include/git2/notes.h @@ -11,7 +11,7 @@ /** * @file git2/notes.h - * @brief Git notes management routines + * @brief Notes are metadata attached to an object * @defgroup git_note Git notes management routines * @ingroup Git * @{ @@ -21,13 +21,15 @@ GIT_BEGIN_DECL /** * Callback for git_note_foreach. * - * Receives: - * - blob_id: Oid of the blob containing the message - * - annotated_object_id: Oid of the git object being annotated - * - payload: Payload data passed to `git_note_foreach` + * @param blob_id object id of the blob containing the message + * @param annotated_object_id the id of the object being annotated + * @param payload user-specified data to the foreach function + * @return 0 on success, or a negative number on failure */ typedef int GIT_CALLBACK(git_note_foreach_cb)( - const git_oid *blob_id, const git_oid *annotated_object_id, void *payload); + const git_oid *blob_id, + const git_oid *annotated_object_id, + void *payload); /** * note iterator @@ -303,4 +305,5 @@ GIT_EXTERN(int) git_note_foreach( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/object.h b/include/git2/object.h index 6384aaa6e94..8a50239fe8d 100644 --- a/include/git2/object.h +++ b/include/git2/object.h @@ -14,13 +14,14 @@ /** * @file git2/object.h - * @brief Git revision object management routines + * @brief Objects are blobs (files), trees (directories), commits, and annotated tags * @defgroup git_object Git revision object management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL +/** Maximum size of a git object */ #define GIT_OBJECT_SIZE_MAX UINT64_MAX /** @@ -53,18 +54,18 @@ GIT_EXTERN(int) git_object_lookup( * * The object obtained will be so that its identifier * matches the first 'len' hexadecimal characters - * (packets of 4 bits) of the given 'id'. - * 'len' must be at least GIT_OID_MINPREFIXLEN, and - * long enough to identify a unique object matching - * the prefix; otherwise the method will fail. + * (packets of 4 bits) of the given `id`. `len` must be + * at least `GIT_OID_MINPREFIXLEN`, and long enough to + * identify a unique object matching the prefix; otherwise + * the method will fail. * * The generated reference is owned by the repository and * should be closed with the `git_object_free` method * instead of free'd manually. * - * The 'type' parameter must match the type of the object + * The `type` parameter must match the type of the object * in the odb; the method will fail otherwise. - * The special value 'GIT_OBJECT_ANY' may be passed to let + * The special value `GIT_OBJECT_ANY` may be passed to let * the method guess the object's type. * * @param object_out pointer where to store the looked-up object @@ -260,7 +261,7 @@ GIT_EXTERN(int) git_object_rawcontent_is_valid( * @warning This function is experimental and its signature may change in * the future. * - * @param valid Output pointer to set with validity of the object content + * @param[out] valid Output pointer to set with validity of the object content * @param buf The contents to validate * @param len The length of the buffer * @param object_type The type of the object in the buffer diff --git a/include/git2/odb.h b/include/git2/odb.h index 4a7af07b81f..e809c36d70e 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -15,7 +15,7 @@ /** * @file git2/odb.h - * @brief Git object database routines + * @brief An object database manages the storage of git objects * @defgroup git_odb Git object database routines * @ingroup Git * @{ @@ -35,6 +35,10 @@ typedef enum { /** * Function type for callbacks from git_odb_foreach. + * + * @param id an id of an object in the object database + * @param payload the payload from the initial call to git_odb_foreach + * @return 0 on success, or an error code */ typedef int GIT_CALLBACK(git_odb_foreach_cb)(const git_oid *id, void *payload); @@ -49,30 +53,53 @@ typedef struct { git_oid_t oid_type; } git_odb_options; -/* The current version of the diff options structure */ +/** The current version of the diff options structure */ #define GIT_ODB_OPTIONS_VERSION 1 -/* Stack initializer for odb options. Alternatively use +/** + * Stack initializer for odb options. Alternatively use * `git_odb_options_init` programmatic initialization. */ #define GIT_ODB_OPTIONS_INIT { GIT_ODB_OPTIONS_VERSION } +#ifdef GIT_EXPERIMENTAL_SHA256 + /** * Create a new object database with no backends. * - * Before the ODB can be used for read/writing, a custom database - * backend must be manually added using `git_odb_add_backend()` + * @param[out] odb location to store the database pointer, if opened. + * @param opts the options for this object database or NULL for defaults + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_new(git_odb **odb, const git_odb_options *opts); + +/** + * Create a new object database and automatically add loose and packed + * backends. * - * @param out location to store the database pointer, if opened. + * @param[out] odb_out location to store the database pointer, if opened. * Set to NULL if the open failed. + * @param objects_dir path of the backends' "objects" directory. * @param opts the options for this object database or NULL for defaults * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_odb_new(git_odb **out, const git_odb_options *opts); +GIT_EXTERN(int) git_odb_open( + git_odb **odb_out, + const char *objects_dir, + const git_odb_options *opts); + #else -GIT_EXTERN(int) git_odb_new(git_odb **out); -#endif + +/** + * Create a new object database with no backends. + * + * Before the ODB can be used for read/writing, a custom database + * backend must be manually added using `git_odb_add_backend()` + * + * @param[out] odb location to store the database pointer, if opened. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_new(git_odb **odb); /** * Create a new object database and automatically add @@ -85,19 +112,12 @@ GIT_EXTERN(int) git_odb_new(git_odb **out); * assuming `objects_dir` as the Objects folder which * contains a 'pack/' folder with the corresponding data * - * @param out location to store the database pointer, if opened. + * @param[out] odb_out location to store the database pointer, if opened. * Set to NULL if the open failed. * @param objects_dir path of the backends' "objects" directory. - * @param opts the options for this object database or NULL for defaults * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_odb_open( - git_odb **out, - const char *objects_dir, - const git_odb_options *opts); -#else -GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); +GIT_EXTERN(int) git_odb_open(git_odb **odb_out, const char *objects_dir); #endif /** @@ -134,13 +154,13 @@ GIT_EXTERN(void) git_odb_free(git_odb *db); * internally cached, so it should be closed * by the user once it's no longer in use. * - * @param out pointer where to store the read object + * @param[out] obj pointer where to store the read object * @param db database to search for the object in. * @param id identity of the object to read. * @return 0 if the object was read, GIT_ENOTFOUND if the object is * not in the database. */ -GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id); +GIT_EXTERN(int) git_odb_read(git_odb_object **obj, git_odb *db, const git_oid *id); /** * Read an object from the database, given a prefix @@ -160,7 +180,7 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i * internally cached, so it should be closed * by the user once it's no longer in use. * - * @param out pointer where to store the read object + * @param[out] obj pointer where to store the read object * @param db database to search for the object in. * @param short_id a prefix of the id of the object to read. * @param len the length of the prefix @@ -168,7 +188,7 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i * database. GIT_EAMBIGUOUS if the prefix is ambiguous * (several objects match the prefix) */ -GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len); +GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **obj, git_odb *db, const git_oid *short_id, size_t len); /** * Read the header of an object from the database, without @@ -180,8 +200,8 @@ GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git * of an object, so the whole object will be read and then the * header will be returned. * - * @param len_out pointer where to store the length - * @param type_out pointer where to store the type + * @param[out] len_out pointer where to store the length + * @param[out] type_out pointer where to store the type * @param db database to search for the object in. * @param id identity of the object to read. * @return 0 if the object was read, GIT_ENOTFOUND if the object is not @@ -301,7 +321,10 @@ GIT_EXTERN(int) git_odb_refresh(git_odb *db); * @param payload data to pass to the callback * @return 0 on success, non-zero callback return value, or error code */ -GIT_EXTERN(int) git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload); +GIT_EXTERN(int) git_odb_foreach( + git_odb *db, + git_odb_foreach_cb cb, + void *payload); /** * Write an object directly into the ODB @@ -316,7 +339,7 @@ GIT_EXTERN(int) git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payloa * * @param out pointer to store the OID result of the write * @param odb object database where to store the object - * @param data buffer with the data to store + * @param data @type `const unsigned char *` buffer with the data to store * @param len size of the buffer * @param type type of the data to store * @return 0 or an error code @@ -466,29 +489,54 @@ GIT_EXTERN(int) git_odb_write_pack( GIT_EXTERN(int) git_odb_write_multi_pack_index( git_odb *db); +#ifdef GIT_EXPERIMENTAL_SHA256 + /** - * Determine the object-ID (sha1 or sha256 hash) of a data buffer + * Generate the object ID (in SHA1 or SHA256 format) for a given data buffer. * - * The resulting OID will be the identifier for the data buffer as if - * the data buffer it were to written to the ODB. - * - * @param out the resulting object-ID. + * @param[out] oid the resulting object ID. * @param data data to hash * @param len size of the data * @param object_type of the data to hash * @param oid_type the oid type to hash to * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 GIT_EXTERN(int) git_odb_hash( - git_oid *out, + git_oid *oid, const void *data, size_t len, git_object_t object_type, git_oid_t oid_type); + +/** + * Determine the object ID of a file on disk. + * + * @param[out] oid oid structure the result is written into. + * @param path file to read and determine object id for + * @param object_type of the data to hash + * @param oid_type the oid type to hash to + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_hashfile( + git_oid *oid, + const char *path, + git_object_t object_type, + git_oid_t oid_type); #else -GIT_EXTERN(int) git_odb_hash(git_oid *out, const void *data, size_t len, git_object_t type); -#endif + +/** + * Determine the object-ID (sha1 or sha256 hash) of a data buffer + * + * The resulting OID will be the identifier for the data buffer as if + * the data buffer it were to written to the ODB. + * + * @param[out] oid the resulting object-ID. + * @param data data to hash + * @param len size of the data + * @param object_type of the data to hash + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_hash(git_oid *oid, const void *data, size_t len, git_object_t object_type); /** * Read a file from disk and fill a git_oid with the object id @@ -498,20 +546,13 @@ GIT_EXTERN(int) git_odb_hash(git_oid *out, const void *data, size_t len, git_obj * the `-w` flag, however, with the --no-filters flag. * If you need filters, see git_repository_hashfile. * - * @param out oid structure the result is written into. + * @param[out] oid oid structure the result is written into. * @param path file to read and determine object id for * @param object_type of the data to hash - * @param oid_type the oid type to hash to * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_odb_hashfile( - git_oid *out, - const char *path, - git_object_t object_type, - git_oid_t oid_type); -#else -GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, git_object_t type); +GIT_EXTERN(int) git_odb_hashfile(git_oid *oid, const char *path, git_object_t object_type); + #endif /** @@ -557,7 +598,7 @@ GIT_EXTERN(const git_oid *) git_odb_object_id(git_odb_object *object); * This pointer is owned by the object and shall not be free'd. * * @param object the object - * @return a pointer to the data + * @return @type `const unsigned char *` a pointer to the data */ GIT_EXTERN(const void *) git_odb_object_data(git_odb_object *object); @@ -651,4 +692,5 @@ GIT_EXTERN(int) git_odb_set_commit_graph(git_odb *odb, git_commit_graph *cgraph) /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index 12dd0fd38a3..88ca29fb9f8 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -13,17 +13,13 @@ /** * @file git2/backend.h - * @brief Git custom backend functions + * @brief Object database backends manage the storage of git objects * @defgroup git_odb Git object database routines * @ingroup Git * @{ */ GIT_BEGIN_DECL -/* - * Constructors for in-box ODB backends. - */ - /** Options for configuring a packfile object backend. */ typedef struct { unsigned int version; /**< version for the struct */ @@ -35,56 +31,16 @@ typedef struct { git_oid_t oid_type; } git_odb_backend_pack_options; -/* The current version of the diff options structure */ +/** The current version of the diff options structure */ #define GIT_ODB_BACKEND_PACK_OPTIONS_VERSION 1 -/* Stack initializer for odb pack backend options. Alternatively use +/** + * Stack initializer for odb pack backend options. Alternatively use * `git_odb_backend_pack_options_init` programmatic initialization. */ #define GIT_ODB_BACKEND_PACK_OPTIONS_INIT \ { GIT_ODB_BACKEND_PACK_OPTIONS_VERSION } -/** - * Create a backend for the packfiles. - * - * @param out location to store the odb backend pointer - * @param objects_dir the Git repository's objects directory - * - * @return 0 or an error code - */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_odb_backend_pack( - git_odb_backend **out, - const char *objects_dir, - const git_odb_backend_pack_options *opts); -#else -GIT_EXTERN(int) git_odb_backend_pack( - git_odb_backend **out, - const char *objects_dir); -#endif - -/** - * Create a backend out of a single packfile - * - * This can be useful for inspecting the contents of a single - * packfile. - * - * @param out location to store the odb backend pointer - * @param index_file path to the packfile's .idx file - * - * @return 0 or an error code - */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_odb_backend_one_pack( - git_odb_backend **out, - const char *index_file, - const git_odb_backend_pack_options *opts); -#else -GIT_EXTERN(int) git_odb_backend_one_pack( - git_odb_backend **out, - const char *index_file); -#endif - typedef enum { GIT_ODB_BACKEND_LOOSE_FSYNC = (1 << 0) } git_odb_backend_loose_flag_t; @@ -118,30 +74,100 @@ typedef struct { git_oid_t oid_type; } git_odb_backend_loose_options; -/* The current version of the diff options structure */ +/** The current version of the diff options structure */ #define GIT_ODB_BACKEND_LOOSE_OPTIONS_VERSION 1 -/* Stack initializer for odb loose backend options. Alternatively use +/** + * Stack initializer for odb loose backend options. Alternatively use * `git_odb_backend_loose_options_init` programmatic initialization. */ #define GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT \ { GIT_ODB_BACKEND_LOOSE_OPTIONS_VERSION, 0, -1 } +/* + * Constructors for in-box ODB backends. + */ + +#ifdef GIT_EXPERIMENTAL_SHA256 + +/** + * Create a backend for a directory containing packfiles. + * + * @param[out] out location to store the odb backend pointer + * @param objects_dir the Git repository's objects directory + * @param opts the options to use when creating the pack backend + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_backend_pack( + git_odb_backend **out, + const char *objects_dir, + const git_odb_backend_pack_options *opts); + +/** + * Create a backend for a single packfile. + * + * @param[out] out location to store the odb backend pointer + * @param index_file path to the packfile's .idx file + * @param opts the options to use when creating the pack backend + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_backend_one_pack( + git_odb_backend **out, + const char *index_file, + const git_odb_backend_pack_options *opts); + /** * Create a backend for loose objects * - * @param out location to store the odb backend pointer + * @param[out] out location to store the odb backend pointer * @param objects_dir the Git repository's objects directory * @param opts options for the loose object backend or NULL * * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 GIT_EXTERN(int) git_odb_backend_loose( git_odb_backend **out, const char *objects_dir, git_odb_backend_loose_options *opts); + #else + +/** + * Create a backend for a directory containing packfiles. + * + * @param[out] out location to store the odb backend pointer + * @param objects_dir the Git repository's objects directory + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_backend_pack( + git_odb_backend **out, + const char *objects_dir); + +/** + * Create a backend out of a single packfile + * + * This can be useful for inspecting the contents of a single + * packfile. + * + * @param[out] out location to store the odb backend pointer + * @param index_file path to the packfile's .idx file + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_backend_one_pack( + git_odb_backend **out, + const char *index_file); + +/** + * Create a backend for loose objects + * + * @param[out] out location to store the odb backend pointer + * @param objects_dir the Git repository's objects directory + * @param compression_level zlib compression level (0-9), or -1 for the default + * @param do_fsync if non-zero, perform an fsync on write + * @param dir_mode permission to use when creating directories, or 0 for default + * @param file_mode permission to use when creating directories, or 0 for default + * @return 0 or an error code + */ GIT_EXTERN(int) git_odb_backend_loose( git_odb_backend **out, const char *objects_dir, @@ -149,6 +175,7 @@ GIT_EXTERN(int) git_odb_backend_loose( int do_fsync, unsigned int dir_mode, unsigned int file_mode); + #endif /** Streaming mode */ @@ -218,6 +245,7 @@ struct git_odb_writepack { void GIT_CALLBACK(free)(git_odb_writepack *writepack); }; +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/oid.h b/include/git2/oid.h index 35b43ef183a..0af9737a04d 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -13,7 +13,7 @@ /** * @file git2/oid.h - * @brief Git object id routines + * @brief Object IDs * @defgroup git_oid Git object id routines * @ingroup Git * @{ @@ -82,13 +82,18 @@ typedef enum { #endif -/* Maximum possible object ID size in raw / hex string format. */ -#ifndef GIT_EXPERIMENTAL_SHA256 -# define GIT_OID_MAX_SIZE GIT_OID_SHA1_SIZE -# define GIT_OID_MAX_HEXSIZE GIT_OID_SHA1_HEXSIZE -#else +/** Maximum possible object ID size in raw format */ +#ifdef GIT_EXPERIMENTAL_SHA256 # define GIT_OID_MAX_SIZE GIT_OID_SHA256_SIZE +#else +# define GIT_OID_MAX_SIZE GIT_OID_SHA1_SIZE +#endif + +/** Maximum possible object ID size in hex format */ +#ifdef GIT_EXPERIMENTAL_SHA256 # define GIT_OID_MAX_HEXSIZE GIT_OID_SHA256_HEXSIZE +#else +# define GIT_OID_MAX_HEXSIZE GIT_OID_SHA1_HEXSIZE #endif /** Minimum length (in number of hex characters, @@ -107,6 +112,15 @@ typedef struct git_oid { unsigned char id[GIT_OID_MAX_SIZE]; } git_oid; +#ifdef GIT_EXPERIMENTAL_SHA256 + +GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str, git_oid_t type); +GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str, git_oid_t type); +GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length, git_oid_t type); +GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw, git_oid_t type); + +#else + /** * Parse a hex formatted object id into a git_oid. * @@ -119,28 +133,18 @@ typedef struct git_oid { * the hex sequence and have at least the number of bytes * needed for an oid encoded in hex (40 bytes for sha1, * 256 bytes for sha256). - * @param type the type of object id * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str, git_oid_t type); -#else GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str); -#endif /** * Parse a hex formatted NUL-terminated string into a git_oid. * * @param out oid structure the result is written into. * @param str input hex string; must be null-terminated. - * @param type the type of object id * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str, git_oid_t type); -#else GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str); -#endif /** * Parse N characters of a hex formatted object id into a git_oid. @@ -151,14 +155,9 @@ GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str); * @param out oid structure the result is written into. * @param str input hex string of at least size `length` * @param length length of the input string - * @param type the type of object id * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length, git_oid_t type); -#else GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length); -#endif /** * Copy an already raw oid into a git_oid structure. @@ -167,10 +166,8 @@ GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length); * @param raw the raw input bytes to be copied. * @return 0 on success or error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw, git_oid_t type); -#else GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw); + #endif /** @@ -310,6 +307,7 @@ GIT_EXTERN(int) git_oid_strcmp(const git_oid *id, const char *str); /** * Check is an oid is all zeros. * + * @param id the object ID to check * @return 1 if all zeros, 0 otherwise. */ GIT_EXTERN(int) git_oid_is_zero(const git_oid *id); @@ -370,4 +368,5 @@ GIT_EXTERN(void) git_oid_shorten_free(git_oid_shorten *os); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/oidarray.h b/include/git2/oidarray.h index 94fc58daba4..e79a55953df 100644 --- a/include/git2/oidarray.h +++ b/include/git2/oidarray.h @@ -10,6 +10,13 @@ #include "common.h" #include "oid.h" +/** + * @file git2/oidarray.h + * @brief An array of object IDs + * @defgroup git_oidarray Arrays of object IDs + * @ingroup Git + * @{ + */ GIT_BEGIN_DECL /** Array of object ids */ @@ -34,4 +41,3 @@ GIT_EXTERN(void) git_oidarray_dispose(git_oidarray *array); GIT_END_DECL #endif - diff --git a/include/git2/pack.h b/include/git2/pack.h index bee72a6c085..3837e04468d 100644 --- a/include/git2/pack.h +++ b/include/git2/pack.h @@ -233,7 +233,15 @@ GIT_EXTERN(size_t) git_packbuilder_object_count(git_packbuilder *pb); */ GIT_EXTERN(size_t) git_packbuilder_written(git_packbuilder *pb); -/** Packbuilder progress notification function */ +/** + * Packbuilder progress notification function. + * + * @param stage the stage of the packbuilder + * @param current the current object + * @param total the total number of objects + * @param payload the callback payload + * @return 0 on success or an error code + */ typedef int GIT_CALLBACK(git_packbuilder_progress)( int stage, uint32_t current, @@ -267,4 +275,5 @@ GIT_EXTERN(void) git_packbuilder_free(git_packbuilder *pb); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/patch.h b/include/git2/patch.h index 9cf758a3edb..782482158be 100644 --- a/include/git2/patch.h +++ b/include/git2/patch.h @@ -14,7 +14,7 @@ /** * @file git2/patch.h - * @brief Patch handling routines. + * @brief Patches store the textual diffs in a delta * @ingroup Git * @{ */ @@ -283,8 +283,7 @@ GIT_EXTERN(int) git_patch_to_buf( git_buf *out, git_patch *patch); -GIT_END_DECL - /**@}*/ +GIT_END_DECL #endif diff --git a/include/git2/pathspec.h b/include/git2/pathspec.h index acbd5cd1d6f..6f6918cdb9d 100644 --- a/include/git2/pathspec.h +++ b/include/git2/pathspec.h @@ -12,6 +12,13 @@ #include "strarray.h" #include "diff.h" +/** + * @file git2/pathspec.h + * @brief Specifiers for path matching + * @defgroup git_pathspec Specifiers for path matching + * @ingroup Git + * @{ + */ GIT_BEGIN_DECL /** @@ -276,5 +283,7 @@ GIT_EXTERN(size_t) git_pathspec_match_list_failed_entrycount( GIT_EXTERN(const char *) git_pathspec_match_list_failed_entry( const git_pathspec_match_list *m, size_t pos); +/** @} */ GIT_END_DECL + #endif diff --git a/include/git2/proxy.h b/include/git2/proxy.h index cfc0c645f8b..195ab75e099 100644 --- a/include/git2/proxy.h +++ b/include/git2/proxy.h @@ -12,6 +12,12 @@ #include "cert.h" #include "credential.h" +/** + * @file git2/proxy.h + * @brief TLS proxies + * @ingroup Git + * @{ + */ GIT_BEGIN_DECL /** @@ -78,7 +84,10 @@ typedef struct { void *payload; } git_proxy_options; +/** Current version for the `git_proxy_options` structure */ #define GIT_PROXY_OPTIONS_VERSION 1 + +/** Static constructor for `git_proxy_options` */ #define GIT_PROXY_OPTIONS_INIT {GIT_PROXY_OPTIONS_VERSION} /** @@ -93,6 +102,7 @@ typedef struct { */ GIT_EXTERN(int) git_proxy_options_init(git_proxy_options *opts, unsigned int version); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/rebase.h b/include/git2/rebase.h index a53e68d9cf9..3fb3e5733a2 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -17,8 +17,8 @@ /** * @file git2/rebase.h - * @brief Git rebase routines - * @defgroup git_rebase Git merge routines + * @brief Rebase manipulates commits, placing them on a new parent + * @defgroup git_rebase Rebase manipulates commits, placing them on a new parent * @ingroup Git * @{ */ @@ -154,7 +154,10 @@ typedef enum { GIT_REBASE_OPERATION_EXEC } git_rebase_operation_t; +/** Current version for the `git_rebase_options` structure */ #define GIT_REBASE_OPTIONS_VERSION 1 + +/** Static constructor for `git_rebase_options` */ #define GIT_REBASE_OPTIONS_INIT \ { GIT_REBASE_OPTIONS_VERSION, 0, 0, NULL, GIT_MERGE_OPTIONS_INIT, \ GIT_CHECKOUT_OPTIONS_INIT, NULL, NULL } @@ -395,4 +398,5 @@ GIT_EXTERN(void) git_rebase_free(git_rebase *rebase); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/refdb.h b/include/git2/refdb.h index c4849abdc4e..536ef10da29 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -14,8 +14,8 @@ /** * @file git2/refdb.h - * @brief Git custom refs backend functions - * @defgroup git_refdb Git custom refs backend API + * @brief A database for references (branches and tags) + * @defgroup git_refdb A database for references (branches and tags) * @ingroup Git * @{ */ diff --git a/include/git2/reflog.h b/include/git2/reflog.h index ec365c1fab2..a0956c63a6a 100644 --- a/include/git2/reflog.h +++ b/include/git2/reflog.h @@ -13,8 +13,8 @@ /** * @file git2/reflog.h - * @brief Git reflog management routines - * @defgroup git_reflog Git reflog management routines + * @brief Reference logs store how references change + * @defgroup git_reflog Reference logs store how references change * @ingroup Git * @{ */ @@ -167,4 +167,5 @@ GIT_EXTERN(void) git_reflog_free(git_reflog *reflog); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/refs.h b/include/git2/refs.h index 06f8bb97c48..d820f2a1867 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -14,8 +14,8 @@ /** * @file git2/refs.h - * @brief Git reference management routines - * @defgroup git_reference Git reference management routines + * @brief References point to a commit; generally these are branches and tags + * @defgroup git_reference References point to a commit; generally these are branches and tags * @ingroup Git * @{ */ @@ -29,7 +29,7 @@ GIT_BEGIN_DECL * The name will be checked for validity. * See `git_reference_symbolic_create()` for rules about valid names. * - * @param out pointer to the looked-up reference + * @param[out] out pointer to the looked-up reference * @param repo the repository to look up the reference * @param name the long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...) * @return 0 on success, GIT_ENOTFOUND, GIT_EINVALIDSPEC or an error code. @@ -371,6 +371,7 @@ GIT_EXTERN(int) git_reference_set_target( * reflog is enabled for the repository. We only rename * the reflog if it exists. * + * @param[out] new_ref The new reference * @param ref The reference to rename * @param new_name The new name for the reference * @param force Overwrite an existing reference @@ -406,6 +407,7 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref); * This method removes the named reference from the repository without * looking at its old value. * + * @param repo The repository to remove the reference from * @param name The reference to remove * @return 0 or an error code */ @@ -518,7 +520,7 @@ GIT_EXTERN(int) git_reference_cmp( /** * Create an iterator for the repo's references * - * @param out pointer in which to store the iterator + * @param[out] out pointer in which to store the iterator * @param repo the repository * @return 0 or an error code */ @@ -543,7 +545,7 @@ GIT_EXTERN(int) git_reference_iterator_glob_new( /** * Get the next reference * - * @param out pointer in which to store the reference + * @param[out] out pointer in which to store the reference * @param iter the iterator * @return 0, GIT_ITEROVER if there are no more; or an error code */ @@ -724,7 +726,7 @@ GIT_EXTERN(int) git_reference_normalize_name( * If you pass `GIT_OBJECT_ANY` as the target type, then the object * will be peeled until a non-tag object is met. * - * @param out Pointer to the peeled git_object + * @param[out] out Pointer to the peeled git_object * @param ref The reference to be processed * @param type The type of the requested object (GIT_OBJECT_COMMIT, * GIT_OBJECT_TAG, GIT_OBJECT_TREE, GIT_OBJECT_BLOB or GIT_OBJECT_ANY). @@ -768,4 +770,5 @@ GIT_EXTERN(const char *) git_reference_shorthand(const git_reference *ref); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/refspec.h b/include/git2/refspec.h index e7087132b04..16ebd1ddfa8 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -14,8 +14,8 @@ /** * @file git2/refspec.h - * @brief Git refspec attributes - * @defgroup git_refspec Git refspec attributes + * @brief Refspecs map local references to remote references + * @defgroup git_refspec Refspecs map local references to remote references * @ingroup Git * @{ */ @@ -79,7 +79,7 @@ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); GIT_EXTERN(git_direction) git_refspec_direction(const git_refspec *spec); /** - * Check if a refspec's source descriptor matches a reference + * Check if a refspec's source descriptor matches a reference * * @param refspec the refspec * @param refname the name of the reference to check @@ -116,6 +116,7 @@ GIT_EXTERN(int) git_refspec_transform(git_buf *out, const git_refspec *spec, con */ GIT_EXTERN(int) git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/remote.h b/include/git2/remote.h index 662fc935243..ecb7b537eb7 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -19,8 +19,8 @@ /** * @file git2/remote.h - * @brief Git remote management functions - * @defgroup git_remote remote management functions + * @brief Remotes are where local repositories fetch from and push to + * @defgroup git_remote Remotes are where local repositories fetch from and push to * @ingroup Git * @{ */ @@ -116,7 +116,10 @@ typedef struct git_remote_create_options { unsigned int flags; } git_remote_create_options; +/** Current version for the `git_remote_create_options` structure */ #define GIT_REMOTE_CREATE_OPTIONS_VERSION 1 + +/** Static constructor for `git_remote_create_options` */ #define GIT_REMOTE_CREATE_OPTIONS_INIT {GIT_REMOTE_CREATE_OPTIONS_VERSION} /** @@ -466,7 +469,15 @@ typedef enum git_remote_completion_t { GIT_REMOTE_COMPLETION_ERROR } git_remote_completion_t; -/** Push network progress notification function */ +/** + * Push network progress notification callback. + * + * @param current The number of objects pushed so far + * @param total The total number of objects to push + * @param bytes The number of bytes pushed + * @param payload The user-specified payload callback + * @return 0 or an error code to stop the transfer + */ typedef int GIT_CALLBACK(git_push_transfer_progress_cb)( unsigned int current, unsigned int total, @@ -502,8 +513,12 @@ typedef struct { * as commands to the destination. * @param len number of elements in `updates` * @param payload Payload provided by the caller + * @return 0 or an error code to stop the push */ -typedef int GIT_CALLBACK(git_push_negotiation)(const git_push_update **updates, size_t len, void *payload); +typedef int GIT_CALLBACK(git_push_negotiation)( + const git_push_update **updates, + size_t len, + void *payload); /** * Callback used to inform of the update status from the remote. @@ -682,7 +697,10 @@ struct git_remote_callbacks { void *data); }; +/** Current version for the `git_remote_callbacks_options` structure */ #define GIT_REMOTE_CALLBACKS_VERSION 1 + +/** Static constructor for `git_remote_callbacks_options` */ #define GIT_REMOTE_CALLBACKS_INIT {GIT_REMOTE_CALLBACKS_VERSION} /** @@ -809,7 +827,10 @@ typedef struct { git_strarray custom_headers; } git_fetch_options; +/** Current version for the `git_fetch_options` structure */ #define GIT_FETCH_OPTIONS_VERSION 1 + +/** Static constructor for `git_fetch_options` */ #define GIT_FETCH_OPTIONS_INIT { \ GIT_FETCH_OPTIONS_VERSION, \ GIT_REMOTE_CALLBACKS_INIT, \ @@ -877,7 +898,10 @@ typedef struct { git_strarray remote_push_options; } git_push_options; +/** Current version for the `git_push_options` structure */ #define GIT_PUSH_OPTIONS_VERSION 1 + +/** Static constructor for `git_push_options` */ #define GIT_PUSH_OPTIONS_INIT { GIT_PUSH_OPTIONS_VERSION, 1, GIT_REMOTE_CALLBACKS_INIT, GIT_PROXY_OPTIONS_INIT } /** @@ -921,7 +945,10 @@ typedef struct { git_strarray custom_headers; } git_remote_connect_options; +/** Current version for the `git_remote_connect_options` structure */ #define GIT_REMOTE_CONNECT_OPTIONS_VERSION 1 + +/** Static constructor for `git_remote_connect_options` */ #define GIT_REMOTE_CONNECT_OPTIONS_INIT { \ GIT_REMOTE_CONNECT_OPTIONS_VERSION, \ GIT_REMOTE_CALLBACKS_INIT, \ @@ -1041,14 +1068,14 @@ GIT_EXTERN(int) git_remote_upload( * `git_remote_connect` will be used (if it was called). * * @param remote the remote to update - * @param reflog_message The message to insert into the reflogs. If - * NULL and fetching, the default is "fetch ", where is - * the name of the remote (or its url, for in-memory remotes). This - * parameter is ignored when pushing. * @param callbacks pointer to the callback structure to use or NULL * @param update_flags the git_remote_update_flags for these tips. * @param download_tags what the behaviour for downloading tags is for this fetch. This is * ignored for push. This must be the same value passed to `git_remote_download()`. + * @param reflog_message The message to insert into the reflogs. If + * NULL and fetching, the default is "fetch ", where is + * the name of the remote (or its url, for in-memory remotes). This + * parameter is ignored when pushing. * @return 0 or an error code */ GIT_EXTERN(int) git_remote_update_tips( @@ -1116,6 +1143,9 @@ GIT_EXTERN(int) git_remote_push( /** * Get the statistics structure that is filled in by the fetch operation. + * + * @param remote the remote to get statistics for + * @return the git_indexer_progress for the remote */ GIT_EXTERN(const git_indexer_progress *) git_remote_stats(git_remote *remote); @@ -1215,4 +1245,5 @@ GIT_EXTERN(int) git_remote_default_branch(git_buf *out, git_remote *remote); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/repository.h b/include/git2/repository.h index 0afda72d402..a10ea3fcb3e 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -15,8 +15,8 @@ /** * @file git2/repository.h - * @brief Git repository management routines - * @defgroup git_repository Git repository management routines + * @brief The repository stores revisions for a source tree + * @defgroup git_repository The repository stores revisions for a source tree * @ingroup Git * @{ */ @@ -31,7 +31,7 @@ GIT_BEGIN_DECL * The method will automatically detect if 'path' is a normal * or bare repository or fail is 'path' is neither. * - * @param out pointer to the repo which will be opened + * @param[out] out pointer to the repo which will be opened * @param path the path to the repository * @return 0 or an error code */ @@ -48,6 +48,15 @@ GIT_EXTERN(int) git_repository_open(git_repository **out, const char *path); */ GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_worktree *wt); +#ifdef GIT_EXPERIMENTAL_SHA256 + +GIT_EXTERN(int) git_repository_wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type); + +#else + /** * Create a "fake" repository to wrap an object database * @@ -57,18 +66,12 @@ GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_work * * @param out pointer to the repo * @param odb the object database to wrap - * @param oid_type the oid type of the object database * @return 0 or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_repository_wrap_odb( - git_repository **out, - git_odb *odb, - git_oid_t oid_type); -#else GIT_EXTERN(int) git_repository_wrap_odb( git_repository **out, git_odb *odb); + #endif /** @@ -158,7 +161,7 @@ typedef enum { /** * Find and open a repository with extended controls. * - * @param out Pointer to the repo which will be opened. This can + * @param[out] out Pointer to the repo which will be opened. This can * actually be NULL if you only want to use the error code to * see if a repo at this path could be opened. * @param path Path to open as git repository. If the flags @@ -186,7 +189,7 @@ GIT_EXTERN(int) git_repository_open_ext( * if you're e.g. hosting git repositories and need to access them * efficiently * - * @param out Pointer to the repo which will be opened. + * @param[out] out Pointer to the repo which will be opened. * @param bare_path Direct path to the bare repository * @return 0 on success, or an error code */ @@ -211,7 +214,7 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo); * TODO: * - Reinit the repository * - * @param out pointer to the repo which will be created or reinitialized + * @param[out] out pointer to the repo which will be created or reinitialized * @param path the path to the repository * @param is_bare if true, a Git repository without a working directory is * created at the pointed path. If false, provided path will be @@ -373,7 +376,10 @@ typedef struct { #endif } git_repository_init_options; +/** Current version for the `git_repository_init_options` structure */ #define GIT_REPOSITORY_INIT_OPTIONS_VERSION 1 + +/** Static constructor for `git_repository_init_options` */ #define GIT_REPOSITORY_INIT_OPTIONS_INIT {GIT_REPOSITORY_INIT_OPTIONS_VERSION} /** @@ -415,7 +421,7 @@ GIT_EXTERN(int) git_repository_init_ext( * `git_reference_free()` must be called when done with it to release the * allocated memory and prevent a leak. * - * @param out pointer to the reference which will be retrieved + * @param[out] out pointer to the reference which will be retrieved * @param repo a repository object * * @return 0 on success, GIT_EUNBORNBRANCH when HEAD points to a non existing @@ -636,7 +642,7 @@ GIT_EXTERN(int) git_repository_config_snapshot(git_config **out, git_repository * The ODB must be freed once it's no longer being used by * the user. * - * @param out Pointer to store the loaded ODB + * @param[out] out Pointer to store the loaded ODB * @param repo A repository object * @return 0, or an error code */ @@ -652,7 +658,7 @@ GIT_EXTERN(int) git_repository_odb(git_odb **out, git_repository *repo); * The refdb must be freed once it's no longer being used by * the user. * - * @param out Pointer to store the loaded refdb + * @param[out] out Pointer to store the loaded refdb * @param repo A repository object * @return 0, or an error code */ @@ -668,7 +674,7 @@ GIT_EXTERN(int) git_repository_refdb(git_refdb **out, git_repository *repo); * The index must be freed once it's no longer being used by * the user. * - * @param out Pointer to store the loaded index + * @param[out] out Pointer to store the loaded index * @param repo A repository object * @return 0, or an error code */ @@ -858,7 +864,9 @@ GIT_EXTERN(int) git_repository_set_head_detached( * * See the documentation for `git_repository_set_head_detached()`. * - * @see git_repository_set_head_detached + * @param repo Repository pointer + * @param committish annotated commit to point HEAD to + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_set_head_detached_from_annotated( git_repository *repo, @@ -951,8 +959,8 @@ GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); * The memory is owned by the repository and must not be freed by the * user. * - * @param name where to store the pointer to the name - * @param email where to store the pointer to the email + * @param[out] name where to store the pointer to the name + * @param[out] email where to store the pointer to the email * @param repo the repository * @return 0 or an error code */ @@ -993,4 +1001,5 @@ GIT_EXTERN(int) git_repository_commit_parents(git_commitarray *commits, git_repo /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/reset.h b/include/git2/reset.h index b2ee2ba7bfb..0123f7c7600 100644 --- a/include/git2/reset.h +++ b/include/git2/reset.h @@ -14,7 +14,7 @@ /** * @file git2/reset.h - * @brief Git reset management routines + * @brief Reset will update the local repository to a prior state * @ingroup Git * @{ */ @@ -75,11 +75,23 @@ GIT_EXTERN(int) git_reset( * * See the documentation for `git_reset()`. * - * @see git_reset + * @param repo Repository where to perform the reset operation. + * + * @param target Annotated commit to which the Head should be moved to. + * This object must belong to the given `repo`, it will be dereferenced + * to a git_commit which oid will be used as the target of the branch. + * + * @param reset_type Kind of reset operation to perform. + * + * @param checkout_opts Optional checkout options to be used for a HARD reset. + * The checkout_strategy field will be overridden (based on reset_type). + * This parameter can be used to propagate notify and progress callbacks. + * + * @return 0 on success or an error code */ GIT_EXTERN(int) git_reset_from_annotated( git_repository *repo, - const git_annotated_commit *commit, + const git_annotated_commit *target, git_reset_t reset_type, const git_checkout_options *checkout_opts); @@ -108,4 +120,5 @@ GIT_EXTERN(int) git_reset_default( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/revert.h b/include/git2/revert.h index 331e90dffcf..ec51eca2dd8 100644 --- a/include/git2/revert.h +++ b/include/git2/revert.h @@ -13,8 +13,8 @@ /** * @file git2/revert.h - * @brief Git revert routines - * @defgroup git_revert Git revert routines + * @brief Cherry-pick the inverse of a change to "undo" its effects + * @defgroup git_revert Cherry-pick the inverse of a change to "undo" its effects * @ingroup Git * @{ */ @@ -33,8 +33,13 @@ typedef struct { git_checkout_options checkout_opts; /**< Options for the checkout */ } git_revert_options; +/** Current version for the `git_revert_options` structure */ #define GIT_REVERT_OPTIONS_VERSION 1 -#define GIT_REVERT_OPTIONS_INIT {GIT_REVERT_OPTIONS_VERSION, 0, GIT_MERGE_OPTIONS_INIT, GIT_CHECKOUT_OPTIONS_INIT} + +/** Static constructor for `git_revert_options` */ +#define GIT_REVERT_OPTIONS_INIT { \ + GIT_REVERT_OPTIONS_VERSION, 0, \ + GIT_MERGE_OPTIONS_INIT, GIT_CHECKOUT_OPTIONS_INIT } /** * Initialize git_revert_options structure @@ -87,5 +92,5 @@ GIT_EXTERN(int) git_revert( /** @} */ GIT_END_DECL -#endif +#endif diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 51ea2dc13f5..c14fe3dc874 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -12,8 +12,8 @@ /** * @file git2/revparse.h - * @brief Git revision parsing routines - * @defgroup git_revparse Git revision parsing routines + * @brief Parse the textual revision information + * @defgroup git_revparse Parse the textual revision information * @ingroup Git * @{ */ @@ -107,7 +107,7 @@ GIT_EXTERN(int) git_revparse( git_repository *repo, const char *spec); - /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index 4aa9f5b1e0e..7c4ac5465d9 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -13,8 +13,8 @@ /** * @file git2/revwalk.h - * @brief Git revision traversal routines - * @defgroup git_revwalk Git revision traversal routines + * @brief Traverse (walk) the commit graph (revision history) + * @defgroup git_revwalk Traverse (walk) the commit graph (revision history) * @ingroup Git * @{ */ @@ -299,4 +299,5 @@ GIT_EXTERN(int) git_revwalk_add_hide_cb( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/signature.h b/include/git2/signature.h index a027d25dcdc..20ec24b340a 100644 --- a/include/git2/signature.h +++ b/include/git2/signature.h @@ -12,9 +12,13 @@ /** * @file git2/signature.h - * @brief Git signature creation + * @brief Signatures are the actor in a repository and when they acted * @defgroup git_signature Git signature creation * @ingroup Git + * + * Signatures contain the information about the actor (committer or + * author) in a repository, and the time that they performed the + * commit, or authoring. * @{ */ GIT_BEGIN_DECL @@ -140,4 +144,5 @@ GIT_EXTERN(void) git_signature_free(git_signature *sig); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/stash.h b/include/git2/stash.h index b43ae6b24b6..ad28c32639a 100644 --- a/include/git2/stash.h +++ b/include/git2/stash.h @@ -13,8 +13,13 @@ /** * @file git2/stash.h - * @brief Git stash management routines + * @brief Stashes stores some uncommitted state in the repository * @ingroup Git + * + * Stashes stores some uncommitted state in the repository; generally + * this allows a user to stash some changes so that they can restore + * the working directory to an unmodified state. This can allow a + * developer to work on two different changes in parallel. * @{ */ GIT_BEGIN_DECL @@ -94,7 +99,10 @@ typedef struct git_stash_save_options { git_strarray paths; } git_stash_save_options; +/** Current version for the `git_stash_save_options` structure */ #define GIT_STASH_SAVE_OPTIONS_VERSION 1 + +/** Static constructor for `git_stash_save_options` */ #define GIT_STASH_SAVE_OPTIONS_INIT { GIT_STASH_SAVE_OPTIONS_VERSION } /** @@ -165,6 +173,10 @@ typedef enum { * Stash application progress notification function. * Return 0 to continue processing, or a negative value to * abort the stash application. + * + * @param progress the progress information + * @param payload the user-specified payload to the apply function + * @return 0 on success, -1 on error */ typedef int GIT_CALLBACK(git_stash_apply_progress_cb)( git_stash_apply_progress_t progress, @@ -191,7 +203,10 @@ typedef struct git_stash_apply_options { void *progress_payload; } git_stash_apply_options; +/** Current version for the `git_stash_apply_options` structure */ #define GIT_STASH_APPLY_OPTIONS_VERSION 1 + +/** Static constructor for `git_stash_apply_options` */ #define GIT_STASH_APPLY_OPTIONS_INIT { \ GIT_STASH_APPLY_OPTIONS_VERSION, \ GIT_STASH_APPLY_DEFAULT, \ @@ -309,4 +324,5 @@ GIT_EXTERN(int) git_stash_pop( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/status.h b/include/git2/status.h index bb28e875b00..e13783b6746 100644 --- a/include/git2/status.h +++ b/include/git2/status.h @@ -14,7 +14,7 @@ /** * @file git2/status.h - * @brief Git file status routines + * @brief Status indicates how a user has changed the working directory and index * @defgroup git_status Git file status routines * @ingroup Git * @{ @@ -54,11 +54,10 @@ typedef enum { /** * Function pointer to receive status on individual files * - * `path` is the relative path to the file from the root of the repository. - * - * `status_flags` is a combination of `git_status_t` values that apply. - * - * `payload` is the value you passed to the foreach function as payload. + * @param path is the path to the file + * @param status_flags the `git_status_t` values for file's status + * @param payload the user-specified payload to the foreach function + * @return 0 on success, or a negative number on failure */ typedef int GIT_CALLBACK(git_status_cb)( const char *path, unsigned int status_flags, void *payload); @@ -207,6 +206,7 @@ typedef enum { GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED = (1u << 15) } git_status_opt_t; +/** Default `git_status_opt_t` values */ #define GIT_STATUS_OPT_DEFAULTS \ (GIT_STATUS_OPT_INCLUDE_IGNORED | \ GIT_STATUS_OPT_INCLUDE_UNTRACKED | \ @@ -261,7 +261,10 @@ typedef struct { uint16_t rename_threshold; } git_status_options; +/** Current version for the `git_status_options` structure */ #define GIT_STATUS_OPTIONS_VERSION 1 + +/** Static constructor for `git_status_options` */ #define GIT_STATUS_OPTIONS_INIT {GIT_STATUS_OPTIONS_VERSION} /** @@ -449,4 +452,5 @@ GIT_EXTERN(int) git_status_should_ignore( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/strarray.h b/include/git2/strarray.h index 03d93f8fbbc..dcb628a1846 100644 --- a/include/git2/strarray.h +++ b/include/git2/strarray.h @@ -11,8 +11,8 @@ /** * @file git2/strarray.h - * @brief Git string array routines - * @defgroup git_strarray Git string array routines + * @brief An array of strings for the user to free + * @defgroup git_strarray An array of strings for the user to free * @ingroup Git * @{ */ @@ -40,4 +40,3 @@ GIT_EXTERN(void) git_strarray_dispose(git_strarray *array); GIT_END_DECL #endif - diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 25d6687a9c9..911b3cee39c 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -15,7 +15,7 @@ /** * @file git2/submodule.h - * @brief Git submodule management utilities + * @brief Submodules place another repository's contents within this one * * Submodule support in libgit2 builds a list of known submodules and keeps * it in the repository. The list is built from the .gitmodules file, the @@ -88,20 +88,27 @@ typedef enum { GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13) } git_submodule_status_t; +/** Submodule source bits */ #define GIT_SUBMODULE_STATUS__IN_FLAGS 0x000Fu +/** Submodule index status */ #define GIT_SUBMODULE_STATUS__INDEX_FLAGS 0x0070u +/** Submodule working directory status */ #define GIT_SUBMODULE_STATUS__WD_FLAGS 0x3F80u +/** Whether the submodule is modified */ #define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ (((S) & ~GIT_SUBMODULE_STATUS__IN_FLAGS) == 0) +/** Whether the submodule is modified (in the index) */ #define GIT_SUBMODULE_STATUS_IS_INDEX_UNMODIFIED(S) \ (((S) & GIT_SUBMODULE_STATUS__INDEX_FLAGS) == 0) +/** Whether the submodule is modified (in the working directory) */ #define GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(S) \ (((S) & (GIT_SUBMODULE_STATUS__WD_FLAGS & \ ~GIT_SUBMODULE_STATUS_WD_UNINITIALIZED)) == 0) +/** Whether the submodule working directory is dirty */ #define GIT_SUBMODULE_STATUS_IS_WD_DIRTY(S) \ (((S) & (GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED | \ GIT_SUBMODULE_STATUS_WD_WD_MODIFIED | \ @@ -150,7 +157,10 @@ typedef struct git_submodule_update_options { int allow_fetch; } git_submodule_update_options; +/** Current version for the `git_submodule_update_options` structure */ #define GIT_SUBMODULE_UPDATE_OPTIONS_VERSION 1 + +/** Static constructor for `git_submodule_update_options` */ #define GIT_SUBMODULE_UPDATE_OPTIONS_INIT \ { GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \ GIT_CHECKOUT_OPTIONS_INIT, \ @@ -530,7 +540,8 @@ GIT_EXTERN(int) git_submodule_set_update( * Note that at this time, libgit2 does not honor this setting and the * fetch functionality current ignores submodules. * - * @return 0 if fetchRecurseSubmodules is false, 1 if true + * @param submodule the submodule to examine + * @return the submodule recursion configuration */ GIT_EXTERN(git_submodule_recurse_t) git_submodule_fetch_recurse_submodules( git_submodule *submodule); @@ -542,7 +553,7 @@ GIT_EXTERN(git_submodule_recurse_t) git_submodule_fetch_recurse_submodules( * * @param repo the repository to affect * @param name the submodule to configure - * @param fetch_recurse_submodules Boolean value + * @param fetch_recurse_submodules the submodule recursion configuration * @return old value for fetchRecurseSubmodules */ GIT_EXTERN(int) git_submodule_set_fetch_recurse_submodules( @@ -664,4 +675,5 @@ GIT_EXTERN(int) git_submodule_location( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/alloc.h b/include/git2/sys/alloc.h index e7f85b890c8..67506f2b17e 100644 --- a/include/git2/sys/alloc.h +++ b/include/git2/sys/alloc.h @@ -10,6 +10,17 @@ #include "git2/common.h" +/** + * @file git2/sys/alloc.h + * @brief Custom memory allocators + * @defgroup git_merge Git merge routines + * @ingroup Git + * + * Users can configure custom allocators; this is particularly + * interesting when running in constrained environments, when calling + * from another language, or during testing. + * @{ + */ GIT_BEGIN_DECL /** @@ -62,6 +73,7 @@ int git_stdalloc_init_allocator(git_allocator *allocator); */ int git_win32_crtdbg_init_allocator(git_allocator *allocator); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/commit.h b/include/git2/sys/commit.h index ba671061f76..a8253c06743 100644 --- a/include/git2/sys/commit.h +++ b/include/git2/sys/commit.h @@ -14,7 +14,7 @@ /** * @file git2/sys/commit.h * @brief Low-level Git commit creation - * @defgroup git_backend Git custom backend APIs + * @defgroup git_commit Low-level Git commit creation * @ingroup Git * @{ */ @@ -29,7 +29,43 @@ GIT_BEGIN_DECL * the `tree`, neither the `parents` list of `git_oid`s are checked for * validity. * - * @see git_commit_create + * @param id Pointer in which to store the OID of the newly created commit + * + * @param repo Repository where to store the commit + * + * @param update_ref If not NULL, name of the reference that + * will be updated to point to this commit. If the reference + * is not direct, it will be resolved to a direct reference. + * Use "HEAD" to update the HEAD of the current branch and + * make it point to this commit. If the reference doesn't + * exist yet, it will be created. If it does exist, the first + * parent must be the tip of this branch. + * + * @param author Signature with author and author time of commit + * + * @param committer Signature with committer and * commit time of commit + * + * @param message_encoding The encoding for the message in the + * commit, represented with a standard encoding name. + * E.g. "UTF-8". If NULL, no encoding header is written and + * UTF-8 is assumed. + * + * @param message Full message for this commit + * + * @param tree An instance of a `git_tree` object that will + * be used as the tree for the commit. This tree object must + * also be owned by the given `repo`. + * + * @param parent_count Number of parents for this commit + * + * @param parents Array of `parent_count` pointers to `git_commit` + * objects that will be used as the parents for this commit. This + * array may be NULL if `parent_count` is 0 (root commit). All the + * given commits must be owned by the `repo`. + * + * @return 0 or an error code + * The created commit will be written to the Object Database and + * the given reference will be updated to point to it */ GIT_EXTERN(int) git_commit_create_from_ids( git_oid *id, @@ -49,6 +85,10 @@ GIT_EXTERN(int) git_commit_create_from_ids( * This is invoked with the count of the number of parents processed so far * along with the user supplied payload. This should return a git_oid of * the next parent or NULL if all parents have been provided. + * + * @param idx the index of the parent + * @param payload the user-specified payload + * @return the object id of the parent, or NULL if there are no further parents */ typedef const git_oid * GIT_CALLBACK(git_commit_parent_callback)(size_t idx, void *payload); @@ -61,7 +101,40 @@ typedef const git_oid * GIT_CALLBACK(git_commit_parent_callback)(size_t idx, voi * with `parent_payload` and should return `git_oid` values or NULL to * indicate that all parents are accounted for. * - * @see git_commit_create + * @param id Pointer in which to store the OID of the newly created commit + * + * @param repo Repository where to store the commit + * + * @param update_ref If not NULL, name of the reference that + * will be updated to point to this commit. If the reference + * is not direct, it will be resolved to a direct reference. + * Use "HEAD" to update the HEAD of the current branch and + * make it point to this commit. If the reference doesn't + * exist yet, it will be created. If it does exist, the first + * parent must be the tip of this branch. + * + * @param author Signature with author and author time of commit + * + * @param committer Signature with committer and * commit time of commit + * + * @param message_encoding The encoding for the message in the + * commit, represented with a standard encoding name. + * E.g. "UTF-8". If NULL, no encoding header is written and + * UTF-8 is assumed. + * + * @param message Full message for this commit + * + * @param tree An instance of a `git_tree` object that will + * be used as the tree for the commit. This tree object must + * also be owned by the given `repo`. + * + * @param parent_cb Callback to invoke to obtain parent information + * + * @param parent_payload User-specified payload to provide to the callback + * + * @return 0 or an error code + * The created commit will be written to the Object Database and + * the given reference will be updated to point to it */ GIT_EXTERN(int) git_commit_create_from_callback( git_oid *id, @@ -77,4 +150,5 @@ GIT_EXTERN(int) git_commit_create_from_callback( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/commit_graph.h b/include/git2/sys/commit_graph.h index 06e045fcd2b..838efee55bf 100644 --- a/include/git2/sys/commit_graph.h +++ b/include/git2/sys/commit_graph.h @@ -12,8 +12,8 @@ /** * @file git2/sys/commit_graph.h - * @brief Git commit-graph - * @defgroup git_commit_graph Git commit-graph APIs + * @brief Commit graphs store information about commit relationships + * @defgroup git_commit_graph Commit graphs * @ingroup Git * @{ */ @@ -136,7 +136,10 @@ typedef struct { size_t max_commits; } git_commit_graph_writer_options; +/** Current version for the `git_commit_graph_writer_options` structure */ #define GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION 1 + +/** Static constructor for `git_commit_graph_writer_options` */ #define GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT { \ GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION \ } @@ -181,4 +184,5 @@ GIT_EXTERN(int) git_commit_graph_writer_dump( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index a45d5f80709..cc4a3991ddc 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -13,14 +13,19 @@ /** * @file git2/sys/config.h - * @brief Git config backend routines - * @defgroup git_backend Git custom backend APIs + * @brief Custom configuration database backends + * @defgroup git_backend Custom configuration database backends * @ingroup Git * @{ */ GIT_BEGIN_DECL +/** + * An entry in a configuration backend. This is provided so that + * backend implementors can have a mechanism to free their data. + */ typedef struct git_config_backend_entry { + /** The base configuration entry */ struct git_config_entry entry; /** @@ -93,7 +98,11 @@ struct git_config_backend { int GIT_CALLBACK(unlock)(struct git_config_backend *, int success); void GIT_CALLBACK(free)(struct git_config_backend *); }; + +/** Current version for the `git_config_backend_options` structure */ #define GIT_CONFIG_BACKEND_VERSION 1 + +/** Static constructor for `git_config_backend_options` */ #define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} /** @@ -152,7 +161,10 @@ typedef struct { const char *origin_path; } git_config_backend_memory_options; +/** Current version for the `git_config_backend_memory_options` structure */ #define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION 1 + +/** Static constructor for `git_config_backend_memory_options` */ #define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT { GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION } @@ -164,6 +176,7 @@ typedef struct { * @param cfg the configuration that is to be parsed * @param len the length of the string pointed to by `cfg` * @param opts the options to initialize this backend with, or NULL + * @return 0 on success or an error code */ extern int git_config_backend_from_string( git_config_backend **out, @@ -179,6 +192,7 @@ extern int git_config_backend_from_string( * @param values the configuration values to set (in "key=value" format) * @param len the length of the values array * @param opts the options to initialize this backend with, or NULL + * @return 0 on success or an error code */ extern int git_config_backend_from_values( git_config_backend **out, @@ -188,4 +202,5 @@ extern int git_config_backend_from_values( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/credential.h b/include/git2/sys/credential.h index bb4c9f94253..0d573a3231f 100644 --- a/include/git2/sys/credential.h +++ b/include/git2/sys/credential.h @@ -11,9 +11,9 @@ #include "git2/credential.h" /** - * @file git2/sys/cred.h - * @brief Git credentials low-level implementation - * @defgroup git_credential Git credentials low-level implementation + * @file git2/sys/credential.h + * @brief Low-level credentials implementation + * @defgroup git_credential Low-level credentials implementation * @ingroup Git * @{ */ @@ -85,6 +85,7 @@ struct git_credential_ssh_custom { void *payload; /**< Payload passed to prompt_callback */ }; +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/diff.h b/include/git2/sys/diff.h index aefd7b9973f..a398f5490fb 100644 --- a/include/git2/sys/diff.h +++ b/include/git2/sys/diff.h @@ -15,7 +15,7 @@ /** * @file git2/sys/diff.h - * @brief Low-level Git diff utilities + * @brief Low-level diff utilities * @ingroup Git * @{ */ @@ -33,6 +33,12 @@ GIT_BEGIN_DECL * must pass a `git_buf *` value as the payload to the `git_diff_print` * and/or `git_patch_print` function. The data will be appended to the * buffer (after any existing content). + * + * @param delta the delta being processed + * @param hunk the hunk being processed + * @param line the line being processed + * @param payload the payload provided by the diff generator + * @return 0 on success or an error code */ GIT_EXTERN(int) git_diff_print_callback__to_buf( const git_diff_delta *delta, @@ -53,6 +59,12 @@ GIT_EXTERN(int) git_diff_print_callback__to_buf( * value from `fopen()`) as the payload to the `git_diff_print` * and/or `git_patch_print` function. If you pass NULL, this will write * data to `stdout`. + * + * @param delta the delta being processed + * @param hunk the hunk being processed + * @param line the line being processed + * @param payload the payload provided by the diff generator + * @return 0 on success or an error code */ GIT_EXTERN(int) git_diff_print_callback__to_file_handle( const git_diff_delta *delta, @@ -70,7 +82,10 @@ typedef struct { size_t oid_calculations; /**< Number of ID calculations */ } git_diff_perfdata; +/** Current version for the `git_diff_perfdata_options` structure */ #define GIT_DIFF_PERFDATA_VERSION 1 + +/** Static constructor for `git_diff_perfdata_options` */ #define GIT_DIFF_PERFDATA_INIT {GIT_DIFF_PERFDATA_VERSION,0,0} /** @@ -85,10 +100,15 @@ GIT_EXTERN(int) git_diff_get_perfdata( /** * Get performance data for diffs from a git_status_list + * + * @param out Structure to be filled with diff performance data + * @param status Diff to read performance data from + * @return 0 for success, <0 for error */ GIT_EXTERN(int) git_status_list_get_perfdata( git_diff_perfdata *out, const git_status_list *status); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/email.h b/include/git2/sys/email.h index 5029f9a532c..26e792abf89 100644 --- a/include/git2/sys/email.h +++ b/include/git2/sys/email.h @@ -33,6 +33,7 @@ GIT_BEGIN_DECL * @param body optional text to include above the diffstat * @param author the person who authored this commit * @param opts email creation options + * @return 0 on success or an error code */ GIT_EXTERN(int) git_email_create_from_diff( git_buf *out, @@ -47,4 +48,5 @@ GIT_EXTERN(int) git_email_create_from_diff( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/errors.h b/include/git2/sys/errors.h index 3ae121524d5..44e8ecba84f 100644 --- a/include/git2/sys/errors.h +++ b/include/git2/sys/errors.h @@ -10,6 +10,15 @@ #include "git2/common.h" +/** + * @file git2/sys/errors.h + * @brief Advanced error handling + * @ingroup Git + * + * Error handling for advanced consumers; those who use callbacks + * or those who create custom databases. + * @{ + */ GIT_BEGIN_DECL /** @@ -61,6 +70,7 @@ GIT_EXTERN(int) git_error_set_str(int error_class, const char *string); */ GIT_EXTERN(void) git_error_set_oom(void); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/filter.h b/include/git2/sys/filter.h index b3759416a1d..60466d173fb 100644 --- a/include/git2/sys/filter.h +++ b/include/git2/sys/filter.h @@ -11,8 +11,8 @@ /** * @file git2/sys/filter.h - * @brief Git filter backend and plugin routines - * @defgroup git_backend Git custom backend APIs + * @brief Custom filter backends and plugins + * @defgroup git_backend Custom filter backends and plugins * @ingroup Git * @{ */ @@ -26,7 +26,10 @@ GIT_BEGIN_DECL */ GIT_EXTERN(git_filter *) git_filter_lookup(const char *name); +/** The "crlf" filter */ #define GIT_FILTER_CRLF "crlf" + +/** The "ident" filter */ #define GIT_FILTER_IDENT "ident" /** @@ -53,6 +56,12 @@ GIT_EXTERN(git_filter *) git_filter_lookup(const char *name); * the filter list for you, but you can use this in combination with the * `git_filter_lookup` and `git_filter_list_push` functions to assemble * your own chains of filters. + * + * @param out the filter list + * @param repo the repository to use for configuration + * @param mode the filter mode (direction) + * @param options the options + * @return 0 on success or an error code */ GIT_EXTERN(int) git_filter_list_new( git_filter_list **out, @@ -72,6 +81,11 @@ GIT_EXTERN(int) git_filter_list_new( * filter. Using this function, you can either pass in a payload if you * know the expected payload format, or you can pass NULL. Some filters * may fail with a NULL payload. Good luck! + * + * @param fl the filter list + * @param filter the filter to push + * @param payload the payload for the filter + * @return 0 on success or an error code */ GIT_EXTERN(int) git_filter_list_push( git_filter_list *fl, git_filter *filter, void *payload); @@ -96,17 +110,26 @@ typedef struct git_filter_source git_filter_source; /** * Get the repository that the source data is coming from. + * + * @param src the filter source + * @return the repository for the filter information */ GIT_EXTERN(git_repository *) git_filter_source_repo(const git_filter_source *src); /** * Get the path that the source data is coming from. + * + * @param src the filter source + * @return the path that is being filtered */ GIT_EXTERN(const char *) git_filter_source_path(const git_filter_source *src); /** * Get the file mode of the source file * If the mode is unknown, this will return 0 + * + * @param src the filter source + * @return the file mode for the file being filtered */ GIT_EXTERN(uint16_t) git_filter_source_filemode(const git_filter_source *src); @@ -114,16 +137,25 @@ GIT_EXTERN(uint16_t) git_filter_source_filemode(const git_filter_source *src); * Get the OID of the source * If the OID is unknown (often the case with GIT_FILTER_CLEAN) then * this will return NULL. + * + * @param src the filter source + * @return the object id of the file being filtered */ GIT_EXTERN(const git_oid *) git_filter_source_id(const git_filter_source *src); /** * Get the git_filter_mode_t to be used + * + * @param src the filter source + * @return the mode (direction) of the filter */ GIT_EXTERN(git_filter_mode_t) git_filter_source_mode(const git_filter_source *src); /** * Get the combination git_filter_flag_t options to be applied + * + * @param src the filter source + * @return the flags of the filter */ GIT_EXTERN(uint32_t) git_filter_source_flags(const git_filter_source *src); @@ -137,6 +169,9 @@ GIT_EXTERN(uint32_t) git_filter_source_flags(const git_filter_source *src); * before the first use of the filter, so you can defer expensive * initialization operations (in case libgit2 is being used in a way that * doesn't need the filter). + * + * @param self the filter to initialize + * @return 0 on success, negative number on failure */ typedef int GIT_CALLBACK(git_filter_init_fn)(git_filter *self); @@ -149,6 +184,8 @@ typedef int GIT_CALLBACK(git_filter_init_fn)(git_filter *self); * This may be called even if the `initialize` callback was not made. * * Typically this function will free the `git_filter` object itself. + * + * @param self the filter to shutdown */ typedef void GIT_CALLBACK(git_filter_shutdown_fn)(git_filter *self); @@ -171,6 +208,12 @@ typedef void GIT_CALLBACK(git_filter_shutdown_fn)(git_filter *self); * allocated (not stack), so that it doesn't go away before the `stream` * callback can use it. If a filter allocates and assigns a value to the * `payload`, it will need a `cleanup` callback to free the payload. + * + * @param self the filter check + * @param payload a data for future filter functions + * @param src the filter source + * @param attr_values the attribute values + * @return 0 on success or a negative value on error */ typedef int GIT_CALLBACK(git_filter_check_fn)( git_filter *self, @@ -191,6 +234,12 @@ typedef int GIT_CALLBACK(git_filter_check_fn)( * The `payload` value will refer to any payload that was set by the * `check` callback. It may be read from or written to as needed. * + * @param self the filter check + * @param payload a data for future filter functions + * @param to the input buffer + * @param from the output buffer + * @param src the filter source + * @return 0 on success or a negative value on error * @deprecated use git_filter_stream_fn */ typedef int GIT_CALLBACK(git_filter_apply_fn)( @@ -209,6 +258,13 @@ typedef int GIT_CALLBACK(git_filter_apply_fn)( * `git_writestream` that will the original data will be written to; * with that data, the `git_writestream` will then perform the filter * translation and stream the filtered data out to the `next` location. + * + * @param out the write stream + * @param self the filter + * @param payload a data for future filter functions + * @param src the filter source + * @param next the output stream + * @return 0 on success or a negative value on error */ typedef int GIT_CALLBACK(git_filter_stream_fn)( git_writestream **out, @@ -225,6 +281,9 @@ typedef int GIT_CALLBACK(git_filter_stream_fn)( * `stream` callbacks allocated a `payload` to keep per-source filter * state, use this callback to free that payload and release resources * as required. + * + * @param self the filter + * @param payload a data for future filter functions */ typedef void GIT_CALLBACK(git_filter_cleanup_fn)( git_filter *self, @@ -291,7 +350,10 @@ struct git_filter { git_filter_cleanup_fn cleanup; }; +/** Current version for the `git_filter_options` structure */ #define GIT_FILTER_VERSION 1 + +/** Static constructor for `git_filter_options` */ #define GIT_FILTER_INIT {GIT_FILTER_VERSION} /** @@ -300,7 +362,7 @@ struct git_filter { * * @param filter the `git_filter` struct to initialize. * @param version Version the struct; pass `GIT_FILTER_VERSION` - * @return Zero on success; -1 on failure. + * @return 0 on success; -1 on failure. */ GIT_EXTERN(int) git_filter_init(git_filter *filter, unsigned int version); @@ -350,4 +412,5 @@ GIT_EXTERN(int) git_filter_unregister(const char *name); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/hashsig.h b/include/git2/sys/hashsig.h index 09c19aec075..0d7be535ce3 100644 --- a/include/git2/sys/hashsig.h +++ b/include/git2/sys/hashsig.h @@ -9,6 +9,16 @@ #include "git2/common.h" +/** + * @file git2/sys/hashsig.h + * @brief Signatures for file similarity comparison + * @defgroup git_hashsig Git merge routines + * @ingroup Git + * + * Hash signatures are used for file similary comparison; this is + * used for git's rename handling. + * @{ + */ GIT_BEGIN_DECL /** @@ -101,6 +111,7 @@ GIT_EXTERN(int) git_hashsig_compare( const git_hashsig *a, const git_hashsig *b); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/index.h b/include/git2/sys/index.h index 1f6d93f7a99..b3b86a04598 100644 --- a/include/git2/sys/index.h +++ b/include/git2/sys/index.h @@ -12,8 +12,8 @@ /** * @file git2/sys/index.h - * @brief Low-level Git index manipulation routines - * @defgroup git_backend Git custom backend APIs + * @brief Low-level index manipulation routines + * @defgroup git_index Low-level index manipulation routines * @ingroup Git * @{ */ @@ -67,6 +67,7 @@ GIT_EXTERN(const git_index_name_entry *) git_index_name_get_byindex( * @param ancestor the path of the file as it existed in the ancestor * @param ours the path of the file as it existed in our tree * @param theirs the path of the file as it existed in their tree + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_index_name_add(git_index *index, const char *ancestor, const char *ours, const char *theirs); diff --git a/include/git2/sys/mempack.h b/include/git2/sys/mempack.h index 96bd8a7e86e..f9173e1f941 100644 --- a/include/git2/sys/mempack.h +++ b/include/git2/sys/mempack.h @@ -15,8 +15,8 @@ /** * @file git2/sys/mempack.h - * @brief Custom ODB backend that permits packing objects in-memory - * @defgroup git_backend Git custom backend APIs + * @brief A custom object database backend for storing objects in-memory + * @defgroup git_mempack A custom object database backend for storing objects in-memory * @ingroup Git * @{ */ @@ -60,6 +60,7 @@ GIT_EXTERN(int) git_mempack_new(git_odb_backend **out); * * @param backend The mempack backend * @param pb The packbuilder to use to write the packfile + * @return 0 on success or an error code */ GIT_EXTERN(int) git_mempack_write_thin_pack(git_odb_backend *backend, git_packbuilder *pb); @@ -101,6 +102,7 @@ GIT_EXTERN(int) git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_ba */ GIT_EXTERN(int) git_mempack_reset(git_odb_backend *backend); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/merge.h b/include/git2/sys/merge.h index ef4bc5aca3d..a9f522054ba 100644 --- a/include/git2/sys/merge.h +++ b/include/git2/sys/merge.h @@ -14,13 +14,18 @@ /** * @file git2/sys/merge.h - * @brief Git merge driver backend and plugin routines - * @defgroup git_merge Git merge driver APIs + * @brief Custom merge drivers + * @defgroup git_merge Custom merge drivers * @ingroup Git * @{ */ GIT_BEGIN_DECL +/** + * A "merge driver" is a mechanism that can be configured to handle + * conflict resolution for files changed in both the "ours" and "theirs" + * side of a merge. + */ typedef struct git_merge_driver git_merge_driver; /** @@ -31,8 +36,11 @@ typedef struct git_merge_driver git_merge_driver; */ GIT_EXTERN(git_merge_driver *) git_merge_driver_lookup(const char *name); +/** The "text" merge driver */ #define GIT_MERGE_DRIVER_TEXT "text" +/** The "binary" merge driver */ #define GIT_MERGE_DRIVER_BINARY "binary" +/** The "union" merge driver */ #define GIT_MERGE_DRIVER_UNION "union" /** @@ -40,23 +48,48 @@ GIT_EXTERN(git_merge_driver *) git_merge_driver_lookup(const char *name); */ typedef struct git_merge_driver_source git_merge_driver_source; -/** Get the repository that the source data is coming from. */ +/** + * Get the repository that the source data is coming from. + * + * @param src the merge driver source + * @return the repository + */ GIT_EXTERN(git_repository *) git_merge_driver_source_repo( const git_merge_driver_source *src); -/** Gets the ancestor of the file to merge. */ +/** + * Gets the ancestor of the file to merge. + * + * @param src the merge driver source + * @return the ancestor or NULL if there was no ancestor + */ GIT_EXTERN(const git_index_entry *) git_merge_driver_source_ancestor( const git_merge_driver_source *src); -/** Gets the ours side of the file to merge. */ +/** + * Gets the ours side of the file to merge. + * + * @param src the merge driver source + * @return the ours side or NULL if there was no ours side + */ GIT_EXTERN(const git_index_entry *) git_merge_driver_source_ours( const git_merge_driver_source *src); -/** Gets the theirs side of the file to merge. */ +/** + * Gets the theirs side of the file to merge. + * + * @param src the merge driver source + * @return the theirs side or NULL if there was no theirs side + */ GIT_EXTERN(const git_index_entry *) git_merge_driver_source_theirs( const git_merge_driver_source *src); -/** Gets the merge file options that the merge was invoked with */ +/** + * Gets the merge file options that the merge was invoked with. + * + * @param src the merge driver source + * @return the options + */ GIT_EXTERN(const git_merge_file_options *) git_merge_driver_source_file_options( const git_merge_driver_source *src); @@ -72,6 +105,9 @@ GIT_EXTERN(const git_merge_file_options *) git_merge_driver_source_file_options( * right before the first use of the driver, so you can defer expensive * initialization operations (in case libgit2 is being used in a way that * doesn't need the merge driver). + * + * @param self the merge driver to initialize + * @return 0 on success, or a negative number on failure */ typedef int GIT_CALLBACK(git_merge_driver_init_fn)(git_merge_driver *self); @@ -84,6 +120,8 @@ typedef int GIT_CALLBACK(git_merge_driver_init_fn)(git_merge_driver *self); * This may be called even if the `initialize` callback was not made. * * Typically this function will free the `git_merge_driver` object itself. + * + * @param self the merge driver to shutdown */ typedef void GIT_CALLBACK(git_merge_driver_shutdown_fn)(git_merge_driver *self); @@ -104,6 +142,14 @@ typedef void GIT_CALLBACK(git_merge_driver_shutdown_fn)(git_merge_driver *self); * specified by the file's attributes. * * The `src` contains the data about the file to be merged. + * + * @param self the merge driver + * @param path_out the resolved path + * @param mode_out the resolved mode + * @param merged_out the merged output contents + * @param filter_name the filter that was invoked + * @param src the data about the unmerged file + * @return 0 on success, or an error code */ typedef int GIT_CALLBACK(git_merge_driver_apply_fn)( git_merge_driver *self, @@ -139,6 +185,7 @@ struct git_merge_driver { git_merge_driver_apply_fn apply; }; +/** The version for the `git_merge_driver` */ #define GIT_MERGE_DRIVER_VERSION 1 /** @@ -179,4 +226,5 @@ GIT_EXTERN(int) git_merge_driver_unregister(const char *name); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/midx.h b/include/git2/sys/midx.h index 3a87484d2b5..2bf0d01eb48 100644 --- a/include/git2/sys/midx.h +++ b/include/git2/sys/midx.h @@ -11,9 +11,9 @@ #include "git2/types.h" /** - * @file git2/midx.h - * @brief Git multi-pack-index routines - * @defgroup git_midx Git multi-pack-index routines + * @file git2/sys/midx.h + * @brief Incremental multi-pack indexes + * @defgroup git_midx Incremental multi-pack indexes * @ingroup Git * @{ */ @@ -75,4 +75,5 @@ GIT_EXTERN(int) git_midx_writer_dump( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h index c42abd3707e..53d8d060eac 100644 --- a/include/git2/sys/odb_backend.h +++ b/include/git2/sys/odb_backend.h @@ -13,9 +13,9 @@ #include "git2/odb.h" /** - * @file git2/sys/backend.h - * @brief Git custom backend implementors functions - * @defgroup git_backend Git custom backend APIs + * @file git2/sys/odb_backend.h + * @brief Object database backends for custom object storage + * @defgroup git_backend Object database backends for custom object storage * @ingroup Git * @{ */ @@ -106,7 +106,10 @@ struct git_odb_backend { void GIT_CALLBACK(free)(git_odb_backend *); }; +/** Current version for the `git_odb_backend_options` structure */ #define GIT_ODB_BACKEND_VERSION 1 + +/** Static constructor for `git_odb_backend_options` */ #define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} /** @@ -167,6 +170,7 @@ GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); #endif +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/openssl.h b/include/git2/sys/openssl.h index b41c55c6d7f..8b74a98cd3d 100644 --- a/include/git2/sys/openssl.h +++ b/include/git2/sys/openssl.h @@ -9,6 +9,12 @@ #include "git2/common.h" +/** + * @file git2/sys/openssl.h + * @brief Custom OpenSSL functionality + * @defgroup git_openssl Custom OpenSSL functionality + * @{ + */ GIT_BEGIN_DECL /** @@ -33,6 +39,7 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_openssl_set_locking(void); +/** @} */ GIT_END_DECL -#endif +#endif diff --git a/include/git2/sys/path.h b/include/git2/sys/path.h index 2a0c7e00d3e..2963bca3f7f 100644 --- a/include/git2/sys/path.h +++ b/include/git2/sys/path.h @@ -10,6 +10,16 @@ #include "git2/common.h" +/** + * @file git2/sys/path.h + * @brief Custom path handling + * @defgroup git_path Custom path handling + * @ingroup Git + * + * Merge will take two commits and attempt to produce a commit that + * includes the changes that were made in both branches. + * @{ + */ GIT_BEGIN_DECL /** @@ -59,6 +69,7 @@ typedef enum { */ GIT_EXTERN(int) git_path_is_gitfile(const char *path, size_t pathlen, git_path_gitfile gitfile, git_path_fs fs); +/** @} */ GIT_END_DECL -#endif /* INCLUDE_sys_git_path */ +#endif diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index c31e26d9558..e88505b5e27 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -12,9 +12,9 @@ #include "git2/oid.h" /** - * @file git2/refdb_backend.h - * @brief Git custom refs backend functions - * @defgroup git_refdb_backend Git custom refs backend API + * @file git2/sys/refdb_backend.h + * @brief Custom reference database backends for refs storage + * @defgroup git_refdb_backend Custom reference database backends for refs storage * @ingroup Git * @{ */ @@ -312,7 +312,10 @@ struct git_refdb_backend { const git_reference *ref, const git_signature *sig, const char *message); }; +/** Current version for the `git_refdb_backend_options` structure */ #define GIT_REFDB_BACKEND_VERSION 1 + +/** Static constructor for `git_refdb_backend_options` */ #define GIT_REFDB_BACKEND_INIT {GIT_REFDB_BACKEND_VERSION} /** @@ -356,6 +359,7 @@ GIT_EXTERN(int) git_refdb_set_backend( git_refdb *refdb, git_refdb_backend *backend); +/** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/refs.h b/include/git2/sys/refs.h index d2ce2e0b914..e434e67c34d 100644 --- a/include/git2/sys/refs.h +++ b/include/git2/sys/refs.h @@ -13,8 +13,8 @@ /** * @file git2/sys/refs.h - * @brief Low-level Git ref creation - * @defgroup git_backend Git custom backend APIs + * @brief Low-level git reference creation + * @defgroup git_backend Low-level git reference creation * @ingroup Git * @{ */ @@ -46,4 +46,5 @@ GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/remote.h b/include/git2/sys/remote.h index 58950e1ec77..476965daa72 100644 --- a/include/git2/sys/remote.h +++ b/include/git2/sys/remote.h @@ -13,7 +13,7 @@ /** * @file git2/sys/remote.h * @brief Low-level remote functionality for custom transports - * @defgroup git_remote Low-level remote functionality + * @defgroup git_remote Low-level remote functionality for custom transports * @ingroup Git * @{ */ @@ -49,4 +49,5 @@ GIT_EXTERN(void) git_remote_connect_options_dispose( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h index 080a404c413..eb0a33a92de 100644 --- a/include/git2/sys/repository.h +++ b/include/git2/sys/repository.h @@ -13,13 +13,25 @@ /** * @file git2/sys/repository.h - * @brief Git repository custom implementation routines - * @defgroup git_backend Git custom backend APIs + * @brief Custom repository handling + * @defgroup git_repository Custom repository handling * @ingroup Git * @{ */ GIT_BEGIN_DECL +#ifdef GIT_EXPERIMENTAL_SHA256 + +/** + * Create a new repository with no backends. + * + * @param[out] out The blank repository + * @param oid_type the object ID type for this repository + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_repository_new(git_repository **out, git_oid_t oid_type); +#else + /** * Create a new repository with neither backends nor config object * @@ -30,13 +42,11 @@ GIT_BEGIN_DECL * can fail to function properly: locations under $GIT_DIR, $GIT_COMMON_DIR, * or $GIT_INFO_DIR are impacted. * - * @param out The blank repository + * @param[out] out The blank repository * @return 0 on success, or an error code */ -#ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_repository_new(git_repository **out, git_oid_t oid_type); -#else GIT_EXTERN(int) git_repository_new(git_repository **out); + #endif /** @@ -161,6 +171,7 @@ GIT_EXTERN(int) git_repository_set_bare(git_repository *repo); * and caches them so that subsequent calls to `git_submodule_lookup` are O(1). * * @param repo the repository whose submodules will be cached. + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_submodule_cache_all( git_repository *repo); @@ -176,10 +187,12 @@ GIT_EXTERN(int) git_repository_submodule_cache_all( * of these has changed, the cache might become invalid. * * @param repo the repository whose submodule cache will be cleared + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_submodule_cache_clear( git_repository *repo); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/sys/stream.h b/include/git2/sys/stream.h index 3277088c99c..eabff68643f 100644 --- a/include/git2/sys/stream.h +++ b/include/git2/sys/stream.h @@ -11,8 +11,16 @@ #include "git2/types.h" #include "git2/proxy.h" +/** + * @file git2/sys/stream.h + * @brief Streaming file I/O functionality + * @defgroup git_stream Streaming file I/O functionality + * @ingroup Git + * @{ + */ GIT_BEGIN_DECL +/** Current version for the `git_stream` structures */ #define GIT_STREAM_VERSION 1 /** @@ -147,6 +155,7 @@ GIT_EXTERN(int) git_stream_register_tls(git_stream_cb ctor); #endif +/**@}*/ GIT_END_DECL #endif diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 370ca45d570..ad6765c623e 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -18,14 +18,20 @@ /** * @file git2/sys/transport.h - * @brief Git custom transport registration interfaces and functions - * @defgroup git_transport Git custom transport registration + * @brief Custom transport registration interfaces and functions + * @defgroup git_transport Custom transport registration * @ingroup Git + * + * Callers can override the default HTTPS or SSH implementation by + * specifying a custom transport. * @{ */ GIT_BEGIN_DECL +/** + * The negotiation state during a fetch smart transport negotiation. + */ typedef struct { const git_remote_head * const *refs; size_t refs_len; @@ -146,7 +152,10 @@ struct git_transport { void GIT_CALLBACK(free)(git_transport *transport); }; +/** Current version for the `git_transport` structure */ #define GIT_TRANSPORT_VERSION 1 + +/** Static constructor for `git_transport` */ #define GIT_TRANSPORT_INIT {GIT_TRANSPORT_VERSION} /** @@ -299,6 +308,7 @@ GIT_EXTERN(int) git_transport_smart_credentials(git_credential **out, git_transp * * @param out options struct to fill * @param transport the transport to extract the data from. + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_transport_remote_connect_options( git_remote_connect_options *out, @@ -386,7 +396,14 @@ struct git_smart_subtransport { void GIT_CALLBACK(free)(git_smart_subtransport *transport); }; -/** A function which creates a new subtransport for the smart transport */ +/** + * A function that creates a new subtransport for the smart transport + * + * @param out the smart subtransport + * @param owner the transport owner + * @param param the input parameter + * @return 0 on success, or an error code + */ typedef int GIT_CALLBACK(git_smart_subtransport_cb)( git_smart_subtransport **out, git_transport *owner, @@ -429,6 +446,7 @@ typedef struct git_smart_subtransport_definition { * * @param out The newly created subtransport * @param owner The smart transport to own this subtransport + * @param param custom parameters for the subtransport * @return 0 or an error code */ GIT_EXTERN(int) git_smart_subtransport_http( @@ -441,6 +459,7 @@ GIT_EXTERN(int) git_smart_subtransport_http( * * @param out The newly created subtransport * @param owner The smart transport to own this subtransport + * @param param custom parameters for the subtransport * @return 0 or an error code */ GIT_EXTERN(int) git_smart_subtransport_git( @@ -453,6 +472,7 @@ GIT_EXTERN(int) git_smart_subtransport_git( * * @param out The newly created subtransport * @param owner The smart transport to own this subtransport + * @param param custom parameters for the subtransport * @return 0 or an error code */ GIT_EXTERN(int) git_smart_subtransport_ssh( @@ -462,4 +482,5 @@ GIT_EXTERN(int) git_smart_subtransport_ssh( /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/tag.h b/include/git2/tag.h index 98305365590..3b0c12ebcb8 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -15,7 +15,7 @@ /** * @file git2/tag.h - * @brief Git tag parsing routines + * @brief A (nearly) immutable pointer to a commit; useful for versioning * @defgroup git_tag Git tag management * @ingroup Git * @{ @@ -335,6 +335,7 @@ typedef int GIT_CALLBACK(git_tag_foreach_cb)(const char *name, git_oid *oid, voi * @param repo Repository * @param callback Callback function * @param payload Pointer to callback data (optional) + * @return 0 on success or an error code */ GIT_EXTERN(int) git_tag_foreach( git_repository *repo, @@ -380,4 +381,5 @@ GIT_EXTERN(int) git_tag_name_is_valid(int *valid, const char *name); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/trace.h b/include/git2/trace.h index 8cee3a94ecc..62cb87c012c 100644 --- a/include/git2/trace.h +++ b/include/git2/trace.h @@ -12,8 +12,8 @@ /** * @file git2/trace.h - * @brief Git tracing configuration routines - * @defgroup git_trace Git tracing configuration routines + * @brief Tracing functionality to introspect libgit2 in your application + * @defgroup git_trace Tracing functionality to introspect libgit2 in your application * @ingroup Git * @{ */ @@ -48,8 +48,13 @@ typedef enum { /** * An instance for a tracing function + * + * @param level the trace level + * @param msg the trace message */ -typedef void GIT_CALLBACK(git_trace_cb)(git_trace_level_t level, const char *msg); +typedef void GIT_CALLBACK(git_trace_cb)( + git_trace_level_t level, + const char *msg); /** * Sets the system tracing configuration to the specified level with the @@ -64,4 +69,5 @@ GIT_EXTERN(int) git_trace_set(git_trace_level_t level, git_trace_cb cb); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/transaction.h b/include/git2/transaction.h index 4938570b5a1..212d32919a7 100644 --- a/include/git2/transaction.h +++ b/include/git2/transaction.h @@ -12,8 +12,8 @@ /** * @file git2/transaction.h - * @brief Git transactional reference routines - * @defgroup git_transaction Git transactional reference routines + * @brief Transactional reference handling + * @defgroup git_transaction Transactional reference handling * @ingroup Git * @{ */ @@ -118,4 +118,5 @@ GIT_EXTERN(void) git_transaction_free(git_transaction *tx); /** @} */ GIT_END_DECL + #endif diff --git a/include/git2/transport.h b/include/git2/transport.h index 5a27de9a860..04a7390b10f 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -15,8 +15,8 @@ /** * @file git2/transport.h - * @brief Git transport interfaces and functions - * @defgroup git_transport interfaces and functions + * @brief Transports are the low-level mechanism to connect to a remote server + * @defgroup git_transport Transports are the low-level mechanism to connect to a remote server * @ingroup Git * @{ */ @@ -30,10 +30,18 @@ GIT_BEGIN_DECL * @param str The message from the transport * @param len The length of the message * @param payload Payload provided by the caller + * @return 0 on success or an error code */ typedef int GIT_CALLBACK(git_transport_message_cb)(const char *str, int len, void *payload); -/** Signature of a function which creates a transport */ +/** + * Signature of a function which creates a transport. + * + * @param out the transport generate + * @param owner the owner for the transport + * @param param the param to the transport creation + * @return 0 on success or an error code + */ typedef int GIT_CALLBACK(git_transport_cb)(git_transport **out, git_remote *owner, void *param); /** @} */ diff --git a/include/git2/tree.h b/include/git2/tree.h index ce0a60907fa..b8e2de217ed 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -14,8 +14,8 @@ /** * @file git2/tree.h - * @brief Git tree parsing, loading routines - * @defgroup git_tree Git tree parsing, loading routines + * @brief Trees are collections of files and folders to make up the repository hierarchy + * @defgroup git_tree Trees are collections of files and folders to make up the repository hierarchy * @ingroup Git * @{ */ @@ -24,7 +24,7 @@ GIT_BEGIN_DECL /** * Lookup a tree object from the repository. * - * @param out Pointer to the looked up tree + * @param[out] out Pointer to the looked up tree * @param repo The repo to use when locating the tree. * @param id Identity of the tree to locate. * @return 0 or an error code @@ -345,6 +345,10 @@ GIT_EXTERN(int) git_treebuilder_remove( * The return value is treated as a boolean, with zero indicating that the * entry should be left alone and any non-zero value meaning that the * entry should be removed from the treebuilder list (i.e. filtered out). + * + * @param entry the tree entry for the callback to examine + * @param payload the payload from the caller + * @return 0 to do nothing, non-zero to remove the entry */ typedef int GIT_CALLBACK(git_treebuilder_filter_cb)( const git_tree_entry *entry, void *payload); @@ -379,7 +383,14 @@ GIT_EXTERN(int) git_treebuilder_filter( GIT_EXTERN(int) git_treebuilder_write( git_oid *id, git_treebuilder *bld); -/** Callback for the tree traversal method */ +/** + * Callback for the tree traversal method. + * + * @param root the current (relative) root to the entry + * @param entry the tree entry + * @param payload the caller-provided callback payload + * @return a positive value to skip the entry, a negative value to stop the walk + */ typedef int GIT_CALLBACK(git_treewalk_cb)( const char *root, const git_tree_entry *entry, void *payload); @@ -470,6 +481,6 @@ typedef struct { GIT_EXTERN(int) git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseline, size_t nupdates, const git_tree_update *updates); /** @} */ - GIT_END_DECL + #endif diff --git a/include/git2/types.h b/include/git2/types.h index d4b033dc770..a4afd18c3bc 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -81,13 +81,18 @@ typedef enum { GIT_OBJECT_REF_DELTA = 7 /**< A delta, base is given by object id. */ } git_object_t; -/** An open object database handle. */ +/** + * An object database stores the objects (commit, trees, blobs, tags, + * etc) for a repository. + */ typedef struct git_odb git_odb; /** A custom backend in an ODB */ typedef struct git_odb_backend git_odb_backend; -/** An object read from the ODB */ +/** + * A "raw" object read from the object database. + */ typedef struct git_odb_object git_odb_object; /** A stream to read/write from the ODB */ @@ -194,7 +199,18 @@ typedef struct git_reference_iterator git_reference_iterator; /** Transactional interface to references */ typedef struct git_transaction git_transaction; -/** Annotated commits, the input to merge and rebase. */ +/** + * Annotated commits are commits with additional metadata about how the + * commit was resolved, which can be used for maintaining the user's + * "intent" through commands like merge and rebase. + * + * For example, if a user wants to conceptually "merge `HEAD`", then the + * commit portion of an annotated commit will point to the `HEAD` commit, + * but the _annotation_ will denote the ref `HEAD`. This allows git to + * perform the internal bookkeeping so that the system knows both the + * content of what is being merged but also how the content was looked up + * so that it can be recorded in the reflog appropriately. + */ typedef struct git_annotated_commit git_annotated_commit; /** Representation of a status collection */ diff --git a/include/git2/version.h b/include/git2/version.h index 8cde510d67e..d512bbb06d0 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,6 +7,14 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ +/** + * @file git2/version.h + * @brief The version of libgit2 + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + /** * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. @@ -61,4 +69,7 @@ #define LIBGIT2_VERSION_CHECK(major, minor, revision) \ (LIBGIT2_VERSION_NUMBER >= ((major)*1000000)+((minor)*10000)+((revision)*100)) +/** @} */ +GIT_END_DECL + #endif diff --git a/include/git2/worktree.h b/include/git2/worktree.h index a6e5d17c4b1..fd3751753b4 100644 --- a/include/git2/worktree.h +++ b/include/git2/worktree.h @@ -14,9 +14,9 @@ #include "checkout.h" /** - * @file git2/worktrees.h - * @brief Git worktree related functions - * @defgroup git_commit Git worktree related functions + * @file git2/worktree.h + * @brief Additional working directories for a repository + * @defgroup git_commit Additional working directories for a repository * @ingroup Git * @{ */ @@ -96,7 +96,10 @@ typedef struct git_worktree_add_options { git_checkout_options checkout_options; } git_worktree_add_options; +/** Current version for the `git_worktree_add_options` structure */ #define GIT_WORKTREE_ADD_OPTIONS_VERSION 1 + +/** Static constructor for `git_worktree_add_options` */ #define GIT_WORKTREE_ADD_OPTIONS_INIT { GIT_WORKTREE_ADD_OPTIONS_VERSION, \ 0, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT } @@ -211,7 +214,10 @@ typedef struct git_worktree_prune_options { uint32_t flags; } git_worktree_prune_options; +/** Current version for the `git_worktree_prune_options` structure */ #define GIT_WORKTREE_PRUNE_OPTIONS_VERSION 1 + +/** Static constructor for `git_worktree_prune_options` */ #define GIT_WORKTREE_PRUNE_OPTIONS_INIT {GIT_WORKTREE_PRUNE_OPTIONS_VERSION,0} /** @@ -268,4 +274,5 @@ GIT_EXTERN(int) git_worktree_prune(git_worktree *wt, /** @} */ GIT_END_DECL + #endif From 2adb7bc3f5f6eed38938ec6b7ab4a79827ade37e Mon Sep 17 00:00:00 2001 From: Ryan Pham Date: Thu, 28 Nov 2024 10:31:39 +0900 Subject: [PATCH 705/816] refs: Handle normalizing negative refspecs Negative refspecs were added in Git v2.29.0 which allows refspecs to be prefixed with `^`[^1]. Currently, the library is unable to normalize negative refspecs which causes errors in different tools that rely on `libgit2`. Specifically, when the library attempts to parse and normalize a negative refspec, it returns a `GIT_EINVALIDSPEC` code. Add the ability to correctly normalize negative refspecs. While this PR will not update the behavior of `fetch`, or other actions that rely on negative refspecs, this allows us to be able to successfully parse and normalize them. A future change will handle updating the individual actions. [^1]: https://github.com/git/git/commit/c0192df6306d4d9ad77f6015a053925b13155834 --- src/libgit2/refs.c | 25 +++++++++++++++++++------ tests/libgit2/refs/normalize.c | 8 ++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index 007af37fd18..12dbd7aca9d 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -835,17 +835,20 @@ static int is_valid_ref_char(char ch) } } -static int ensure_segment_validity(const char *name, char may_contain_glob) +static int ensure_segment_validity(const char *name, char may_contain_glob, bool allow_caret_prefix) { const char *current = name; + const char *start = current; char prev = '\0'; const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION); int segment_len; if (*current == '.') return -1; /* Refname starts with "." */ + if (allow_caret_prefix && *current == '^') + start++; - for (current = name; ; current++) { + for (current = start; ; current++) { if (*current == '\0' || *current == '/') break; @@ -877,7 +880,7 @@ static int ensure_segment_validity(const char *name, char may_contain_glob) return segment_len; } -static bool is_all_caps_and_underscore(const char *name, size_t len) +static bool is_valid_normalized_name(const char *name, size_t len) { size_t i; char c; @@ -888,6 +891,9 @@ static bool is_all_caps_and_underscore(const char *name, size_t len) for (i = 0; i < len; i++) { c = name[i]; + if (i == 0 && c == '^') + continue; /* The first character is allowed to be "^" for negative refspecs */ + if ((c < 'A' || c > 'Z') && c != '_') return false; } @@ -908,6 +914,7 @@ int git_reference__normalize_name( int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; unsigned int process_flags; bool normalize = (buf != NULL); + bool allow_caret_prefix = true; bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0; #ifdef GIT_USE_ICONV @@ -945,7 +952,7 @@ int git_reference__normalize_name( while (true) { char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN; - segment_len = ensure_segment_validity(current, may_contain_glob); + segment_len = ensure_segment_validity(current, may_contain_glob, allow_caret_prefix); if (segment_len < 0) goto cleanup; @@ -981,6 +988,12 @@ int git_reference__normalize_name( break; current += segment_len + 1; + + /* + * A caret prefix is only allowed in the first segment to signify a + * negative refspec. + */ + allow_caret_prefix = false; } /* A refname can not be empty */ @@ -1000,12 +1013,12 @@ int git_reference__normalize_name( if ((segments_count == 1 ) && !(flags & GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND) && - !(is_all_caps_and_underscore(name, (size_t)segment_len) || + !(is_valid_normalized_name(name, (size_t)segment_len) || ((flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) goto cleanup; if ((segments_count > 1) - && (is_all_caps_and_underscore(name, strchr(name, '/') - name))) + && (is_valid_normalized_name(name, strchr(name, '/') - name))) goto cleanup; error = 0; diff --git a/tests/libgit2/refs/normalize.c b/tests/libgit2/refs/normalize.c index ff815002c20..ca38007b405 100644 --- a/tests/libgit2/refs/normalize.c +++ b/tests/libgit2/refs/normalize.c @@ -399,3 +399,11 @@ void test_refs_normalize__refspec_pattern(void) ensure_refname_invalid( ONE_LEVEL_AND_REFSPEC, "*/*/foo"); } + +void test_refs_normalize__negative_refspec_pattern(void) +{ + ensure_refname_normalized( + GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "^foo/bar", "^foo/bar"); + ensure_refname_invalid( + GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo/^bar"); +} From 1da67ef096136a881211582287374c876b37e8f8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Dec 2024 12:20:42 +0000 Subject: [PATCH 706/816] Allow documentation (re)generation in CI build Provide a mechanism to allow the documentation to be force rebuilt. --- .github/workflows/documentation.yml | 13 +++++++++++- script/api-docs/generate | 32 ++++++++++++++++++----------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 9ef44bca791..5eab5b6ced9 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -6,6 +6,11 @@ on: branches: [ main, maint/* ] release: workflow_dispatch: + inputs: + force: + description: 'Force rebuild' + type: boolean + required: true concurrency: group: documentation @@ -42,8 +47,14 @@ jobs: working-directory: source - name: Generate documentation run: | + args="" + + if [ "${{ inputs.force }}" = "true" ]; then + args="--force" + fi + npm install - ./generate ../.. ../../../www/docs + ./generate $args ../.. ../../../www/docs working-directory: source/script/api-docs - name: Examine changes run: | diff --git a/script/api-docs/generate b/script/api-docs/generate index c103cc19822..bc9af0cae66 100755 --- a/script/api-docs/generate +++ b/script/api-docs/generate @@ -9,17 +9,29 @@ set -eo pipefail source_path=$(mktemp -d) -verbose=true +verbose= force= -if [ "$1" = "" ]; then - echo "usage: $0 repo_path output_path" 1>&2 +for var in "$@"; do + if [ "${var}" == "--verbose" ]; then + verbose=true + elif [ "${var}" == "--force" ]; then + force=true + elif [ "${repo_path}" == "" ]; then + repo_path="${var}" + elif [ "${output_path}" == "" ]; then + output_path="${var}" + else + repo_path="" + output_path="" + fi +done + +if [ "${repo_path}" = "" -o "${output_path}" = "" ]; then + echo "usage: $0 [--verbose] [--force] repo_path output_path" 1>&2 exit 1 fi -repo_path=$1 -output_path=$2 - function do_checkout { if [ "$1" = "" ]; then echo "usage: $0 source_path" 1>&2 @@ -78,14 +90,9 @@ for version in ${source_path}/*; do fi fi - options="" - if [ "${force}" ]; then - options="${options} --force" - fi - echo "Generating raw API documentation for ${version}..." mkdir -p "${output_path}/api" - node ./api-generator.js $options "${source_path}/${version}" > "${output_path}/api/${version}.json" + node ./api-generator.js "${source_path}/${version}" > "${output_path}/api/${version}.json" done if [ "${verbose}" ]; then @@ -103,3 +110,4 @@ if [ "${force}" ]; then fi node ./docs-generator.js --verbose --jekyll-layout default "${output_path}/api" "${output_path}/reference" +node ./docs-generator.js ${options} --jekyll-layout default "${output_path}/api" "${output_path}/reference" From 6297b6195ce6ae1c6d055740d26bca623efcf506 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Dec 2024 09:24:57 +0000 Subject: [PATCH 707/816] Add search capabilities to docs Include "minisearch" which is a straightforward client-side search tool; and a script to generate the search index for minisearch for each version of libgit2. --- script/api-docs/generate | 1 + script/api-docs/package-lock.json | 8 +- script/api-docs/package.json | 3 +- script/api-docs/search-generator.js | 212 ++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 2 deletions(-) create mode 100755 script/api-docs/search-generator.js diff --git a/script/api-docs/generate b/script/api-docs/generate index bc9af0cae66..b150fc8e21b 100755 --- a/script/api-docs/generate +++ b/script/api-docs/generate @@ -109,5 +109,6 @@ if [ "${force}" ]; then options="${options} --force" fi +node ./search-generator.js --verbose "${output_path}/api" "${output_path}/search-index" node ./docs-generator.js --verbose --jekyll-layout default "${output_path}/api" "${output_path}/reference" node ./docs-generator.js ${options} --jekyll-layout default "${output_path}/api" "${output_path}/reference" diff --git a/script/api-docs/package-lock.json b/script/api-docs/package-lock.json index bd9ca1a4756..3ba22260f12 100644 --- a/script/api-docs/package-lock.json +++ b/script/api-docs/package-lock.json @@ -6,7 +6,8 @@ "": { "dependencies": { "commander": "^12.1.0", - "markdown-it": "^14.1.0" + "markdown-it": "^14.1.0", + "minisearch": "^7.1.1" } }, "node_modules/argparse": { @@ -62,6 +63,11 @@ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" }, + "node_modules/minisearch": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.1.tgz", + "integrity": "sha512-b3YZEYCEH4EdCAtYP7OlDyx7FdPwNzuNwLQ34SfJpM9dlbBZzeXndGavTrC+VCiRWomL21SWfMc6SCKO/U2ZNw==" + }, "node_modules/punycode.js": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", diff --git a/script/api-docs/package.json b/script/api-docs/package.json index 53ae0705407..67a6fe7aa2a 100644 --- a/script/api-docs/package.json +++ b/script/api-docs/package.json @@ -1,6 +1,7 @@ { "dependencies": { "commander": "^12.1.0", - "markdown-it": "^14.1.0" + "markdown-it": "^14.1.0", + "minisearch": "^7.1.1" } } diff --git a/script/api-docs/search-generator.js b/script/api-docs/search-generator.js new file mode 100755 index 00000000000..cad73f947ae --- /dev/null +++ b/script/api-docs/search-generator.js @@ -0,0 +1,212 @@ +#!/usr/bin/env node + +const markdownit = require('markdown-it'); +const { program } = require('commander'); +const minisearch = require('minisearch'); + +const path = require('node:path'); +const fs = require('node:fs/promises'); + +const linkPrefix = '/docs/reference'; + +const defaultBranch = 'main'; + +function uniqueifyId(api, nodes) { + let suffix = "", i = 1; + + while (true) { + const possibleId = `${api.kind}-${api.name}${suffix}`; + let collision = false; + + for (const item of nodes) { + if (item.id === possibleId) { + collision = true; + break; + } + } + + if (!collision) { + return possibleId; + } + + suffix = `-${++i}`; + } +} + +async function produceSearchIndex(version, apiData) { + const nodes = [ ]; + + for (const group in apiData['groups']) { + for (const name in apiData['groups'][group]['apis']) { + const api = apiData['groups'][group]['apis'][name]; + + let displayName = name; + + if (api.kind === 'macro') { + displayName = displayName.replace(/\(.*/, ''); + } + + const apiSearchData = { + id: uniqueifyId(api, nodes), + name: displayName, + group: group, + kind: api.kind + }; + + apiSearchData.description = Array.isArray(api.comment) ? + api.comment[0] : api.comment; + + let detail = ""; + + if (api.kind === 'macro') { + detail = api.value; + } + else if (api.kind === 'alias') { + detail = api.type; + } + else { + let details = undefined; + + if (api.kind === 'struct' || api.kind === 'enum') { + details = api.members; + } + else if (api.kind === 'function' || api.kind === 'callback') { + details = api.params; + } + else { + throw new Error(`unknown api type '${api.kind}'`); + } + + for (const item of details || [ ]) { + if (detail.length > 0) { + detail += ' '; + } + + detail += item.name; + + if (item.comment) { + detail += ' '; + detail += item.comment; + } + } + + if (api.kind === 'function' || api.kind === 'callback') { + if (detail.length > 0 && api.returns?.type) { + detail += ' ' + api.returns.type; + } + + if (detail.length > 0 && api.returns?.comment) { + detail += ' ' + api.returns.comment; + } + } + } + + detail = detail.replaceAll(/\s+/g, ' ') + .replaceAll(/[\"\'\`]/g, ''); + + apiSearchData.detail = detail; + + nodes.push(apiSearchData); + } + } + + const index = new minisearch({ + fields: [ 'name', 'description', 'detail' ], + storeFields: [ 'name', 'group', 'kind', 'description' ], + searchOptions: { boost: { name: 5, description: 2 } } + }); + + index.addAll(nodes); + + const filename = `${outputPath}/${version}.json`; + await fs.mkdir(outputPath, { recursive: true }); + await fs.writeFile(filename, JSON.stringify(index, null, 2)); +} + +function versionSort(a, b) { + if (a === b) { + return 0; + } + + const aVersion = a.match(/^v(\d+)(?:\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?(?:-(.*))?$/); + const bVersion = b.match(/^v(\d+)(?:\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?(?:-(.*))?$/); + + if (!aVersion && !bVersion) { + return a.localeCompare(b); + } + else if (aVersion && !bVersion) { + return -1; + } + else if (!aVersion && bVersion) { + return 1; + } + + for (let i = 1; i < 5; i++) { + if (!aVersion[i] && !bVersion[i]) { + break; + } + else if (aVersion[i] && !bVersion[i]) { + return 1; + } + else if (!aVersion[i] && bVersion[i]) { + return -1; + } + else if (aVersion[i] !== bVersion[i]) { + return aVersion[i] - bVersion[i]; + } + } + + if (aVersion[5] && !bVersion[5]) { + return -1; + } + else if (!aVersion[5] && bVersion[5]) { + return 1; + } + else if (aVersion[5] && bVersion[5]) { + return aVersion[5].localeCompare(bVersion[5]); + } + + return 0; +} + +program.option('--verbose') + .option('--version '); +program.parse(); + +const options = program.opts(); + +if (program.args.length != 2) { + console.error(`usage: ${path.basename(process.argv[1])} raw_api_dir output_dir`); + process.exit(1); +} + +const docsPath = program.args[0]; +const outputPath = program.args[1]; + +(async () => { + try { + const v = options.version ? options.version : + (await fs.readdir(docsPath)) + .filter(a => a.endsWith('.json')) + .map(a => a.replace(/\.json$/, '')); + + const versions = v.sort(versionSort).reverse(); + + for (const version of versions) { + if (options.verbose) { + console.log(`Reading documentation data for ${version}...`); + } + + const apiData = JSON.parse(await fs.readFile(`${docsPath}/${version}.json`)); + + if (options.verbose) { + console.log(`Creating minisearch index for ${version}...`); + } + + await produceSearchIndex(version, apiData); + } + } catch (e) { + console.error(e); + process.exit(1); + } +})(); From 5efc00612c853f65f93dd9bd3a0fec123968542e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Dec 2024 09:36:39 +0000 Subject: [PATCH 708/816] Generate search page in documentation generation --- script/api-docs/docs-generator.js | 91 ++++++++++++++++++++++++++++--- script/api-docs/generate | 13 +++-- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/script/api-docs/docs-generator.js b/script/api-docs/docs-generator.js index 5be9e1d20b3..bfa7fe8ee6f 100755 --- a/script/api-docs/docs-generator.js +++ b/script/api-docs/docs-generator.js @@ -96,6 +96,7 @@ function produceHeader(version, api, type) { content += `

    ${api.name}

    \n`; content += produceAttributes(version, api, type); + content += produceSearchArea(version, type); content += produceVersionPicker(version, `apiHeaderVersionSelect ${type}HeaderVersionSelect`, @@ -553,6 +554,23 @@ async function layout(data) { return layout.toString().replaceAll(/{{([a-z]+)}}/g, (match, p1) => data[p1] || ""); } +function produceSearchArea(version, type) { + let content = ""; + + content += `\n`; + content += ` \n`; + content += ` \n`; + + content += `
    \n`; + content += ` \n`; + content += `
    \n`; + content += `
    \n`; + content += `
    \n`; + content += `\n`; + + return content; +} + async function produceDocumentationForApi(version, api, type) { let content = ""; @@ -834,6 +852,7 @@ async function produceIndexForGroup(version, group, versionApis) { content += `
    \n`; content += `

    ${groupName}

    \n`; + content += produceSearchArea(version, 'group'); content += produceVersionPicker(version, "groupHeaderVersionSelect", (v) => { if (apiData[v]['groups'][group]) { return `${linkPrefix}/${v}/${groupName}/index.html`; @@ -963,6 +982,7 @@ function versionIndexContent(version, apiData) { content += `
    \n`; content += `

    ${projectTitle} ${version}

    \n`; + content += produceSearchArea(version, 'version'); content += produceVersionPicker(version, "versionHeaderVersionSelect", (v) => `${linkPrefix}/${v}/index.html`); @@ -1187,6 +1207,62 @@ function calculateVersionDeltas(apiData) { } } +async function produceSearch(versions) { + if (options.verbose) { + console.log(`Producing search page...`); + } + + let content = ""; + + content += `\n`; + content += `\n`; + content += `\n`; + content += `\n`; + + content += `\n`; + + content += ` \n`; + + const filename = `${outputPath}/search.html`; + + await fs.mkdir(outputPath, { recursive: true }); + await fs.writeFile(filename, await layout({ + title: `API search (${projectTitle})`, + content: content + })); +} + async function produceMainIndex(versions) { const versionList = versions.sort(versionSort); const versionDefault = versionList[versionList.length - 1]; @@ -1273,6 +1349,7 @@ function versionSort(a, b) { program.option('--output ') .option('--layout ') .option('--jekyll-layout ') + .option('--version ') .option('--verbose') .option('--force') .option('--strict'); @@ -1290,13 +1367,12 @@ const outputPath = program.args[1]; (async () => { try { - for (const version of (await fs.readdir(docsPath)) - .filter(a => a.endsWith('.json')) - .map(a => a.replace(/\.json$/, '')) - .sort(versionSort) - .reverse()) { - versions.push(version); - } + const v = options.version ? options.version : + (await fs.readdir(docsPath)) + .filter(a => a.endsWith('.json')) + .map(a => a.replace(/\.json$/, '')); + + versions.push(...v.sort(versionSort).reverse()); for (const version of versions) { if (options.verbose) { @@ -1318,6 +1394,7 @@ const outputPath = program.args[1]; await produceDocumentationForVersion(version, apiData[version]); } + await produceSearch(versions); await produceMainIndex(versions); } catch (e) { console.error(e); diff --git a/script/api-docs/generate b/script/api-docs/generate index b150fc8e21b..76f3d8ce6a8 100755 --- a/script/api-docs/generate +++ b/script/api-docs/generate @@ -101,14 +101,15 @@ if [ "${verbose}" ]; then echo "" fi -options="" +search_options="" +docs_options="" if [ "${verbose}" ]; then - options="${options} --verbose" + search_options="${search_options} --verbose" + docs_options="${docs_options} --verbose" fi if [ "${force}" ]; then - options="${options} --force" + docs_options="${docs_options} --force" fi -node ./search-generator.js --verbose "${output_path}/api" "${output_path}/search-index" -node ./docs-generator.js --verbose --jekyll-layout default "${output_path}/api" "${output_path}/reference" -node ./docs-generator.js ${options} --jekyll-layout default "${output_path}/api" "${output_path}/reference" +node ./search-generator.js ${search_options} "${output_path}/api" "${output_path}/search-index" +node ./docs-generator.js ${docs_options} --jekyll-layout default "${output_path}/api" "${output_path}/reference" From 8ae0a22bf9fed972d8311e16f4d27721e2f84990 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Dec 2024 17:02:08 +0000 Subject: [PATCH 709/816] Documentation: don't resort versions Array.sort() mutates the array _and_ returns it; don't mutate the version array. --- script/api-docs/docs-generator.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/script/api-docs/docs-generator.js b/script/api-docs/docs-generator.js index bfa7fe8ee6f..2670b8a3a7b 100755 --- a/script/api-docs/docs-generator.js +++ b/script/api-docs/docs-generator.js @@ -1264,8 +1264,7 @@ async function produceSearch(versions) { } async function produceMainIndex(versions) { - const versionList = versions.sort(versionSort); - const versionDefault = versionList[versionList.length - 1]; + const versionDefault = versions[0]; if (options.verbose) { console.log(`Producing documentation index...`); From 88fee7af5622309bfe9b02df289de27a5fa7c017 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Dec 2024 21:52:44 +0000 Subject: [PATCH 710/816] Documentation: update refdb_backend docs Parameters are documented by `@param`, not `@arg` --- include/git2/sys/refdb_backend.h | 66 ++++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index e88505b5e27..813822a69bd 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -65,9 +65,9 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg exists The implementation shall set this to `0` if a ref does + * @param exists The implementation shall set this to `0` if a ref does * not exist, otherwise to `1`. - * @arg ref_name The reference's name that should be checked for + * @param ref_name The reference's name that should be checked for * existence. * @return `0` on success, a negative error value code. */ @@ -81,9 +81,9 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg out The implementation shall set this to the allocated + * @param out The implementation shall set this to the allocated * reference, if it could be found, otherwise to `NULL`. - * @arg ref_name The reference's name that should be checked for + * @param ref_name The reference's name that should be checked for * existence. * @return `0` on success, `GIT_ENOTFOUND` if the reference does * exist, otherwise a negative error code. @@ -98,12 +98,12 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg out The implementation shall set this to the allocated + * @param out The implementation shall set this to the allocated * reference iterator. A custom structure may be used with an * embedded `git_reference_iterator` structure. Both `next` * and `next_name` functions of `git_reference_iterator` need * to be populated. - * @arg glob A pattern to filter references by. If given, the iterator + * @param glob A pattern to filter references by. If given, the iterator * shall only return references that match the glob when * passed to `wildmatch`. * @return `0` on success, otherwise a negative error code. @@ -118,20 +118,20 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg ref The reference to persist. May either be a symbolic or + * @param ref The reference to persist. May either be a symbolic or * direct reference. - * @arg force Whether to write the reference if a reference with the + * @param force Whether to write the reference if a reference with the * same name already exists. - * @arg who The person updating the reference. Shall be used to create + * @param who The person updating the reference. Shall be used to create * a reflog entry. - * @arg message The message detailing what kind of reference update is + * @param message The message detailing what kind of reference update is * performed. Shall be used to create a reflog entry. - * @arg old If not `NULL` and `force` is not set, then the + * @param old If not `NULL` and `force` is not set, then the * implementation needs to ensure that the reference is currently at * the given OID before writing the new value. If both `old` * and `old_target` are `NULL`, then the reference should not * exist at the point of writing. - * @arg old_target If not `NULL` and `force` is not set, then the + * @param old_target If not `NULL` and `force` is not set, then the * implementation needs to ensure that the symbolic * reference is currently at the given target before * writing the new value. If both `old` and @@ -149,15 +149,15 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg out The implementation shall set this to the newly created + * @param out The implementation shall set this to the newly created * reference or `NULL` on error. - * @arg old_name The current name of the reference that is to be renamed. - * @arg new_name The new name that the old reference shall be renamed to. - * @arg force Whether to write the reference if a reference with the + * @param old_name The current name of the reference that is to be renamed. + * @param new_name The new name that the old reference shall be renamed to. + * @param force Whether to write the reference if a reference with the * target name already exists. - * @arg who The person updating the reference. Shall be used to create + * @param who The person updating the reference. Shall be used to create * a reflog entry. - * @arg message The message detailing what kind of reference update is + * @param message The message detailing what kind of reference update is * performed. Shall be used to create a reflog entry. * @return `0` on success, otherwise a negative error code. */ @@ -173,11 +173,11 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg ref_name The name of the reference name that shall be deleted. - * @arg old_id If not `NULL` and `force` is not set, then the + * @param ref_name The name of the reference name that shall be deleted. + * @param old_id If not `NULL` and `force` is not set, then the * implementation needs to ensure that the reference is currently at * the given OID before writing the new value. - * @arg old_target If not `NULL` and `force` is not set, then the + * @param old_target If not `NULL` and `force` is not set, then the * implementation needs to ensure that the symbolic * reference is currently at the given target before * writing the new value. @@ -243,7 +243,7 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg reflog The complete reference log for a given reference. Note + * @param reflog The complete reference log for a given reference. Note * that this may contain entries that have already been * written to disk. * @return `0` on success, a negative error code otherwise @@ -255,8 +255,8 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg old_name The name of old reference whose reflog shall be renamed from. - * @arg new_name The name of new reference whose reflog shall be renamed to. + * @param old_name The name of old reference whose reflog shall be renamed from. + * @param new_name The name of new reference whose reflog shall be renamed to. * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(reflog_rename)(git_refdb_backend *_backend, const char *old_name, const char *new_name); @@ -266,7 +266,7 @@ struct git_refdb_backend { * * A refdb implementation must provide this function. * - * @arg name The name of the reference whose reflog shall be deleted. + * @param name The name of the reference whose reflog shall be deleted. * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(reflog_delete)(git_refdb_backend *backend, const char *name); @@ -277,9 +277,9 @@ struct git_refdb_backend { * A refdb implementation may provide this function; if it is not * provided, the transaction API will fail to work. * - * @arg payload_out Opaque parameter that will be passed verbosely to + * @param payload_out Opaque parameter that will be passed verbosely to * `unlock`. - * @arg refname Reference that shall be locked. + * @param refname Reference that shall be locked. * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(lock)(void **payload_out, git_refdb_backend *backend, const char *refname); @@ -294,16 +294,16 @@ struct git_refdb_backend { * A refdb implementation must provide this function if a `lock` * implementation is provided. * - * @arg payload The payload returned by `lock`. - * @arg success `1` if a reference should be updated, `2` if + * @param payload The payload returned by `lock`. + * @param success `1` if a reference should be updated, `2` if * a reference should be deleted, `0` if the lock must be * discarded. - * @arg update_reflog `1` in case the reflog should be updated, `0` + * @param update_reflog `1` in case the reflog should be updated, `0` * otherwise. - * @arg ref The reference which should be unlocked. - * @arg who The person updating the reference. Shall be used to create + * @param ref The reference which should be unlocked. + * @param who The person updating the reference. Shall be used to create * a reflog entry in case `update_reflog` is set. - * @arg message The message detailing what kind of reference update is + * @param message The message detailing what kind of reference update is * performed. Shall be used to create a reflog entry in * case `update_reflog` is set. * @return `0` on success, a negative error code otherwise From 4bb69b08274933c021b68312a97bb1d130cbb3c4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Dec 2024 22:36:10 +0000 Subject: [PATCH 711/816] odb_mempack: use an out param --- include/git2/sys/mempack.h | 5 +++-- src/libgit2/odb_mempack.c | 13 +++++++++++-- tests/libgit2/odb/backend/mempack.c | 11 ++++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/git2/sys/mempack.h b/include/git2/sys/mempack.h index 171c9e56e01..37824390282 100644 --- a/include/git2/sys/mempack.h +++ b/include/git2/sys/mempack.h @@ -104,10 +104,11 @@ GIT_EXTERN(int) git_mempack_reset(git_odb_backend *backend); /** * Get the total number of objects in mempack * + * @param count The count of objects in the mempack * @param backend The mempack backend - * @return the number of objects in the mempack, -1 on error + * @return 0 on success, or -1 on error */ -GIT_EXTERN(int) git_mempack_object_count(git_odb_backend *backend); +GIT_EXTERN(int) git_mempack_object_count(size_t *count, git_odb_backend *backend); GIT_END_DECL diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c index 55bb134dfd7..1b235d20fa2 100644 --- a/src/libgit2/odb_mempack.c +++ b/src/libgit2/odb_mempack.c @@ -210,9 +210,18 @@ int git_mempack_new(git_odb_backend **out) return 0; } -int git_mempack_object_count(git_odb_backend *_backend) +int git_mempack_object_count(size_t *out, git_odb_backend *_backend) { struct memory_packer_db *db = (struct memory_packer_db *)_backend; + uint32_t count; + GIT_ASSERT_ARG(_backend); - return git_odb_mempack_oidmap_size(&db->objects); + + count = git_odb_mempack_oidmap_size(&db->objects); + + if (count < 0) + return count; + + *out = (size_t)count; + return 0; } diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c index bb59d38c44b..84449090a06 100644 --- a/tests/libgit2/odb/backend/mempack.c +++ b/tests/libgit2/odb/backend/mempack.c @@ -61,17 +61,22 @@ void test_odb_backend_mempack__blob_create_from_buffer_succeeds(void) void test_odb_backend_mempack__empty_object_count_succeeds(void) { - cl_assert_equal_sz(0, git_mempack_object_count(_backend)); + size_t count; + cl_git_pass(git_mempack_object_count(&count, _backend)); + cl_assert_equal_sz(0, count); } void test_odb_backend_mempack__object_count_succeeds(void) { const char *data = "data"; + size_t count; cl_git_pass(git_odb_write(&_oid, _odb, data, strlen(data) + 1, GIT_OBJECT_BLOB)); - cl_assert_equal_sz(1, git_mempack_object_count(_backend)); + cl_git_pass(git_mempack_object_count(&count, _backend)); + cl_assert_equal_sz(1, count); } void test_odb_backend_mempack__object_count_fails(void) { - cl_git_fail_with(-1, git_mempack_object_count(0)); + size_t count; + cl_git_fail_with(-1, git_mempack_object_count(&count, 0)); } From f54d4601cee1bb8719493ac6eca4ec4916fd4853 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 9 Dec 2024 23:24:32 +0000 Subject: [PATCH 712/816] odb: fix mempack cast --- src/libgit2/odb_mempack.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c index 1b235d20fa2..2f3fba9ad98 100644 --- a/src/libgit2/odb_mempack.c +++ b/src/libgit2/odb_mempack.c @@ -213,15 +213,9 @@ int git_mempack_new(git_odb_backend **out) int git_mempack_object_count(size_t *out, git_odb_backend *_backend) { struct memory_packer_db *db = (struct memory_packer_db *)_backend; - uint32_t count; GIT_ASSERT_ARG(_backend); - count = git_odb_mempack_oidmap_size(&db->objects); - - if (count < 0) - return count; - - *out = (size_t)count; + *out = (size_t)git_odb_mempack_oidmap_size(&db->objects); return 0; } From 455ce4099405e738b97b0d2a5b754b0f3f7851d6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Nov 2024 12:43:16 +0000 Subject: [PATCH 713/816] Make `GIT_WIN32` an internal declaration The `GIT_WIN32` macro should only be used internally; keep it as such. --- include/git2/common.h | 11 +++-------- src/util/git2_util.h | 4 ++++ src/util/util.h | 8 ++++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 56847e68165..dda821c7cba 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -73,11 +73,6 @@ typedef size_t size_t; # define GIT_FORMAT_PRINTF(a,b) /* empty */ #endif -/** Defined when building on Windows (but not via cygwin) */ -#if (defined(_WIN32)) && !defined(__CYGWIN__) -#define GIT_WIN32 1 -#endif - #ifdef __amigaos4__ #include #endif @@ -101,10 +96,10 @@ GIT_BEGIN_DECL * environment variable). A semi-colon ";" is used on Windows and * AmigaOS, and a colon ":" for all other systems. */ -#if defined(GIT_WIN32) || defined(AMIGA) -#define GIT_PATH_LIST_SEPARATOR ';' +#if (defined(_WIN32) && !defined(__CYGWIN__)) || defined(AMIGA) +# define GIT_PATH_LIST_SEPARATOR ';' #else -#define GIT_PATH_LIST_SEPARATOR ':' +# define GIT_PATH_LIST_SEPARATOR ':' #endif /** diff --git a/src/util/git2_util.h b/src/util/git2_util.h index 5bf09819956..d47ce5f43e9 100644 --- a/src/util/git2_util.h +++ b/src/util/git2_util.h @@ -49,6 +49,10 @@ typedef struct git_str git_str; # define GIT_WARN_UNUSED_RESULT #endif +#if (defined(_WIN32)) && !defined(__CYGWIN__) +# define GIT_WIN32 1 +#endif + #include #include #include diff --git a/src/util/util.h b/src/util/util.h index 2ed005110ef..7053a9d494a 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -7,15 +7,15 @@ #ifndef INCLUDE_util_h__ #define INCLUDE_util_h__ -#ifndef GIT_WIN32 -# include -#endif - #include "str.h" #include "git2_util.h" #include "strnlen.h" #include "thread.h" +#ifndef GIT_WIN32 +# include +#endif + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) #define MSB(x, bits) ((x) & (~UINT64_C(0) << (bitsizeof(x) - (bits)))) From 4fef2bd289ad6c6f24127091987f4fd6c5a93bf9 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Tue, 10 Dec 2024 20:44:04 +0000 Subject: [PATCH 714/816] Move abbrev_length from object to repository. --- src/libgit2/diff_print.c | 3 ++- src/libgit2/object.c | 27 +-------------------------- src/libgit2/object.h | 2 -- src/libgit2/repository.c | 25 +++++++++++++++++++++++++ src/libgit2/repository.h | 3 +++ 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/libgit2/diff_print.c b/src/libgit2/diff_print.c index 8e76e85b4f8..0ffba0d55d8 100644 --- a/src/libgit2/diff_print.c +++ b/src/libgit2/diff_print.c @@ -15,6 +15,7 @@ #include "zstream.h" #include "blob.h" #include "delta.h" +#include "repository.h" #include "git2/sys/diff.h" typedef struct { @@ -53,7 +54,7 @@ static int diff_print_info_init__common( if (!pi->id_strlen) { if (!repo) pi->id_strlen = GIT_ABBREV_DEFAULT; - else if (git_object__abbrev_length(&pi->id_strlen, repo) < 0) + else if (git_repository__abbrev_length(&pi->id_strlen, repo) < 0) return -1; } diff --git a/src/libgit2/object.c b/src/libgit2/object.c index 9b885120470..36665c67630 100644 --- a/src/libgit2/object.c +++ b/src/libgit2/object.c @@ -520,31 +520,6 @@ int git_object_lookup_bypath( return error; } -int git_object__abbrev_length(int *out, git_repository *repo) -{ - size_t oid_hexsize; - int len; - int error; - - oid_hexsize = git_oid_hexsize(repo->oid_type); - - if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0) - return error; - - if (len == GIT_ABBREV_FALSE) { - len = (int)oid_hexsize; - } - - if (len < GIT_ABBREV_MINIMUM || (size_t)len > oid_hexsize) { - git_error_set(GIT_ERROR_CONFIG, "invalid oid abbreviation setting: '%d'", len); - return -1; - } - - *out = len; - - return error; -} - static int git_object__short_id(git_str *out, const git_object *obj) { git_repository *repo; @@ -561,7 +536,7 @@ static int git_object__short_id(git_str *out, const git_object *obj) git_oid_clear(&id, repo->oid_type); oid_hexsize = git_oid_hexsize(repo->oid_type); - if ((error = git_object__abbrev_length(&len, repo)) < 0) + if ((error = git_repository__abbrev_length(&len, repo)) < 0) return error; if ((size_t)len == oid_hexsize) { diff --git a/src/libgit2/object.h b/src/libgit2/object.h index b21165f70aa..b6c604c8178 100644 --- a/src/libgit2/object.h +++ b/src/libgit2/object.h @@ -83,6 +83,4 @@ GIT_INLINE(git_object_t) git_object__type_from_filemode(git_filemode_t mode) } } -int git_object__abbrev_length(int *out, git_repository *repo); - #endif diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 0cc47452b88..ca6c2bb10d9 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -4009,3 +4009,28 @@ int git_repository_commit_parents(git_commitarray *out, git_repository *repo) git_reference_free(head_ref); return error; } + +int git_repository__abbrev_length(int *out, git_repository *repo) +{ + size_t oid_hexsize; + int len; + int error; + + oid_hexsize = git_oid_hexsize(repo->oid_type); + + if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0) + return error; + + if (len == GIT_ABBREV_FALSE) { + len = (int)oid_hexsize; + } + + if (len < GIT_ABBREV_MINIMUM || (size_t)len > oid_hexsize) { + git_error_set(GIT_ERROR_CONFIG, "invalid oid abbreviation setting: '%d'", len); + return -1; + } + + *out = len; + + return error; +} diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index 4e820c9b866..fcd6aa2d8bd 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -213,6 +213,9 @@ int git_repository__wrap_odb( int git_repository__configmap_lookup(int *out, git_repository *repo, git_configmap_item item); void git_repository__configmap_lookup_cache_clear(git_repository *repo); +/** Return the length that object names will be abbreviated to. */ +int git_repository__abbrev_length(int *out, git_repository *repo); + int git_repository__item_path(git_str *out, const git_repository *repo, git_repository_item_t item); GIT_INLINE(int) git_repository__ensure_not_bare( From 0f1cb81a0c277e76389509d3bb7a83fca8858f4d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 10 Dec 2024 23:22:35 +0000 Subject: [PATCH 715/816] Documentation: clean up old documentation Clean up the outdated documentation folder before re-generating it in place. This accomodates a deleted API. --- script/api-docs/docs-generator.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/script/api-docs/docs-generator.js b/script/api-docs/docs-generator.js index 2670b8a3a7b..dcf25e57311 100755 --- a/script/api-docs/docs-generator.js +++ b/script/api-docs/docs-generator.js @@ -1084,6 +1084,19 @@ async function produceDocumentationMetadata(version, apiData) { await fs.writeFile(filename, JSON.stringify(apiData.info, null, 2) + "\n"); } +async function cleanupOldDocumentation(version) { + const versionDir = `${outputPath}/${version}`; + + for (const fn of await fs.readdir(versionDir)) { + if (fn === '.metadata') { + continue; + } + + const path = `${versionDir}/${fn}`; + await fs.rm(path, { recursive: true }); + } +} + async function produceDocumentationForVersion(version, apiData) { if (!options.force && await documentationIsUpToDateForVersion(version, apiData)) { if (options.verbose) { @@ -1097,6 +1110,8 @@ async function produceDocumentationForVersion(version, apiData) { console.log(`Producing documentation for ${version}...`); } + await cleanupOldDocumentation(version); + await produceDocumentationForApis(version, apiData); for (const group in apiData['groups']) { From 03e0bf3ba214bbe4b8394cb867209da271a2c972 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 10 Dec 2024 23:41:15 +0000 Subject: [PATCH 716/816] Documentation generation: verbose generation --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 5eab5b6ced9..da3effd8e24 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -54,7 +54,7 @@ jobs: fi npm install - ./generate $args ../.. ../../../www/docs + ./generate --verbose $args ../.. ../../../www/docs working-directory: source/script/api-docs - name: Examine changes run: | From 7668c13552cc1090608726bb871f57ac4f7eab83 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 11 Dec 2024 00:38:17 +0000 Subject: [PATCH 717/816] refs: remove obsolete validity test with carat prefix Refs can now be prefixed with a ^ (indicating a negative ref). Remove a now-obsolete validity test. --- tests/libgit2/refs/normalize.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/libgit2/refs/normalize.c b/tests/libgit2/refs/normalize.c index ca38007b405..f1850759d9d 100644 --- a/tests/libgit2/refs/normalize.c +++ b/tests/libgit2/refs/normalize.c @@ -229,8 +229,6 @@ void test_refs_normalize__jgit_suite(void) GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master^"); ensure_refname_invalid( GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/^master"); - ensure_refname_invalid( - GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "^refs/heads/master"); ensure_refname_invalid( GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL, "refs/heads/master~"); From f675ea3cd73eab025a8392bb8ec6b3a5d7a1cc5f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 11 Dec 2024 10:54:21 +0000 Subject: [PATCH 718/816] docs: remind people about `git_libgit2_init` Currently `git_libgit2_init` must be called before you can work with the library. Remind people about this as they read the documentation. --- include/git2/clone.h | 4 ++++ include/git2/repository.h | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/git2/clone.h b/include/git2/clone.h index 0d06a41df1f..b7a47ab484b 100644 --- a/include/git2/clone.h +++ b/include/git2/clone.h @@ -200,6 +200,10 @@ GIT_EXTERN(int) git_clone_options_init( * git's defaults. You can use the options in the callback to * customize how these are created. * + * Note that the libgit2 library _must_ be initialized using + * `git_libgit2_init` before any APIs can be called, including + * this one. + * * @param[out] out pointer that will receive the resulting repository object * @param url the remote repository to clone * @param local_path local directory to clone to diff --git a/include/git2/repository.h b/include/git2/repository.h index a10ea3fcb3e..59c4d0f30d6 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -31,6 +31,10 @@ GIT_BEGIN_DECL * The method will automatically detect if 'path' is a normal * or bare repository or fail is 'path' is neither. * + * Note that the libgit2 library _must_ be initialized using + * `git_libgit2_init` before any APIs can be called, including + * this one. + * * @param[out] out pointer to the repo which will be opened * @param path the path to the repository * @return 0 or an error code @@ -84,6 +88,10 @@ GIT_EXTERN(int) git_repository_wrap_odb( * The method will automatically detect if the repository is bare * (if there is a repository). * + * Note that the libgit2 library _must_ be initialized using + * `git_libgit2_init` before any APIs can be called, including + * this one. + * * @param out A pointer to a user-allocated git_buf which will contain * the found path. * @@ -161,6 +169,10 @@ typedef enum { /** * Find and open a repository with extended controls. * + * Note that the libgit2 library _must_ be initialized using + * `git_libgit2_init` before any APIs can be called, including + * this one. + * * @param[out] out Pointer to the repo which will be opened. This can * actually be NULL if you only want to use the error code to * see if a repo at this path could be opened. @@ -189,6 +201,10 @@ GIT_EXTERN(int) git_repository_open_ext( * if you're e.g. hosting git repositories and need to access them * efficiently * + * Note that the libgit2 library _must_ be initialized using + * `git_libgit2_init` before any APIs can be called, including + * this one. + * * @param[out] out Pointer to the repo which will be opened. * @param bare_path Direct path to the bare repository * @return 0 on success, or an error code @@ -214,6 +230,10 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo); * TODO: * - Reinit the repository * + * Note that the libgit2 library _must_ be initialized using + * `git_libgit2_init` before any APIs can be called, including + * this one. + * * @param[out] out pointer to the repo which will be created or reinitialized * @param path the path to the repository * @param is_bare if true, a Git repository without a working directory is @@ -404,6 +424,10 @@ GIT_EXTERN(int) git_repository_init_options_init( * auto-detect the case sensitivity of the file system and if the * file system supports file mode bits correctly. * + * Note that the libgit2 library _must_ be initialized using + * `git_libgit2_init` before any APIs can be called, including + * this one. + * * @param out Pointer to the repo which will be created or reinitialized. * @param repo_path The path to the repository. * @param opts Pointer to git_repository_init_options struct. From 48820e6c74eeb8a6cb6ed5de655b63bac1ca4a9c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 11 Dec 2024 10:57:26 +0000 Subject: [PATCH 719/816] pathspec: additional pathspec wildcard tests We did not have (obvious) pathspec wildcard tests for `**/foo` behavior. Add some based on git's observed behavior. --- tests/libgit2/repo/pathspec.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/libgit2/repo/pathspec.c b/tests/libgit2/repo/pathspec.c index 5b86662bcfb..0efc2a372f0 100644 --- a/tests/libgit2/repo/pathspec.c +++ b/tests/libgit2/repo/pathspec.c @@ -383,3 +383,33 @@ void test_repo_pathspec__in_memory(void) git_pathspec_free(ps); } + +void test_repo_pathspec__starstar(void) +{ + static char *strings[] = { "**/foo", "**/bar/baz" }; + git_strarray s = { strings, ARRAY_SIZE(strings) }; + git_pathspec *ps; + + cl_git_pass(git_pathspec_new(&ps, &s)); + + /* "**" "/foo" does *not* match top-level "foo" */ + cl_assert(!git_pathspec_matches_path(ps, 0, "foo")); + cl_assert(!git_pathspec_matches_path(ps, 0, "fooz")); + cl_assert(!git_pathspec_matches_path(ps, 0, "bar")); + + cl_assert(git_pathspec_matches_path(ps, 0, "asdf/foo")); + cl_assert(!git_pathspec_matches_path(ps, 0, "asdf/fooz")); + cl_assert(git_pathspec_matches_path(ps, 0, "a/b/c/foo")); + cl_assert(!git_pathspec_matches_path(ps, 0, "a/b/c/fooz")); + + cl_assert(git_pathspec_matches_path(ps, 0, "bar/foo")); + cl_assert(!git_pathspec_matches_path(ps, 0, "bar/baz")); + cl_assert(!git_pathspec_matches_path(ps, 0, "bar/foo/baz")); + + cl_assert(!git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "asdf/foo")); + cl_assert(!git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "a/b/c/foo")); + cl_assert(!git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "bar/foo")); + cl_assert(!git_pathspec_matches_path(ps, GIT_PATHSPEC_NO_GLOB, "bar/baz")); + + git_pathspec_free(ps); +} From d363cc8fee9c31b56d115f6c8b497e3a1fd24523 Mon Sep 17 00:00:00 2001 From: lmcglash Date: Wed, 11 Dec 2024 19:55:54 +0000 Subject: [PATCH 720/816] Apply PR feedback. --- src/libgit2/config_cache.c | 2 +- src/libgit2/repository.c | 9 ++++----- src/libgit2/repository.h | 2 +- tests/libgit2/object/shortid.c | 14 ++++++++++++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libgit2/config_cache.c b/src/libgit2/config_cache.c index 0b574c20c4e..05d9d5828e0 100644 --- a/src/libgit2/config_cache.c +++ b/src/libgit2/config_cache.c @@ -65,8 +65,8 @@ static git_configmap _configmap_logallrefupdates[] = { }; static git_configmap _configmap_abbrev[] = { - {GIT_CONFIGMAP_FALSE, NULL, GIT_ABBREV_FALSE}, {GIT_CONFIGMAP_INT32, NULL, 0}, + {GIT_CONFIGMAP_FALSE, NULL, GIT_ABBREV_FALSE}, {GIT_CONFIGMAP_STRING, "auto", GIT_ABBREV_DEFAULT} }; diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index ca6c2bb10d9..d41fa3933ad 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -4021,15 +4021,14 @@ int git_repository__abbrev_length(int *out, git_repository *repo) if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0) return error; - if (len == GIT_ABBREV_FALSE) { - len = (int)oid_hexsize; - } - - if (len < GIT_ABBREV_MINIMUM || (size_t)len > oid_hexsize) { + if (len < GIT_ABBREV_MINIMUM) { git_error_set(GIT_ERROR_CONFIG, "invalid oid abbreviation setting: '%d'", len); return -1; } + if (len == GIT_ABBREV_FALSE || (size_t)len > oid_hexsize) + len = (int)oid_hexsize; + *out = len; return error; diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index fcd6aa2d8bd..79e087bfa93 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -102,7 +102,7 @@ typedef enum { /* core.trustctime */ GIT_TRUSTCTIME_DEFAULT = GIT_CONFIGMAP_TRUE, /* core.abbrev */ - GIT_ABBREV_FALSE = GIT_CONFIGMAP_FALSE, + GIT_ABBREV_FALSE = GIT_OID_MAX_HEXSIZE, GIT_ABBREV_MINIMUM = 4, GIT_ABBREV_DEFAULT = 7, /* core.precomposeunicode */ diff --git a/tests/libgit2/object/shortid.c b/tests/libgit2/object/shortid.c index 81e7b2f35f9..3657a419884 100644 --- a/tests/libgit2/object/shortid.c +++ b/tests/libgit2/object/shortid.c @@ -70,14 +70,24 @@ void test_object_shortid__core_abbrev(void) cl_assert_equal_i(40, shorty.size); cl_assert_equal_s("ce013625030ba8dba906f756967f9e9ca394464a", shorty.ptr); + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "false")); + cl_git_pass(git_object_short_id(&shorty, obj)); + cl_assert_equal_i(40, shorty.size); + cl_assert_equal_s("ce013625030ba8dba906f756967f9e9ca394464a", shorty.ptr); + + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "99")); + cl_git_pass(git_object_short_id(&shorty, obj)); + cl_assert_equal_i(40, shorty.size); + cl_assert_equal_s("ce013625030ba8dba906f756967f9e9ca394464a", shorty.ptr); + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "4")); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(4, shorty.size); cl_assert_equal_s("ce01", shorty.ptr); - cl_git_pass(git_config_set_string(cfg, "core.abbrev", "3")); + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "0")); cl_git_fail(git_object_short_id(&shorty, obj)); - cl_git_pass(git_config_set_string(cfg, "core.abbrev", "41")); + cl_git_pass(git_config_set_string(cfg, "core.abbrev", "3")); cl_git_fail(git_object_short_id(&shorty, obj)); cl_git_pass(git_config_set_string(cfg, "core.abbrev", "invalid")); cl_git_fail(git_object_short_id(&shorty, obj)); From bef4b73871d4d1e5f08152c1e0835f209bd397a3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 13 Dec 2024 23:13:52 +0000 Subject: [PATCH 721/816] transport: only clear data when not in rpc mode In RPC mode (https), we need to resend the data so that the remote endpoint keeps context. In non-RPC mode, we need not (and should not) resend it. Clear that buffer data in non-RPC mode to prevent this. --- src/libgit2/transports/smart_protocol.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 0522f751784..b35b33b4347 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -433,7 +433,9 @@ int git_smart__negotiate_fetch( if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; - git_str_clear(&data); + + if (!t->rpc) + git_str_clear(&data); while ((error = recv_pkt((git_pkt **)&pkt, NULL, t)) == 0) { bool complete = false; From 833224964aa66a7e086e07c9f7bb55a934b96869 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Mar 2024 15:42:57 +0000 Subject: [PATCH 722/816] security: require TLSv1.2 or higher --- src/libgit2/streams/mbedtls.c | 6 ++---- src/libgit2/streams/openssl.c | 13 ++++++++----- src/libgit2/streams/stransport.c | 3 +-- tests/libgit2/online/badssl.c | 8 ++++++++ 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index 1b2780706c6..11629a43562 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -94,10 +94,8 @@ int git_mbedtls_stream_global_init(void) goto cleanup; } - /* configure TLSv1.1 */ -#ifdef MBEDTLS_SSL_MINOR_VERSION_2 - mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); -#endif + /* configure TLSv1.2 */ + mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); /* verify_server_cert is responsible for making the check. * OPTIONAL because REQUIRED drops the certificate as soon as the check diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index f531d1bc8f1..cfeafeaaa6d 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -106,7 +106,10 @@ static void git_openssl_free(void *mem) static int openssl_init(void) { - long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + long ssl_opts = SSL_OP_NO_SSLv2 | + SSL_OP_NO_SSLv3 | + SSL_OP_NO_TLSv1 | + SSL_OP_NO_TLSv1_1; const char *ciphers = git__ssl_ciphers; #ifdef VALGRIND static bool allocators_initialized = false; @@ -135,10 +138,10 @@ static int openssl_init(void) OPENSSL_init_ssl(0, NULL); /* - * Load SSLv{2,3} and TLSv1 so that we can talk with servers - * which use the SSL hellos, which are often used for - * compatibility. We then disable SSL so we only allow OpenSSL - * to speak TLSv1 to perform the encryption itself. + * Despite the name SSLv23_method, this is actually a version- + * flexible context, which honors the protocol versions + * specified in `ssl_opts`. So we only support TLSv1.2 and + * higher. */ if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method()))) goto error; diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 863616dcc77..2d4cc55b549 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -331,8 +331,7 @@ static int stransport_wrap( if ((ret = SSLSetIOFuncs(st->ctx, read_cb, write_cb)) != noErr || (ret = SSLSetConnection(st->ctx, st)) != noErr || (ret = SSLSetSessionOption(st->ctx, kSSLSessionOptionBreakOnServerAuth, true)) != noErr || - (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr || - (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr || + (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol12)) != noErr || (ret = SSLSetPeerDomainName(st->ctx, host, strlen(host))) != noErr) { CFRelease(st->ctx); git__free(st); diff --git a/tests/libgit2/online/badssl.c b/tests/libgit2/online/badssl.c index 6735e9cdb31..7169d59f2e6 100644 --- a/tests/libgit2/online/badssl.c +++ b/tests/libgit2/online/badssl.c @@ -73,3 +73,11 @@ void test_online_badssl__old_cipher(void) cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL)); cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", &opts)); } + +void test_online_badssl__sslv3(void) +{ + if (!g_has_ssl) + cl_skip(); + + cl_git_fail(git_clone(&g_repo, "https://mailserv.baehal.com/fake.git", "./fake", NULL)); +} From e014b10e78b37bc297ecfe8ef95931e1ae7c37ea Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 10:07:10 +0000 Subject: [PATCH 723/816] security: improve the default TLS ciphers Update our default cipher list to the most recent "intermediate" configuration from Mozilla's SSL cipher list, which is "recommended cnofiguration for a general-purpose server". https://wiki.mozilla.org/Security/Server_Side_TLS This removes many outdated ciphers that are no longer practically supported by servers, including GitHub, GitLab, and Bitbucket. --- src/libgit2/streams/mbedtls.c | 4 ++-- src/libgit2/streams/openssl.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index 11629a43562..1493f119c96 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -39,8 +39,8 @@ #undef inline -#define GIT_SSL_DEFAULT_CIPHERS "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-DSS-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-DSS-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-DSS-WITH-AES-128-CBC-SHA256:TLS-DHE-DSS-WITH-AES-256-CBC-SHA256:TLS-DHE-DSS-WITH-AES-128-CBC-SHA:TLS-DHE-DSS-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-AES-128-GCM-SHA256:TLS-RSA-WITH-AES-256-GCM-SHA384:TLS-RSA-WITH-AES-128-CBC-SHA256:TLS-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA" -#define GIT_SSL_DEFAULT_CIPHERS_COUNT 30 +#define GIT_SSL_DEFAULT_CIPHERS "TLS1-3-AES-128-GCM-SHA256:TLS1-3-AES-256-GCM-SHA384:TLS1-3-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256" +#define GIT_SSL_DEFAULT_CIPHERS_COUNT 12 static int ciphers_list[GIT_SSL_DEFAULT_CIPHERS_COUNT]; diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index cfeafeaaa6d..ca64e460b75 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -40,7 +40,7 @@ extern char *git__ssl_ciphers; SSL_CTX *git__ssl_ctx; -#define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" +#define GIT_SSL_DEFAULT_CIPHERS "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305" static BIO_METHOD *git_stream_bio_method; From ab0e1606b449d1e521a703fb57f7484aeea60182 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 10:42:44 +0000 Subject: [PATCH 724/816] docs: include v1.8.4 changelog --- docs/changelog.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index fe12271f3ed..02bad65e17c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,31 @@ +v1.8.4 +------ + +We erroneously shipped v1.8.3 without actually including the change +in v1.8.2. This release re-re-introduces the pre-v1.8.0 `commit` +constness behavior. + +## What's Changed + +### Bug fixes + +* Fix constness issue introduced in #6716 by @ethomson in https://github.com/libgit2/libgit2/pull/6829 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.8.3...v1.8.4 + +v1.8.3 +------ + +This release fixes a bug introduced in v1.8.1 for users of the legacy +[Node.js http-parser](https://github.com/nodejs/http-parser) +dependency. + +## What's Changed + +### Bug fixes + +* http: Backport on_status initialize fix for http-parser by @ethomson in https://github.com/libgit2/libgit2/pull/6931 + v1.8.2 ------ From 5576e8f6a92893b594b9d8f11b698f1a6d5f566c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 10:55:49 +0000 Subject: [PATCH 725/816] docs: add "benchmarks" section to changelog --- .github/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/release.yml b/.github/release.yml index 4d4e31860c2..ac05fc6de70 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -15,6 +15,9 @@ changelog: - title: Code cleanups labels: - cleanup + - title: Benchmarks + labels: + - benchmarks - title: Build and CI improvements labels: - build From 009677e611ee534c8765b320bb169953a2bfbac1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 16:47:47 +0000 Subject: [PATCH 726/816] oid: provide private type_is_valid functionality As users begin to specify the object ID types, provide an internal mechanism to determine whether the type is valid / supported or not. --- src/libgit2/oid.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h index f25a899a681..9415915fcb2 100644 --- a/src/libgit2/oid.h +++ b/src/libgit2/oid.h @@ -66,6 +66,15 @@ GIT_INLINE(size_t) git_oid_hexsize(git_oid_t type) return 0; } +GIT_INLINE(bool) git_oid_type_is_valid(git_oid_t type) +{ + return (type == GIT_OID_SHA1 +#ifdef GIT_EXPERIMENTAL_SHA256 + || type == GIT_OID_SHA256 +#endif + ); +} + GIT_INLINE(const char *) git_oid_type_name(git_oid_t type) { switch (type) { From 3d9f4061ca56a3f2c4055904d924974031f59923 Mon Sep 17 00:00:00 2001 From: Ryan Pham Date: Thu, 28 Nov 2024 13:35:11 +0900 Subject: [PATCH 727/816] refspec: Add func to distinguish negative refspecs Negative refspecs were added in Git v2.29.0 and are denoted by prefixing a refspec with a caret. This adds a way to distinguish if a refspec is negative and match negative refspecs. --- include/git2/refspec.h | 9 +++++++++ src/libgit2/refspec.c | 16 ++++++++++++++++ src/libgit2/refspec.h | 8 ++++++++ 3 files changed, 33 insertions(+) diff --git a/include/git2/refspec.h b/include/git2/refspec.h index 16ebd1ddfa8..49d5f89f7e6 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -78,6 +78,15 @@ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); */ GIT_EXTERN(git_direction) git_refspec_direction(const git_refspec *spec); +/** + * Check if a refspec's source descriptor matches a negative reference + * + * @param refspec the refspec + * @param refname the name of the reference to check + * @return 1 if the refspec matches, 0 otherwise + */ +GIT_EXTERN(int) git_refspec_src_matches_negative(const git_refspec *refspec, const char *refname); + /** * Check if a refspec's source descriptor matches a reference * diff --git a/src/libgit2/refspec.c b/src/libgit2/refspec.c index f0a0c2bfb3e..18ece6b7076 100644 --- a/src/libgit2/refspec.c +++ b/src/libgit2/refspec.c @@ -225,6 +225,14 @@ int git_refspec_force(const git_refspec *refspec) return refspec->force; } +int git_refspec_src_matches_negative(const git_refspec *refspec, const char *refname) +{ + if (refspec == NULL || refspec->src == NULL || !git_refspec_is_negative(refspec)) + return false; + + return (wildmatch(refspec->src + 1, refname, 0) == 0); +} + int git_refspec_src_matches(const git_refspec *refspec, const char *refname) { if (refspec == NULL || refspec->src == NULL) @@ -340,6 +348,14 @@ int git_refspec_is_wildcard(const git_refspec *spec) return (spec->src[strlen(spec->src) - 1] == '*'); } +int git_refspec_is_negative(const git_refspec *spec) +{ + GIT_ASSERT_ARG(spec); + GIT_ASSERT_ARG(spec->src); + + return (spec->src[0] == '^' && spec->dst == NULL); +} + git_direction git_refspec_direction(const git_refspec *spec) { GIT_ASSERT_ARG(spec); diff --git a/src/libgit2/refspec.h b/src/libgit2/refspec.h index bf4f7fcfbbc..37612216c04 100644 --- a/src/libgit2/refspec.h +++ b/src/libgit2/refspec.h @@ -45,6 +45,14 @@ int git_refspec__serialize(git_str *out, const git_refspec *refspec); */ int git_refspec_is_wildcard(const git_refspec *spec); +/** + * Determines if a refspec is a negative refspec. + * + * @param spec the refspec + * @return 1 if the refspec is a negative, 0 otherwise + */ +int git_refspec_is_negative(const git_refspec *spec); + /** * DWIM `spec` with `refs` existing on the remote, append the dwim'ed * result in `out`. From f7f30ec136907a2aad5e58ba95081ac94fe6aba6 Mon Sep 17 00:00:00 2001 From: Ryan Pham Date: Thu, 28 Nov 2024 15:25:44 +0900 Subject: [PATCH 728/816] remote: Handle fetching negative refspecs Add support for fetching with negative refspecs. Fetching from the remote with a negative refspec will now validate any references fetched do not match _any_ negative refspecs and at least one non-negative refspec. As we must ensure that fetched references do not match any of the negative refspecs provided, we cannot short-circuit when checking for matching refspecs. --- src/libgit2/refspec.c | 13 ++++++- src/libgit2/remote.c | 8 +++-- tests/libgit2/refs/normalize.c | 2 ++ tests/libgit2/remote/fetch.c | 64 ++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/libgit2/refspec.c b/src/libgit2/refspec.c index 18ece6b7076..7ce8ef4ba71 100644 --- a/src/libgit2/refspec.c +++ b/src/libgit2/refspec.c @@ -22,6 +22,7 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) const char *lhs, *rhs; int valid = 0; unsigned int flags; + bool is_neg_refspec = false; GIT_ASSERT_ARG(refspec); GIT_ASSERT_ARG(input); @@ -34,6 +35,9 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) refspec->force = 1; lhs++; } + if (*lhs == '^') { + is_neg_refspec = true; + } rhs = strrchr(lhs, ':'); @@ -62,7 +66,14 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) llen = (rhs ? (size_t)(rhs - lhs - 1) : strlen(lhs)); if (1 <= llen && memchr(lhs, '*', llen)) { - if ((rhs && !is_glob) || (!rhs && is_fetch)) + /* + * If the lefthand side contains a glob, then one of the following must be + * true, otherwise the spec is invalid + * 1) the rhs exists and also contains a glob + * 2) it is a negative refspec (i.e. no rhs) + * 3) the rhs doesn't exist and we're fetching + */ + if ((rhs && !is_glob) || (rhs && is_neg_refspec) || (!rhs && is_fetch && !is_neg_refspec)) goto invalid; is_glob = 1; } else if (rhs && is_glob) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 5e59ce894c2..5d87d420785 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2628,17 +2628,21 @@ int git_remote_name_is_valid(int *valid, const char *remote_name) git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname) { git_refspec *spec; + git_refspec *match = NULL; size_t i; git_vector_foreach(&remote->active_refspecs, i, spec) { if (spec->push) continue; + if (git_refspec_is_negative(spec) && git_refspec_src_matches_negative(spec, refname)) + return NULL; + if (git_refspec_src_matches(spec, refname)) - return spec; + match = spec; } - return NULL; + return match; } git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname) diff --git a/tests/libgit2/refs/normalize.c b/tests/libgit2/refs/normalize.c index f1850759d9d..c2f5684ef17 100644 --- a/tests/libgit2/refs/normalize.c +++ b/tests/libgit2/refs/normalize.c @@ -402,6 +402,8 @@ void test_refs_normalize__negative_refspec_pattern(void) { ensure_refname_normalized( GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "^foo/bar", "^foo/bar"); + ensure_refname_normalized( + GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "^foo/bar/*", "^foo/bar/*"); ensure_refname_invalid( GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo/^bar"); } diff --git a/tests/libgit2/remote/fetch.c b/tests/libgit2/remote/fetch.c index 7d2d11e2702..a24f09925ac 100644 --- a/tests/libgit2/remote/fetch.c +++ b/tests/libgit2/remote/fetch.c @@ -10,8 +10,11 @@ static char* repo2_path; static const char *REPO1_REFNAME = "refs/heads/main"; static const char *REPO2_REFNAME = "refs/remotes/repo1/main"; +static const char *REPO1_UNDERSCORE_REFNAME = "refs/heads/_branch"; +static const char *REPO2_UNDERSCORE_REFNAME = "refs/remotes/repo1/_branch"; static char *FORCE_FETCHSPEC = "+refs/heads/main:refs/remotes/repo1/main"; static char *NON_FORCE_FETCHSPEC = "refs/heads/main:refs/remotes/repo1/main"; +static char *NEGATIVE_SPEC = "^refs/heads/_*"; void test_remote_fetch__initialize(void) { git_config *c; @@ -170,3 +173,64 @@ void test_remote_fetch__do_update_refs_if_not_descendant_and_force(void) { git_reference_free(ref); } + +/** + * This checks that negative refspecs are respected when fetching. We create a + * repository with a '_' prefixed reference. A second repository is configured + * with a negative refspec to ignore any refs prefixed with '_' and fetch the + * first repository into the second. + * + * @param commit1id A pointer to an OID which will be populated with the first + * commit. + */ +static void do_fetch_repo_with_ref_matching_negative_refspec(git_oid *commit1id) { + /* create a commit in repo 1 and a reference to it with '_' prefix */ + { + git_oid empty_tree_id; + git_tree *empty_tree; + git_signature *sig; + git_treebuilder *tb; + cl_git_pass(git_treebuilder_new(&tb, repo1, NULL)); + cl_git_pass(git_treebuilder_write(&empty_tree_id, tb)); + cl_git_pass(git_tree_lookup(&empty_tree, repo1, &empty_tree_id)); + cl_git_pass(git_signature_default(&sig, repo1)); + cl_git_pass(git_commit_create(commit1id, repo1, REPO1_UNDERSCORE_REFNAME, sig, + sig, NULL, "one", empty_tree, 0, NULL)); + + git_tree_free(empty_tree); + git_signature_free(sig); + git_treebuilder_free(tb); + } + + /* fetch the remote with negative refspec for references prefixed with '_' */ + { + char *refspec_strs = { NEGATIVE_SPEC }; + git_strarray refspecs = { + .count = 1, + .strings = &refspec_strs, + }; + + git_remote *remote; + + cl_git_pass(git_remote_create_anonymous(&remote, repo2, + git_repository_path(repo1))); + cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, "some message")); + + git_remote_free(remote); + } +} + +void test_remote_fetch__skip_negative_refspec_match(void) { + git_oid commit1id; + git_reference *ref1; + git_reference *ref2; + + do_fetch_repo_with_ref_matching_negative_refspec(&commit1id); + + /* assert that the reference in exists in repo1 but not in repo2 */ + cl_git_pass(git_reference_lookup(&ref1, repo1, REPO1_UNDERSCORE_REFNAME)); + cl_assert_equal_b(git_reference_lookup(&ref2, repo2, REPO2_UNDERSCORE_REFNAME), GIT_ENOTFOUND); + + git_reference_free(ref1); + git_reference_free(ref2); +} From 708d64f1e8eaa1ded7ba0915e154fe15defe5d7a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 16:48:22 +0000 Subject: [PATCH 729/816] index: provide a index_options structure when opening Instead of simply taking the oid type, future-proof our index opening and creation functionality by taking an options structure. --- examples/show-index.c | 2 +- include/git2/index.h | 52 +++++++++++++++++++++++++++++++++++++++---- src/libgit2/index.c | 14 ++++++++---- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/examples/show-index.c b/examples/show-index.c index 0a5e7d1a2e4..ac0040874ec 100644 --- a/examples/show-index.c +++ b/examples/show-index.c @@ -31,7 +31,7 @@ int lg2_show_index(git_repository *repo, int argc, char **argv) dirlen = strlen(dir); if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) { #ifdef GIT_EXPERIMENTAL_SHA256 - check_lg2(git_index_open(&index, dir, GIT_OID_SHA1), "could not open index", dir); + check_lg2(git_index_open(&index, dir, NULL), "could not open index", dir); #else check_lg2(git_index_open(&index, dir), "could not open index", dir); #endif diff --git a/include/git2/index.h b/include/git2/index.h index 9f3efe1fc7e..0adff1abd95 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -191,25 +191,69 @@ typedef enum { #ifdef GIT_EXPERIMENTAL_SHA256 +/** + * The options for opening or creating an index. + * + * Initialize with `GIT_INDEX_OPTIONS_INIT`. Alternatively, you can + * use `git_index_options_init`. + * + * @options[version] GIT_INDEX_OPTIONS_VERSION + * @options[init_macro] GIT_INDEX_OPTIONS_INIT + * @options[init_function] git_index_options_init + */ +typedef struct git_index_options { + unsigned int version; /**< The version */ + + /** + * The object ID type for the object IDs that exist in the index. + * + * If this is not specified, this defaults to `GIT_OID_SHA1`. + */ + git_oid_t oid_type; +} git_index_options; + +/** Current version for the `git_index_options` structure */ +#define GIT_INDEX_OPTIONS_VERSION 1 + +/** Static constructor for `git_index_options` */ +#define GIT_INDEX_OPTIONS_INIT { GIT_INDEX_OPTIONS_VERSION } + +/** + * Initialize git_index_options structure + * + * Initializes a `git_index_options` with default values. Equivalent to creating + * an instance with GIT_INDEX_OPTIONS_INIT. + * + * @param opts The `git_index_options` struct to initialize. + * @param version The struct version; pass `GIT_INDEX_OPTIONS_VERSION`. + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_index_options_init( + git_index_options *opts, + unsigned int version); + /** * Creates a new bare Git index object, without a repository to back * it. This index object is capable of storing SHA256 objects. * * @param index_out the pointer for the new index * @param index_path the path to the index file in disk - * @param oid_type the object ID type to use for the repository + * @param opts the options for opening the index, or NULL * @return 0 or an error code */ -GIT_EXTERN(int) git_index_open(git_index **index_out, const char *index_path, git_oid_t oid_type); +GIT_EXTERN(int) git_index_open( + git_index **index_out, + const char *index_path, + const git_index_options *opts); /** * Create an in-memory index object. * * @param index_out the pointer for the new index - * @param oid_type the object ID type to use for the repository + * @param opts the options for opening the index, or NULL * @return 0 or an error code */ -GIT_EXTERN(int) git_index_new(git_index **index_out, git_oid_t oid_type); +GIT_EXTERN(int) git_index_new(git_index **index_out, const git_index_options *opts); #else diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 29d10ef7213..a3142c8bcd9 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -399,6 +399,7 @@ int git_index__open( index = git__calloc(1, sizeof(git_index)); GIT_ERROR_CHECK_ALLOC(index); + GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); index->oid_type = oid_type; if (git_pool_init(&index->tree_pool, 1) < 0) @@ -441,9 +442,13 @@ int git_index__open( } #ifdef GIT_EXPERIMENTAL_SHA256 -int git_index_open(git_index **index_out, const char *index_path, git_oid_t oid_type) +int git_index_open( + git_index **index_out, + const char *index_path, + const git_index_options *opts) { - return git_index__open(index_out, index_path, oid_type); + return git_index__open(index_out, index_path, + opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT); } #else int git_index_open(git_index **index_out, const char *index_path) @@ -458,9 +463,10 @@ int git_index__new(git_index **out, git_oid_t oid_type) } #ifdef GIT_EXPERIMENTAL_SHA256 -int git_index_new(git_index **out, git_oid_t oid_type) +int git_index_new(git_index **out, const git_index_options *opts) { - return git_index__new(out, oid_type); + return git_index__new(out, + opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT); } #else int git_index_new(git_index **out) From 9aa5faa38b1be87c8d59d661581271276c05171b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 16:58:50 +0000 Subject: [PATCH 730/816] indexer: move oid_type into the opts structure Object ID type should be an option within the options structure; move it there. --- examples/index-pack.c | 2 +- fuzzers/packfile_fuzzer.c | 2 +- include/git2/indexer.h | 6 ++++-- src/cli/cmd_index_pack.c | 4 +++- src/libgit2/indexer.c | 8 +++++--- src/libgit2/odb_pack.c | 2 +- src/libgit2/pack-objects.c | 3 ++- tests/libgit2/pack/indexer.c | 19 ++++++++++--------- tests/libgit2/pack/packbuilder.c | 6 +++--- 9 files changed, 30 insertions(+), 22 deletions(-) diff --git a/examples/index-pack.c b/examples/index-pack.c index 0f8234c7591..e9f32b8b291 100644 --- a/examples/index-pack.c +++ b/examples/index-pack.c @@ -29,7 +29,7 @@ int lg2_index_pack(git_repository *repo, int argc, char **argv) } #ifdef GIT_EXPERIMENTAL_SHA256 - error = git_indexer_new(&idx, ".", git_repository_oid_type(repo), NULL); + error = git_indexer_new(&idx, ".", NULL); #else error = git_indexer_new(&idx, ".", 0, NULL, NULL); #endif diff --git a/fuzzers/packfile_fuzzer.c b/fuzzers/packfile_fuzzer.c index aeba9575c3e..bcbdd8bc40b 100644 --- a/fuzzers/packfile_fuzzer.c +++ b/fuzzers/packfile_fuzzer.c @@ -84,7 +84,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) } #ifdef GIT_EXPERIMENTAL_SHA256 - error = git_indexer_new(&indexer, ".", GIT_OID_SHA1, NULL); + error = git_indexer_new(&indexer, ".", NULL); #else error = git_indexer_new(&indexer, ".", 0, odb, NULL); #endif diff --git a/include/git2/indexer.h b/include/git2/indexer.h index d47ce2c1885..9aaedc3c43f 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -77,6 +77,9 @@ typedef struct git_indexer_options { /** permissions to use creating packfile or 0 for defaults */ unsigned int mode; + /** the type of object ids in the packfile or 0 for SHA1 */ + git_oid_t oid_type; + /** * object database from which to read base objects when * fixing thin packs. This can be NULL if there are no thin @@ -120,13 +123,12 @@ GIT_EXTERN(int) git_indexer_options_init( * * @param out where to store the indexer instance * @param path to the directory where the packfile should be stored - * @param oid_type the oid type to use for objects + * @param opts the options to create the indexer with * @return 0 or an error code. */ GIT_EXTERN(int) git_indexer_new( git_indexer **out, const char *path, - git_oid_t oid_type, git_indexer_options *opts); #else /** diff --git a/src/cli/cmd_index_pack.c b/src/cli/cmd_index_pack.c index b8e9749de6a..6a67990b47d 100644 --- a/src/cli/cmd_index_pack.c +++ b/src/cli/cmd_index_pack.c @@ -78,7 +78,9 @@ int cmd_index_pack(int argc, char **argv) } #ifdef GIT_EXPERIMENTAL_SHA256 - ret = git_indexer_new(&idx, ".", GIT_OID_SHA1, &idx_opts); + idx_opts.oid_type = GIT_OID_SHA1; + + ret = git_indexer_new(&idx, ".", &idx_opts); #else ret = git_indexer_new(&idx, ".", 0, NULL, &idx_opts); #endif diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index 32a37e0670a..e62daacfa51 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -171,9 +171,12 @@ static int indexer_new( if (in_opts) memcpy(&opts, in_opts, sizeof(opts)); + if (oid_type) + GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); + idx = git__calloc(1, sizeof(git_indexer)); GIT_ERROR_CHECK_ALLOC(idx); - idx->oid_type = oid_type; + idx->oid_type = oid_type ? oid_type : GIT_OID_DEFAULT; idx->odb = odb; idx->progress_cb = opts.progress_cb; idx->progress_payload = opts.progress_cb_payload; @@ -233,13 +236,12 @@ static int indexer_new( int git_indexer_new( git_indexer **out, const char *prefix, - git_oid_t oid_type, git_indexer_options *opts) { return indexer_new( out, prefix, - oid_type, + opts ? opts->oid_type : 0, opts ? opts->mode : 0, opts ? opts->odb : NULL, opts); diff --git a/src/libgit2/odb_pack.c b/src/libgit2/odb_pack.c index 96d3a2be476..430a54a3b77 100644 --- a/src/libgit2/odb_pack.c +++ b/src/libgit2/odb_pack.c @@ -743,10 +743,10 @@ static int pack_backend__writepack(struct git_odb_writepack **out, #ifdef GIT_EXPERIMENTAL_SHA256 opts.odb = odb; + opts.oid_type = backend->opts.oid_type; error = git_indexer_new(&writepack->indexer, backend->pack_folder, - backend->opts.oid_type, &opts); #else error = git_indexer_new(&writepack->indexer, diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index 298e70aa605..ced98e8c86d 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -1442,8 +1442,9 @@ int git_packbuilder_write( #ifdef GIT_EXPERIMENTAL_SHA256 opts.mode = mode; opts.odb = pb->odb; + opts.oid_type = GIT_OID_SHA1; - error = git_indexer_new(&indexer, path, GIT_OID_SHA1, &opts); + error = git_indexer_new(&indexer, path, &opts); #else error = git_indexer_new(&indexer, path, mode, pb->odb, &opts); #endif diff --git a/tests/libgit2/pack/indexer.c b/tests/libgit2/pack/indexer.c index 9722decafc0..023eb5da795 100644 --- a/tests/libgit2/pack/indexer.c +++ b/tests/libgit2/pack/indexer.c @@ -101,7 +101,7 @@ void test_pack_indexer__out_of_order(void) git_indexer_progress stats = { 0 }; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&idx, ".", NULL)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); #endif @@ -123,7 +123,7 @@ void test_pack_indexer__missing_trailer(void) git_indexer_progress stats = { 0 }; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&idx, ".", NULL)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); #endif @@ -144,7 +144,7 @@ void test_pack_indexer__leaky(void) git_indexer_progress stats = { 0 }; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&idx, ".", NULL)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); #endif @@ -178,7 +178,7 @@ void test_pack_indexer__fix_thin(void) #ifdef GIT_EXPERIMENTAL_SHA256 opts.odb = odb; - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts)); + cl_git_pass(git_indexer_new(&idx, ".", &opts)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, odb, &opts)); #endif @@ -215,7 +215,7 @@ void test_pack_indexer__fix_thin(void) cl_git_pass(p_stat(name, &st)); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&idx, ".", NULL)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); #endif @@ -255,7 +255,8 @@ void test_pack_indexer__corrupt_length(void) #ifdef GIT_EXPERIMENTAL_SHA256 opts.odb = odb; - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts)); + opts.oid_type = GIT_OID_SHA1; + cl_git_pass(git_indexer_new(&idx, ".", &opts)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, odb, &opts)); #endif @@ -281,7 +282,7 @@ void test_pack_indexer__incomplete_pack_fails_with_strict(void) opts.verify = 1; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts)); + cl_git_pass(git_indexer_new(&idx, ".", &opts)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts)); #endif @@ -306,7 +307,7 @@ void test_pack_indexer__out_of_order_with_connectivity_checks(void) opts.verify = 1; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts)); + cl_git_pass(git_indexer_new(&idx, ".", &opts)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts)); #endif @@ -354,7 +355,7 @@ void test_pack_indexer__no_tmp_files(void) cl_assert(git_str_len(&first_tmp_file) == 0); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&idx, ".", NULL)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); #endif diff --git a/tests/libgit2/pack/packbuilder.c b/tests/libgit2/pack/packbuilder.c index 05dea29d10e..2c598b6ee94 100644 --- a/tests/libgit2/pack/packbuilder.c +++ b/tests/libgit2/pack/packbuilder.c @@ -102,7 +102,7 @@ void test_pack_packbuilder__create_pack(void) seed_packbuilder(); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&_indexer, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&_indexer, ".", NULL)); #else cl_git_pass(git_indexer_new(&_indexer, ".", 0, NULL, NULL)); #endif @@ -261,7 +261,7 @@ void test_pack_packbuilder__foreach(void) seed_packbuilder(); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&idx, ".", NULL)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); #endif @@ -285,7 +285,7 @@ void test_pack_packbuilder__foreach_with_cancel(void) seed_packbuilder(); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL)); + cl_git_pass(git_indexer_new(&idx, ".", NULL)); #else cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL)); #endif From cefcabfcc1841130a815d5a5f473c25da7f21048 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 17:11:42 +0000 Subject: [PATCH 731/816] repo: specify odb options to odb_wrap odb wrapping --- include/git2/repository.h | 3 ++- src/libgit2/repository.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 59c4d0f30d6..d354b5efc4f 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -10,6 +10,7 @@ #include "common.h" #include "types.h" #include "oid.h" +#include "odb.h" #include "buffer.h" #include "commit.h" @@ -57,7 +58,7 @@ GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_work GIT_EXTERN(int) git_repository_wrap_odb( git_repository **out, git_odb *odb, - git_oid_t oid_type); + const git_odb_options *opts); #else diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index d41fa3933ad..448bf5e2abf 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1228,6 +1228,8 @@ int git_repository__wrap_odb( { git_repository *repo; + GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); + repo = repository_alloc(); GIT_ERROR_CHECK_ALLOC(repo); @@ -1243,9 +1245,9 @@ int git_repository__wrap_odb( int git_repository_wrap_odb( git_repository **out, git_odb *odb, - git_oid_t oid_type) + const git_odb_options *opts) { - return git_repository__wrap_odb(out, odb, oid_type); + return git_repository__wrap_odb(out, odb, opts ? opts->oid_type : GIT_OID_DEFAULT); } #else int git_repository_wrap_odb(git_repository **out, git_odb *odb) From 43c31ecc42ff9312beba58b321141f39505b8531 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 16 Dec 2024 17:25:12 +0000 Subject: [PATCH 732/816] repo: don't require oid_type to wrap_odb The `wrap_odb` function doesn't need to know the OID types in the object database; the object database already knows the type. --- include/git2/repository.h | 11 ----------- src/libgit2/repository.c | 25 +++---------------------- src/libgit2/repository.h | 5 ----- tests/libgit2/odb/backend/loose.c | 2 +- tests/libgit2/odb/backend/mempack.c | 2 +- tests/libgit2/refs/iterator.c | 2 +- 6 files changed, 6 insertions(+), 41 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index d354b5efc4f..b203576affc 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -53,15 +53,6 @@ GIT_EXTERN(int) git_repository_open(git_repository **out, const char *path); */ GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_worktree *wt); -#ifdef GIT_EXPERIMENTAL_SHA256 - -GIT_EXTERN(int) git_repository_wrap_odb( - git_repository **out, - git_odb *odb, - const git_odb_options *opts); - -#else - /** * Create a "fake" repository to wrap an object database * @@ -77,8 +68,6 @@ GIT_EXTERN(int) git_repository_wrap_odb( git_repository **out, git_odb *odb); -#endif - /** * Look for a git repository and copy its path in the given buffer. * The lookup start from base_path and walk across parent directories diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 448bf5e2abf..94738fd61ed 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1221,19 +1221,15 @@ int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *w return err; } -int git_repository__wrap_odb( - git_repository **out, - git_odb *odb, - git_oid_t oid_type) +int git_repository_wrap_odb(git_repository **out, git_odb *odb) { git_repository *repo; - GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); - repo = repository_alloc(); GIT_ERROR_CHECK_ALLOC(repo); - repo->oid_type = oid_type; + GIT_ASSERT(git_oid_type_is_valid(odb->options.oid_type)); + repo->oid_type = odb->options.oid_type; git_repository_set_odb(repo, odb); *out = repo; @@ -1241,21 +1237,6 @@ int git_repository__wrap_odb( return 0; } -#ifdef GIT_EXPERIMENTAL_SHA256 -int git_repository_wrap_odb( - git_repository **out, - git_odb *odb, - const git_odb_options *opts) -{ - return git_repository__wrap_odb(out, odb, opts ? opts->oid_type : GIT_OID_DEFAULT); -} -#else -int git_repository_wrap_odb(git_repository **out, git_odb *odb) -{ - return git_repository__wrap_odb(out, odb, GIT_OID_DEFAULT); -} -#endif - int git_repository_discover( git_buf *out, const char *start_path, diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index 79e087bfa93..fbf143894e6 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -199,11 +199,6 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo); int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo); int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo); -int git_repository__wrap_odb( - git_repository **out, - git_odb *odb, - git_oid_t oid_type); - /* * Configuration map cache * diff --git a/tests/libgit2/odb/backend/loose.c b/tests/libgit2/odb/backend/loose.c index 02227945d71..f5a0b4f5caf 100644 --- a/tests/libgit2/odb/backend/loose.c +++ b/tests/libgit2/odb/backend/loose.c @@ -21,7 +21,7 @@ void test_odb_backend_loose__initialize(void) cl_git_pass(git_odb__new(&_odb, NULL)); cl_git_pass(git_odb_add_backend(_odb, backend, 10)); - cl_git_pass(git_repository__wrap_odb(&_repo, _odb, GIT_OID_SHA1)); + cl_git_pass(git_repository_wrap_odb(&_repo, _odb)); } void test_odb_backend_loose__cleanup(void) diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c index 84449090a06..462a1d333a6 100644 --- a/tests/libgit2/odb/backend/mempack.c +++ b/tests/libgit2/odb/backend/mempack.c @@ -15,7 +15,7 @@ void test_odb_backend_mempack__initialize(void) cl_git_pass(git_mempack_new(&_backend)); cl_git_pass(git_odb__new(&_odb, NULL)); cl_git_pass(git_odb_add_backend(_odb, _backend, 10)); - cl_git_pass(git_repository__wrap_odb(&_repo, _odb, GIT_OID_SHA1)); + cl_git_pass(git_repository_wrap_odb(&_repo, _odb)); } void test_odb_backend_mempack__cleanup(void) diff --git a/tests/libgit2/refs/iterator.c b/tests/libgit2/refs/iterator.c index 020ee01a484..a46db629085 100644 --- a/tests/libgit2/refs/iterator.c +++ b/tests/libgit2/refs/iterator.c @@ -129,7 +129,7 @@ void test_refs_iterator__empty(void) git_repository *empty; cl_git_pass(git_odb__new(&odb, NULL)); - cl_git_pass(git_repository__wrap_odb(&empty, odb, GIT_OID_SHA1)); + cl_git_pass(git_repository_wrap_odb(&empty, odb)); cl_git_pass(git_reference_iterator_new(&iter, empty)); cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&ref, iter)); From 622035e6ad284e2e468d1b482e3ad4c718dff96e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Dec 2024 10:40:29 +0000 Subject: [PATCH 733/816] repo: take an options structure for repository_new Future-proof the SHA256-ification of `git_repository_new` by taking an options structure instead of an oid type. --- include/git2/sys/repository.h | 46 +++++++++++++++++++++++++-- src/libgit2/repository.c | 6 ++-- tests/libgit2/attr/repo.c | 2 +- tests/libgit2/network/remote/local.c | 6 +++- tests/libgit2/odb/backend/nobackend.c | 6 +++- tests/libgit2/repo/new.c | 23 +++++++++++--- 6 files changed, 78 insertions(+), 11 deletions(-) diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h index eb0a33a92de..026ac8a1d1a 100644 --- a/include/git2/sys/repository.h +++ b/include/git2/sys/repository.h @@ -22,14 +22,56 @@ GIT_BEGIN_DECL #ifdef GIT_EXPERIMENTAL_SHA256 +/** + * The options for creating an repository from scratch. + * + * Initialize with `GIT_REPOSITORY_NEW_OPTIONS_INIT`. Alternatively, + * you can use `git_repository_new_options_init`. + * + * @options[version] GIT_REPOSITORY_NEW_OPTIONS_VERSION + * @options[init_macro] GIT_REPOSITORY_NEW_OPTIONS_INIT + * @options[init_function] git_repository_new_options_init + */ +typedef struct git_repository_new_options { + unsigned int version; /**< The version */ + + /** + * The object ID type for the object IDs that exist in the index. + * + * If this is not specified, this defaults to `GIT_OID_SHA1`. + */ + git_oid_t oid_type; +} git_repository_new_options; + +/** Current version for the `git_repository_new_options` structure */ +#define GIT_REPOSITORY_NEW_OPTIONS_VERSION 1 + +/** Static constructor for `git_repository_new_options` */ +#define GIT_REPOSITORY_NEW_OPTIONS_INIT { GIT_REPOSITORY_NEW_OPTIONS_VERSION } + +/** + * Initialize git_repository_new_options structure + * + * Initializes a `git_repository_new_options` with default values. + * Equivalent to creating an instance with + * `GIT_REPOSITORY_NEW_OPTIONS_INIT`. + * + * @param opts The `git_repository_new_options` struct to initialize. + * @param version The struct version; pass `GIT_REPOSITORY_NEW_OPTIONS_VERSION`. + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_repository_new_options_init( + git_repository_new_options *opts, + unsigned int version); + /** * Create a new repository with no backends. * * @param[out] out The blank repository - * @param oid_type the object ID type for this repository + * @param opts the options for repository creation, or NULL for defaults * @return 0 on success, or an error code */ -GIT_EXTERN(int) git_repository_new(git_repository **out, git_oid_t oid_type); +GIT_EXTERN(int) git_repository_new(git_repository **out, git_repository_new_options *opts); #else /** diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 94738fd61ed..82aea517a1c 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -335,6 +335,8 @@ int git_repository__new(git_repository **out, git_oid_t oid_type) *out = repo = repository_alloc(); GIT_ERROR_CHECK_ALLOC(repo); + GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); + repo->is_bare = 1; repo->is_worktree = 0; repo->oid_type = oid_type; @@ -343,9 +345,9 @@ int git_repository__new(git_repository **out, git_oid_t oid_type) } #ifdef GIT_EXPERIMENTAL_SHA256 -int git_repository_new(git_repository **out, git_oid_t oid_type) +int git_repository_new(git_repository **out, git_repository_new_options *opts) { - return git_repository__new(out, oid_type); + return git_repository__new(out, opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT); } #else int git_repository_new(git_repository** out) diff --git a/tests/libgit2/attr/repo.c b/tests/libgit2/attr/repo.c index 747715b51fa..793c1a7d041 100644 --- a/tests/libgit2/attr/repo.c +++ b/tests/libgit2/attr/repo.c @@ -318,7 +318,7 @@ void test_attr_repo__inmemory_repo_without_index(void) /* setup bare in-memory repo without index */ #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&inmemory, GIT_OID_SHA1)); + cl_git_pass(git_repository_new(&inmemory, NULL)); #else cl_git_pass(git_repository_new(&inmemory)); #endif diff --git a/tests/libgit2/network/remote/local.c b/tests/libgit2/network/remote/local.c index f69502c7b15..9f3c8b61179 100644 --- a/tests/libgit2/network/remote/local.c +++ b/tests/libgit2/network/remote/local.c @@ -471,10 +471,14 @@ void test_network_remote_local__anonymous_remote_inmemory_repo(void) git_repository *inmemory; git_remote *remote; +#ifdef GIT_EXPERIMENTAL_SHA256 + git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; +#endif + git_str_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git"))); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&inmemory, GIT_OID_SHA1)); + cl_git_pass(git_repository_new(&inmemory, &repo_opts)); #else cl_git_pass(git_repository_new(&inmemory)); #endif diff --git a/tests/libgit2/odb/backend/nobackend.c b/tests/libgit2/odb/backend/nobackend.c index a81e5857715..e8af9a6d6fa 100644 --- a/tests/libgit2/odb/backend/nobackend.c +++ b/tests/libgit2/odb/backend/nobackend.c @@ -12,7 +12,11 @@ void test_odb_backend_nobackend__initialize(void) git_refdb *refdb; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&_repo, GIT_OID_SHA1)); + git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; + + repo_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_repository_new(&_repo, &repo_opts)); #else cl_git_pass(git_repository_new(&_repo)); #endif diff --git a/tests/libgit2/repo/new.c b/tests/libgit2/repo/new.c index aaa917a4aba..5136e60b09d 100644 --- a/tests/libgit2/repo/new.c +++ b/tests/libgit2/repo/new.c @@ -6,7 +6,11 @@ void test_repo_new__has_nothing(void) git_repository *repo; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&repo, GIT_OID_SHA1)); + git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; + + repo_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_repository_new(&repo, &repo_opts)); #else cl_git_pass(git_repository_new(&repo)); #endif @@ -21,7 +25,11 @@ void test_repo_new__is_bare_until_workdir_set(void) git_repository *repo; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&repo, GIT_OID_SHA1)); + git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; + + repo_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_repository_new(&repo, &repo_opts)); #else cl_git_pass(git_repository_new(&repo)); #endif @@ -38,7 +46,11 @@ void test_repo_new__sha1(void) git_repository *repo; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&repo, GIT_OID_SHA1)); + git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; + + repo_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_repository_new(&repo, &repo_opts)); #else cl_git_pass(git_repository_new(&repo)); #endif @@ -53,8 +65,11 @@ void test_repo_new__sha256(void) cl_skip(); #else git_repository *repo; + git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; + + repo_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_repository_new(&repo, GIT_OID_SHA256)); + cl_git_pass(git_repository_new(&repo, &repo_opts)); cl_assert_equal_i(GIT_OID_SHA256, git_repository_oid_type(repo)); git_repository_free(repo); From 54d666e5f725f408d37312be4a15bd6b2f6a3fdb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 18 Dec 2024 10:40:03 +0000 Subject: [PATCH 734/816] commit_graph: move opts to `new` function Instead of making the commit and dump functions take individual options structures; provide the options structure to the writer creator. This allows us to add additional information (like OID type) during generation. --- include/git2/sys/commit_graph.h | 116 +++++++++++++++--------------- src/libgit2/commit_graph.c | 74 ++++++++++--------- src/libgit2/commit_graph.h | 3 +- tests/libgit2/graph/commitgraph.c | 9 +-- 4 files changed, 99 insertions(+), 103 deletions(-) diff --git a/include/git2/sys/commit_graph.h b/include/git2/sys/commit_graph.h index 838efee55bf..33234bbf7ef 100644 --- a/include/git2/sys/commit_graph.h +++ b/include/git2/sys/commit_graph.h @@ -46,54 +46,6 @@ GIT_EXTERN(int) git_commit_graph_open( */ GIT_EXTERN(void) git_commit_graph_free(git_commit_graph *cgraph); -/** - * Create a new writer for `commit-graph` files. - * - * @param out Location to store the writer pointer. - * @param objects_info_dir The `objects/info` directory. - * The `commit-graph` file will be written in this directory. - * @return 0 or an error code - */ -GIT_EXTERN(int) git_commit_graph_writer_new( - git_commit_graph_writer **out, - const char *objects_info_dir -#ifdef GIT_EXPERIMENTAL_SHA256 - , git_oid_t oid_type -#endif - ); - -/** - * Free the commit-graph writer and its resources. - * - * @param w The writer to free. If NULL no action is taken. - */ -GIT_EXTERN(void) git_commit_graph_writer_free(git_commit_graph_writer *w); - -/** - * Add an `.idx` file (associated to a packfile) to the writer. - * - * @param w The writer. - * @param repo The repository that owns the `.idx` file. - * @param idx_path The path of an `.idx` file. - * @return 0 or an error code - */ -GIT_EXTERN(int) git_commit_graph_writer_add_index_file( - git_commit_graph_writer *w, - git_repository *repo, - const char *idx_path); - -/** - * Add a revwalk to the writer. This will add all the commits from the revwalk - * to the commit-graph. - * - * @param w The writer. - * @param walk The git_revwalk. - * @return 0 or an error code - */ -GIT_EXTERN(int) git_commit_graph_writer_add_revwalk( - git_commit_graph_writer *w, - git_revwalk *walk); - /** * The strategy to use when adding a new set of commits to a pre-existing @@ -108,15 +60,19 @@ typedef enum { } git_commit_graph_split_strategy_t; /** - * Options structure for - * `git_commit_graph_writer_commit`/`git_commit_graph_writer_dump`. + * Options structure for `git_commit_graph_writer_new`. * - * Initialize with `GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT`. Alternatively, you - * can use `git_commit_graph_writer_options_init`. + * Initialize with `GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT`. Alternatively, + * you can use `git_commit_graph_writer_options_init`. */ typedef struct { unsigned int version; +#ifdef GIT_EXPERIMENTAL_SHA256 + /** The object ID type that this commit graph contains. */ + git_oid_t oid_type; +#endif + /** * The strategy to use when adding new commits to a pre-existing commit-graph * chain. @@ -158,29 +114,71 @@ GIT_EXTERN(int) git_commit_graph_writer_options_init( git_commit_graph_writer_options *opts, unsigned int version); +/** + * Create a new writer for `commit-graph` files. + * + * @param out Location to store the writer pointer. + * @param objects_info_dir The `objects/info` directory. + * The `commit-graph` file will be written in this directory. + * @param options The options for the commit graph writer. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_commit_graph_writer_new( + git_commit_graph_writer **out, + const char *objects_info_dir, + const git_commit_graph_writer_options *options); + +/** + * Free the commit-graph writer and its resources. + * + * @param w The writer to free. If NULL no action is taken. + */ +GIT_EXTERN(void) git_commit_graph_writer_free(git_commit_graph_writer *w); + +/** + * Add an `.idx` file (associated to a packfile) to the writer. + * + * @param w The writer. + * @param repo The repository that owns the `.idx` file. + * @param idx_path The path of an `.idx` file. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_commit_graph_writer_add_index_file( + git_commit_graph_writer *w, + git_repository *repo, + const char *idx_path); + +/** + * Add a revwalk to the writer. This will add all the commits from the revwalk + * to the commit-graph. + * + * @param w The writer. + * @param walk The git_revwalk. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_commit_graph_writer_add_revwalk( + git_commit_graph_writer *w, + git_revwalk *walk); + /** * Write a `commit-graph` file to a file. * * @param w The writer - * @param opts Pointer to git_commit_graph_writer_options struct. * @return 0 or an error code */ GIT_EXTERN(int) git_commit_graph_writer_commit( - git_commit_graph_writer *w, - git_commit_graph_writer_options *opts); + git_commit_graph_writer *w); /** * Dump the contents of the `commit-graph` to an in-memory buffer. * - * @param buffer Buffer where to store the contents of the `commit-graph`. + * @param[out] buffer Buffer where to store the contents of the `commit-graph`. * @param w The writer. - * @param opts Pointer to git_commit_graph_writer_options struct. * @return 0 or an error code */ GIT_EXTERN(int) git_commit_graph_writer_dump( git_buf *buffer, - git_commit_graph_writer *w, - git_commit_graph_writer_options *opts); + git_commit_graph_writer *w); /** @} */ GIT_END_DECL diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index 8fd59692730..bfec707f3d4 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -684,21 +684,40 @@ static int packed_commit__cmp(const void *a_, const void *b_) return git_oid_cmp(&a->sha1, &b->sha1); } +int git_commit_graph_writer_options_init( + git_commit_graph_writer_options *opts, + unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, + version, + git_commit_graph_writer_options, + GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT); + return 0; +} + int git_commit_graph_writer_new( git_commit_graph_writer **out, - const char *objects_info_dir -#ifdef GIT_EXPERIMENTAL_SHA256 - , git_oid_t oid_type -#endif + const char *objects_info_dir, + const git_commit_graph_writer_options *opts ) { git_commit_graph_writer *w; + git_oid_t oid_type; -#ifndef GIT_EXPERIMENTAL_SHA256 - git_oid_t oid_type = GIT_OID_SHA1; +#ifdef GIT_EXPERIMENTAL_SHA256 + GIT_ERROR_CHECK_VERSION(opts, + GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION, + "git_commit_graph_writer_options"); + + oid_type = opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT; + GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); +#else + GIT_UNUSED(opts); + oid_type = GIT_OID_SHA1; #endif - GIT_ASSERT_ARG(out && objects_info_dir && oid_type); + GIT_ASSERT_ARG(out && objects_info_dir); w = git__calloc(1, sizeof(git_commit_graph_writer)); GIT_ERROR_CHECK_ALLOC(w); @@ -775,9 +794,9 @@ static int object_entry__cb(const git_oid *id, void *data) } int git_commit_graph_writer_add_index_file( - git_commit_graph_writer *w, - git_repository *repo, - const char *idx_path) + git_commit_graph_writer *w, + git_repository *repo, + const char *idx_path) { int error; struct git_pack_file *p = NULL; @@ -1043,9 +1062,9 @@ static void packed_commit_free_dup(void *packed_commit) } static int commit_graph_write( - git_commit_graph_writer *w, - commit_graph_write_cb write_cb, - void *cb_data) + git_commit_graph_writer *w, + commit_graph_write_cb write_cb, + void *cb_data) { int error = 0; size_t i; @@ -1249,30 +1268,13 @@ static int commit_graph_write_filebuf(const char *buf, size_t size, void *data) return git_filebuf_write(f, buf, size); } -int git_commit_graph_writer_options_init( - git_commit_graph_writer_options *opts, - unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, - version, - git_commit_graph_writer_options, - GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT); - return 0; -} - -int git_commit_graph_writer_commit( - git_commit_graph_writer *w, - git_commit_graph_writer_options *opts) +int git_commit_graph_writer_commit(git_commit_graph_writer *w) { int error; int filebuf_flags = GIT_FILEBUF_DO_NOT_BUFFER; git_str commit_graph_path = GIT_STR_INIT; git_filebuf output = GIT_FILEBUF_INIT; - /* TODO: support options and fill in defaults. */ - GIT_UNUSED(opts); - error = git_str_joinpath( &commit_graph_path, git_str_cstr(&w->objects_info_dir), "commit-graph"); if (error < 0) @@ -1296,18 +1298,14 @@ int git_commit_graph_writer_commit( int git_commit_graph_writer_dump( git_buf *cgraph, - git_commit_graph_writer *w, - git_commit_graph_writer_options *opts) + git_commit_graph_writer *w) { - GIT_BUF_WRAP_PRIVATE(cgraph, git_commit_graph__writer_dump, w, opts); + GIT_BUF_WRAP_PRIVATE(cgraph, git_commit_graph__writer_dump, w); } int git_commit_graph__writer_dump( git_str *cgraph, - git_commit_graph_writer *w, - git_commit_graph_writer_options *opts) + git_commit_graph_writer *w) { - /* TODO: support options. */ - GIT_UNUSED(opts); return commit_graph_write(w, commit_graph_write_buf, cgraph); } diff --git a/src/libgit2/commit_graph.h b/src/libgit2/commit_graph.h index ecf4379bdb6..a06f3f86219 100644 --- a/src/libgit2/commit_graph.h +++ b/src/libgit2/commit_graph.h @@ -156,8 +156,7 @@ struct git_commit_graph_writer { int git_commit_graph__writer_dump( git_str *cgraph, - git_commit_graph_writer *w, - git_commit_graph_writer_options *opts); + git_commit_graph_writer *w); /* * Returns whether the git_commit_graph_file needs to be reloaded since the diff --git a/tests/libgit2/graph/commitgraph.c b/tests/libgit2/graph/commitgraph.c index 53869d61db0..98412671227 100644 --- a/tests/libgit2/graph/commitgraph.c +++ b/tests/libgit2/graph/commitgraph.c @@ -105,18 +105,19 @@ void test_graph_commitgraph__writer(void) cl_git_pass(git_str_joinpath(&path, git_repository_path(repo), "objects/info")); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_commit_graph_writer_new(&w, git_str_cstr(&path), GIT_OID_SHA1)); -#else - cl_git_pass(git_commit_graph_writer_new(&w, git_str_cstr(&path))); + opts.oid_type = GIT_OID_SHA1; #endif + cl_git_pass(git_commit_graph_writer_new(&w, git_str_cstr(&path), &opts)); + /* This is equivalent to `git commit-graph write --reachable`. */ cl_git_pass(git_revwalk_new(&walk, repo)); cl_git_pass(git_revwalk_push_glob(walk, "refs/*")); cl_git_pass(git_commit_graph_writer_add_revwalk(w, walk)); git_revwalk_free(walk); - cl_git_pass(git_commit_graph_writer_dump(&cgraph, w, &opts)); + cl_git_pass(git_commit_graph_writer_dump(&cgraph, w)); + cl_git_pass(git_str_joinpath(&path, git_repository_path(repo), "objects/info/commit-graph")); cl_git_pass(git_futils_readbuffer(&expected_cgraph, git_str_cstr(&path))); From 0738b054d36e994d8be1135223a9ad6e8e55a020 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 18 Dec 2024 10:51:48 +0000 Subject: [PATCH 735/816] commit_graph: add opts to `open` function Provide an options structure to commit graph opening. This allows us to specify information (like OID type) during opening. --- include/git2/sys/commit_graph.h | 41 ++++++++++++++++++++++++++++++- src/libgit2/commit_graph.c | 17 ++++++++++--- tests/libgit2/graph/commitgraph.c | 12 +++++++-- 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/include/git2/sys/commit_graph.h b/include/git2/sys/commit_graph.h index 33234bbf7ef..ff547ef0c1f 100644 --- a/include/git2/sys/commit_graph.h +++ b/include/git2/sys/commit_graph.h @@ -19,6 +19,45 @@ */ GIT_BEGIN_DECL +/** + * Options structure for `git_commit_graph_open_new`. + * + * Initialize with `GIT_COMMIT_GRAPH_OPEN_OPTIONS_INIT`. Alternatively, + * you can use `git_commit_graph_open_options_init`. + */ +typedef struct { + unsigned int version; + +#ifdef GIT_EXPERIMENTAL_SHA256 + /** The object ID type that this commit graph contains. */ + git_oid_t oid_type; +#endif +} git_commit_graph_open_options; + +/** Current version for the `git_commit_graph_open_options` structure */ +#define GIT_COMMIT_GRAPH_OPEN_OPTIONS_VERSION 1 + +/** Static constructor for `git_commit_graph_open_options` */ +#define GIT_COMMIT_GRAPH_OPEN_OPTIONS_INIT { \ + GIT_COMMIT_GRAPH_OPEN_OPTIONS_VERSION \ + } + +/** + * Initialize git_commit_graph_open_options structure + * + * Initializes a `git_commit_graph_open_options` with default values. + * Equivalent to creating an instance with + * `GIT_COMMIT_GRAPH_OPEN_OPTIONS_INIT`. + * + * @param opts The `git_commit_graph_open_options` struct to initialize. + * @param version The struct version; pass `GIT_COMMIT_GRAPH_OPEN_OPTIONS_VERSION`. + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_commit_graph_open_options_init( + git_commit_graph_open_options *opts, + unsigned int version); + + /** * Opens a `git_commit_graph` from a path to an objects directory. * @@ -32,7 +71,7 @@ GIT_EXTERN(int) git_commit_graph_open( git_commit_graph **cgraph_out, const char *objects_dir #ifdef GIT_EXPERIMENTAL_SHA256 - , git_oid_t oid_type + , const git_commit_graph_open_options *options #endif ); diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index bfec707f3d4..92785049e4e 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -365,15 +365,24 @@ int git_commit_graph_open( git_commit_graph **cgraph_out, const char *objects_dir #ifdef GIT_EXPERIMENTAL_SHA256 - , git_oid_t oid_type + , const git_commit_graph_open_options *opts #endif ) { -#ifndef GIT_EXPERIMENTAL_SHA256 - git_oid_t oid_type = GIT_OID_SHA1; -#endif + git_oid_t oid_type; int error; +#ifdef GIT_EXPERIMENTAL_SHA256 + GIT_ERROR_CHECK_VERSION(opts, + GIT_COMMIT_GRAPH_OPEN_OPTIONS_VERSION, + "git_commit_graph_open_options"); + + oid_type = opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT; + GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); +#else + oid_type = GIT_OID_SHA1; +#endif + error = git_commit_graph_new(cgraph_out, objects_dir, true, oid_type); diff --git a/tests/libgit2/graph/commitgraph.c b/tests/libgit2/graph/commitgraph.c index 98412671227..363806bd9e9 100644 --- a/tests/libgit2/graph/commitgraph.c +++ b/tests/libgit2/graph/commitgraph.c @@ -137,12 +137,16 @@ void test_graph_commitgraph__validate(void) struct git_commit_graph *cgraph; git_str objects_dir = GIT_STR_INIT; +#ifdef GIT_EXPERIMENTAL_SHA256 + git_commit_graph_open_options opts = GIT_COMMIT_GRAPH_OPEN_OPTIONS_INIT; +#endif + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_str_joinpath(&objects_dir, git_repository_path(repo), "objects")); /* git_commit_graph_open() calls git_commit_graph_validate() */ #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_commit_graph_open(&cgraph, git_str_cstr(&objects_dir), GIT_OID_SHA1)); + cl_git_pass(git_commit_graph_open(&cgraph, git_str_cstr(&objects_dir), &opts)); #else cl_git_pass(git_commit_graph_open(&cgraph, git_str_cstr(&objects_dir))); #endif @@ -158,6 +162,10 @@ void test_graph_commitgraph__validate_corrupt(void) struct git_commit_graph *cgraph; int fd = -1; +#ifdef GIT_EXPERIMENTAL_SHA256 + git_commit_graph_open_options opts = GIT_COMMIT_GRAPH_OPEN_OPTIONS_INIT; +#endif + cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, cl_git_sandbox_path(1, "testrepo.git", NULL))); @@ -169,7 +177,7 @@ void test_graph_commitgraph__validate_corrupt(void) /* git_commit_graph_open() calls git_commit_graph_validate() */ #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_fail(git_commit_graph_open(&cgraph, cl_git_sandbox_path(1, "testrepo.git", "objects", NULL), GIT_OID_SHA1)); + cl_git_fail(git_commit_graph_open(&cgraph, cl_git_sandbox_path(1, "testrepo.git", "objects", NULL), &opts)); #else cl_git_fail(git_commit_graph_open(&cgraph, cl_git_sandbox_path(1, "testrepo.git", "objects", NULL))); #endif From 6aa9bc4a97c8b6f2350ba324a70a5051a732727b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 18 Dec 2024 11:05:03 +0000 Subject: [PATCH 736/816] midx: add options to writer function Provide an options structure to MIDX writing. This allows us to specify information (like OID type) during writer creation. --- include/git2/sys/midx.h | 40 ++++++++++++++++++++++++++++++++++++++- src/libgit2/midx.c | 22 ++++++++++++++------- src/libgit2/odb_pack.c | 10 +++++++++- tests/libgit2/pack/midx.c | 2 +- 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/include/git2/sys/midx.h b/include/git2/sys/midx.h index 2bf0d01eb48..b3a68afbfc5 100644 --- a/include/git2/sys/midx.h +++ b/include/git2/sys/midx.h @@ -19,6 +19,44 @@ */ GIT_BEGIN_DECL +/** + * Options structure for `git_midx_writer_options`. + * + * Initialize with `GIT_MIDX_WRITER_OPTIONS_INIT`. Alternatively, + * you can use `git_midx_writer_options_init`. + */ +typedef struct { + unsigned int version; + +#ifdef GIT_EXPERIMENTAL_SHA256 + /** The object ID type that this commit graph contains. */ + git_oid_t oid_type; +#endif +} git_midx_writer_options; + +/** Current version for the `git_midx_writer_options` structure */ +#define GIT_MIDX_WRITER_OPTIONS_VERSION 1 + +/** Static constructor for `git_midx_writer_options` */ +#define GIT_MIDX_WRITER_OPTIONS_INIT { \ + GIT_MIDX_WRITER_OPTIONS_VERSION \ + } + +/** + * Initialize git_midx_writer_options structure + * + * Initializes a `git_midx_writer_options` with default values. + * Equivalent to creating an instance with + * `GIT_MIDX_WRITER_OPTIONS_INIT`. + * + * @param opts The `git_midx_writer_options` struct to initialize. + * @param version The struct version; pass `GIT_MIDX_WRITER_OPTIONS_VERSION`. + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_midx_writer_options_init( + git_midx_writer_options *opts, + unsigned int version); + /** * Create a new writer for `multi-pack-index` files. * @@ -31,7 +69,7 @@ GIT_EXTERN(int) git_midx_writer_new( git_midx_writer **out, const char *pack_dir #ifdef GIT_EXPERIMENTAL_SHA256 - , git_oid_t oid_type + , git_midx_writer_options *options #endif ); diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index 0b16af94390..1336ed85f88 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -508,20 +508,28 @@ static int packfile__cmp(const void *a_, const void *b_) } int git_midx_writer_new( - git_midx_writer **out, - const char *pack_dir + git_midx_writer **out, + const char *pack_dir #ifdef GIT_EXPERIMENTAL_SHA256 - , git_oid_t oid_type + , git_midx_writer_options *opts #endif ) { git_midx_writer *w; + git_oid_t oid_type; -#ifndef GIT_EXPERIMENTAL_SHA256 - git_oid_t oid_type = GIT_OID_SHA1; -#endif + GIT_ASSERT_ARG(out && pack_dir); - GIT_ASSERT_ARG(out && pack_dir && oid_type); +#ifdef GIT_EXPERIMENTAL_SHA256 + GIT_ERROR_CHECK_VERSION(opts, + GIT_MIDX_WRITER_OPTIONS_VERSION, + "git_midx_writer_options"); + + oid_type = opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT; + GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); +#else + oid_type = GIT_OID_SHA1; +#endif w = git__calloc(1, sizeof(git_midx_writer)); GIT_ERROR_CHECK_ALLOC(w); diff --git a/src/libgit2/odb_pack.c b/src/libgit2/odb_pack.c index 430a54a3b77..ef8d35309fe 100644 --- a/src/libgit2/odb_pack.c +++ b/src/libgit2/odb_pack.c @@ -796,13 +796,21 @@ static int pack_backend__writemidx(git_odb_backend *_backend) size_t i; int error = 0; +#ifdef GIT_EXPERIMENTAL_SHA256 + git_midx_writer_options midx_opts = GIT_MIDX_WRITER_OPTIONS_INIT; +#endif + GIT_ASSERT_ARG(_backend); backend = (struct pack_backend *)_backend; +#ifdef GIT_EXPERIMENTAL_SHA256 + midx_opts.oid_type = backend->opts.oid_type; +#endif + error = git_midx_writer_new(&w, backend->pack_folder #ifdef GIT_EXPERIMENTAL_SHA256 - , backend->opts.oid_type + , &midx_opts #endif ); diff --git a/tests/libgit2/pack/midx.c b/tests/libgit2/pack/midx.c index 4c4dfc51178..d7180c47898 100644 --- a/tests/libgit2/pack/midx.c +++ b/tests/libgit2/pack/midx.c @@ -59,7 +59,7 @@ void test_pack_midx__writer(void) cl_git_pass(git_str_joinpath(&path, git_repository_path(repo), "objects/pack")); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path), GIT_OID_SHA1)); + cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path), NULL)); #else cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path))); #endif From dc95ee2712858af0b4df2cf54cef87f381701df1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 18 Dec 2024 20:56:49 +0000 Subject: [PATCH 737/816] ssl: restore tls v1.0 support temporarily Removing TLS v1.0 and v1.1 support is a bit of a breaking change; making that change without any announcement or preparation is rather unkind. Defer the TLS v1.2 requirement to the next version, but update the cipher selection to the Mozilla backward compatibility list. --- src/libgit2/streams/mbedtls.c | 10 ++++++---- src/libgit2/streams/openssl.c | 10 +++------- src/libgit2/streams/stransport.c | 3 ++- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index 1493f119c96..37abcdab571 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -39,8 +39,8 @@ #undef inline -#define GIT_SSL_DEFAULT_CIPHERS "TLS1-3-AES-128-GCM-SHA256:TLS1-3-AES-256-GCM-SHA384:TLS1-3-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256" -#define GIT_SSL_DEFAULT_CIPHERS_COUNT 12 +#define GIT_SSL_DEFAULT_CIPHERS "TLS1-3-AES-128-GCM-SHA256:TLS1-3-AES-256-GCM-SHA384:TLS1-3-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-GCM-SHA256:TLS-RSA-WITH-AES-256-GCM-SHA384:TLS-RSA-WITH-AES-128-CBC-SHA256:TLS-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA" +#define GIT_SSL_DEFAULT_CIPHERS_COUNT 28 static int ciphers_list[GIT_SSL_DEFAULT_CIPHERS_COUNT]; @@ -94,8 +94,10 @@ int git_mbedtls_stream_global_init(void) goto cleanup; } - /* configure TLSv1.2 */ - mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); + /* configure TLSv1.1 or better */ +#ifdef MBEDTLS_SSL_MINOR_VERSION_2 + mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); +#endif /* verify_server_cert is responsible for making the check. * OPTIONAL because REQUIRED drops the certificate as soon as the check diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index ca64e460b75..e5641e0e2c2 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -40,8 +40,7 @@ extern char *git__ssl_ciphers; SSL_CTX *git__ssl_ctx; -#define GIT_SSL_DEFAULT_CIPHERS "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305" - +#define GIT_SSL_DEFAULT_CIPHERS "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" static BIO_METHOD *git_stream_bio_method; static int init_bio_method(void); @@ -106,10 +105,7 @@ static void git_openssl_free(void *mem) static int openssl_init(void) { - long ssl_opts = SSL_OP_NO_SSLv2 | - SSL_OP_NO_SSLv3 | - SSL_OP_NO_TLSv1 | - SSL_OP_NO_TLSv1_1; + long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; const char *ciphers = git__ssl_ciphers; #ifdef VALGRIND static bool allocators_initialized = false; @@ -140,7 +136,7 @@ static int openssl_init(void) /* * Despite the name SSLv23_method, this is actually a version- * flexible context, which honors the protocol versions - * specified in `ssl_opts`. So we only support TLSv1.2 and + * specified in `ssl_opts`. So we only support TLSv1.0 and * higher. */ if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method()))) diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 2d4cc55b549..863616dcc77 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -331,7 +331,8 @@ static int stransport_wrap( if ((ret = SSLSetIOFuncs(st->ctx, read_cb, write_cb)) != noErr || (ret = SSLSetConnection(st->ctx, st)) != noErr || (ret = SSLSetSessionOption(st->ctx, kSSLSessionOptionBreakOnServerAuth, true)) != noErr || - (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol12)) != noErr || + (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr || + (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr || (ret = SSLSetPeerDomainName(st->ctx, host, strlen(host))) != noErr) { CFRelease(st->ctx); git__free(st); From e0edd7d0ec2149fd069cec48ff0ba38be3f99a69 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 18 Dec 2024 22:41:12 +0000 Subject: [PATCH 738/816] ssl: enforce TLS v1.2 (or better) Enforce TLS v1.2 or better, and ensure that we use the recommended ciphers (intermediate compatibility) from Mozilla. https://wiki.mozilla.org/Security/Server_Side_TLS --- src/libgit2/streams/mbedtls.c | 14 +++++++++----- src/libgit2/streams/openssl.c | 10 +++++++--- src/libgit2/streams/openssl_dynamic.h | 2 ++ src/libgit2/streams/stransport.c | 3 +-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index 37abcdab571..a3839c2ce15 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -39,8 +39,8 @@ #undef inline -#define GIT_SSL_DEFAULT_CIPHERS "TLS1-3-AES-128-GCM-SHA256:TLS1-3-AES-256-GCM-SHA384:TLS1-3-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-GCM-SHA256:TLS-RSA-WITH-AES-256-GCM-SHA384:TLS-RSA-WITH-AES-128-CBC-SHA256:TLS-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA" -#define GIT_SSL_DEFAULT_CIPHERS_COUNT 28 +#define GIT_SSL_DEFAULT_CIPHERS "TLS1-3-AES-128-GCM-SHA256:TLS1-3-AES-256-GCM-SHA384:TLS1-3-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256" +#define GIT_SSL_DEFAULT_CIPHERS_COUNT 12 static int ciphers_list[GIT_SSL_DEFAULT_CIPHERS_COUNT]; @@ -94,9 +94,13 @@ int git_mbedtls_stream_global_init(void) goto cleanup; } - /* configure TLSv1.1 or better */ -#ifdef MBEDTLS_SSL_MINOR_VERSION_2 - mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); + /* + * Configure TLSv1.2 or better; if the minor version constant isn't + * defined then this version of mbedTLS doesn't support such an old + * version, so we need not do anything. + */ +#ifdef MBEDTLS_SSL_MINOR_VERSION_3 + mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); #endif /* verify_server_cert is responsible for making the check. diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index e5641e0e2c2..ca64e460b75 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -40,7 +40,8 @@ extern char *git__ssl_ciphers; SSL_CTX *git__ssl_ctx; -#define GIT_SSL_DEFAULT_CIPHERS "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" +#define GIT_SSL_DEFAULT_CIPHERS "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305" + static BIO_METHOD *git_stream_bio_method; static int init_bio_method(void); @@ -105,7 +106,10 @@ static void git_openssl_free(void *mem) static int openssl_init(void) { - long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + long ssl_opts = SSL_OP_NO_SSLv2 | + SSL_OP_NO_SSLv3 | + SSL_OP_NO_TLSv1 | + SSL_OP_NO_TLSv1_1; const char *ciphers = git__ssl_ciphers; #ifdef VALGRIND static bool allocators_initialized = false; @@ -136,7 +140,7 @@ static int openssl_init(void) /* * Despite the name SSLv23_method, this is actually a version- * flexible context, which honors the protocol versions - * specified in `ssl_opts`. So we only support TLSv1.0 and + * specified in `ssl_opts`. So we only support TLSv1.2 and * higher. */ if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method()))) diff --git a/src/libgit2/streams/openssl_dynamic.h b/src/libgit2/streams/openssl_dynamic.h index e59f1f93b2a..0d7ef0f2a89 100644 --- a/src/libgit2/streams/openssl_dynamic.h +++ b/src/libgit2/streams/openssl_dynamic.h @@ -182,6 +182,8 @@ # define SSL_OP_NO_COMPRESSION 0x00020000L # define SSL_OP_NO_SSLv2 0x01000000L # define SSL_OP_NO_SSLv3 0x02000000L +# define SSL_OP_NO_TLSv1 0x04000000L +# define SSL_OP_NO_TLSv1_1 0x10000000L # define SSL_MODE_AUTO_RETRY 0x00000004L diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 863616dcc77..2d4cc55b549 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -331,8 +331,7 @@ static int stransport_wrap( if ((ret = SSLSetIOFuncs(st->ctx, read_cb, write_cb)) != noErr || (ret = SSLSetConnection(st->ctx, st)) != noErr || (ret = SSLSetSessionOption(st->ctx, kSSLSessionOptionBreakOnServerAuth, true)) != noErr || - (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr || - (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr || + (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol12)) != noErr || (ret = SSLSetPeerDomainName(st->ctx, host, strlen(host))) != noErr) { CFRelease(st->ctx); git__free(st); From f866bb97bff0c8654e89147527c394b5e3fe85ed Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 22 Dec 2024 08:44:37 +0000 Subject: [PATCH 739/816] features: move version tests out of features test Move the test for querying version information out of the `core::features` test and into the `core::version` test. --- tests/libgit2/core/features.c | 11 ++--------- tests/libgit2/core/version.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index a0f18b65941..366eea1a34d 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -1,15 +1,8 @@ #include "clar_libgit2.h" -void test_core_features__0(void) +void test_core_features__basic(void) { - int major, minor, rev, caps; - - git_libgit2_version(&major, &minor, &rev); - cl_assert_equal_i(LIBGIT2_VERSION_MAJOR, major); - cl_assert_equal_i(LIBGIT2_VERSION_MINOR, minor); - cl_assert_equal_i(LIBGIT2_VERSION_REVISION, rev); - - caps = git_libgit2_features(); + int caps = git_libgit2_features(); #ifdef GIT_THREADS cl_assert((caps & GIT_FEATURE_THREADS) != 0); diff --git a/tests/libgit2/core/version.c b/tests/libgit2/core/version.c index 32498c41d3f..9fd375c69b8 100644 --- a/tests/libgit2/core/version.c +++ b/tests/libgit2/core/version.c @@ -1,5 +1,15 @@ #include "clar_libgit2.h" +void test_core_version__query(void) +{ + int major, minor, rev; + + git_libgit2_version(&major, &minor, &rev); + cl_assert_equal_i(LIBGIT2_VERSION_MAJOR, major); + cl_assert_equal_i(LIBGIT2_VERSION_MINOR, minor); + cl_assert_equal_i(LIBGIT2_VERSION_REVISION, rev); +} + void test_core_version__check(void) { #if !LIBGIT2_VERSION_CHECK(1,6,3) From e0c255dbd68efaf69f0d013332629547bee84f1b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 22 Dec 2024 08:45:35 +0000 Subject: [PATCH 740/816] zlib: add zlib backend status to git2_features.h Add the status of the zlib backend (builtin or external) to `git2_features.h`. --- cmake/SelectZlib.cmake | 4 ++++ src/util/git2_features.h.in | 3 +++ 2 files changed, 7 insertions(+) diff --git a/cmake/SelectZlib.cmake b/cmake/SelectZlib.cmake index fb4361abc80..25c7b2f94fa 100644 --- a/cmake/SelectZlib.cmake +++ b/cmake/SelectZlib.cmake @@ -4,6 +4,7 @@ include(SanitizeBool) SanitizeBool(USE_BUNDLED_ZLIB) if(USE_BUNDLED_ZLIB STREQUAL ON) set(USE_BUNDLED_ZLIB "Bundled") + set(GIT_COMPRESSION_BUILTIN) endif() if(USE_BUNDLED_ZLIB STREQUAL "OFF") @@ -17,6 +18,7 @@ if(USE_BUNDLED_ZLIB STREQUAL "OFF") list(APPEND LIBGIT2_PC_REQUIRES "zlib") endif() add_feature_info(zlib ON "using system zlib") + set(GIT_COMPRESSION_ZLIB 1) else() message(STATUS "zlib was not found; using bundled 3rd-party sources." ) endif() @@ -26,9 +28,11 @@ if(USE_BUNDLED_ZLIB STREQUAL "Chromium") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/chromium-zlib") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $) add_feature_info(zlib ON "using (Chromium) bundled zlib") + set(GIT_COMPRESSION_BUILTIN 1) elseif(USE_BUNDLED_ZLIB OR NOT ZLIB_FOUND) add_subdirectory("${PROJECT_SOURCE_DIR}/deps/zlib" "${PROJECT_BINARY_DIR}/deps/zlib") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/zlib") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $) add_feature_info(zlib ON "using bundled zlib") + set(GIT_COMPRESSION_BUILTIN 1) endif() diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 9408f9b00f6..cd14cc2347d 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -66,6 +66,9 @@ #cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SHA256_MBEDTLS 1 +#cmakedefine GIT_COMPRESSION_BUILTIN 1 +#cmakedefine GIT_COMPRESSION_ZLIB 1 + #cmakedefine GIT_RAND_GETENTROPY 1 #cmakedefine GIT_RAND_GETLOADAVG 1 From 19a031d07539217c70bfa0280fff34cb9533eec6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 22 Dec 2024 09:07:54 +0000 Subject: [PATCH 741/816] Introduce `git_libgit2_feature_backend` API Provide a mechanism to understand the backend provider for feature within libgit2. For example, one can query the mechanism that provides HTTPS by asking for the backend for the `GIT_FEATURE_HTTPS`. This is particularly useful for features that are not completely isomorphic; the HTTPS providers may have slightly different functionality that can be controlled (eg, certificates or cipher support). And the SSH feature is _very_ different between libssh2 and OpenSSH. It may also be useful to understand the support for things like the SHA1 or SHA256 backends to ensure that sha1dc is used, or that FIPS mode is enabled. --- include/git2/common.h | 98 ++++++++++------- src/libgit2/libgit2.c | 171 +++++++++++++++++++++++++++++ tests/libgit2/core/features.c | 198 ++++++++++++++++++++++++++++++++++ 3 files changed, 430 insertions(+), 37 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index dda821c7cba..006f7eeb1e1 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -130,56 +130,80 @@ GIT_EXTERN(int) git_libgit2_version(int *major, int *minor, int *rev); GIT_EXTERN(const char *) git_libgit2_prerelease(void); /** - * Combinations of these values describe the features with which libgit2 - * was compiled + * Configurable features of libgit2; either optional settings (like + * threading), or features that can be enabled by one of a number of + * different backend "providers" (like HTTPS, which can be provided by + * OpenSSL, mbedTLS, or system libraries). */ typedef enum { - /** - * If set, libgit2 was built thread-aware and can be safely used from multiple - * threads. - */ - GIT_FEATURE_THREADS = (1 << 0), - /** - * If set, libgit2 was built with and linked against a TLS implementation. - * Custom TLS streams may still be added by the user to support HTTPS - * regardless of this. - */ - GIT_FEATURE_HTTPS = (1 << 1), - /** - * If set, libgit2 was built with and linked against libssh2. A custom - * transport may still be added by the user to support libssh2 regardless of - * this. - */ - GIT_FEATURE_SSH = (1 << 2), - /** - * If set, libgit2 was built with support for sub-second resolution in file - * modification times. - */ - GIT_FEATURE_NSEC = (1 << 3) + /** + * libgit2 is thread-aware and can be used from multiple threads + * (as described in the documentation). + */ + GIT_FEATURE_THREADS = (1 << 0), + + /** HTTPS remotes */ + GIT_FEATURE_HTTPS = (1 << 1), + + /** SSH remotes */ + GIT_FEATURE_SSH = (1 << 2), + + /** Sub-second resolution in index timestamps */ + GIT_FEATURE_NSEC = (1 << 3), + + /** HTTP parsing; always available */ + GIT_FEATURE_HTTP_PARSER = (1 << 4), + + /** Regular expression support; always available */ + GIT_FEATURE_REGEX = (1 << 5), + + /** Internationalization support for filename translation */ + GIT_FEATURE_I18N = (1 << 6), + + /** NTLM support over HTTPS */ + GIT_FEATURE_AUTH_NTLM = (1 << 7), + + /** Kerberos (SPNEGO) authentication support over HTTPS */ + GIT_FEATURE_AUTH_NEGOTIATE = (1 << 8), + + /** zlib support; always available */ + GIT_FEATURE_COMPRESSION = (1 << 9), + + /** SHA1 object support; always available */ + GIT_FEATURE_SHA1 = (1 << 10), + + /** SHA256 object support */ + GIT_FEATURE_SHA256 = (1 << 11) } git_feature_t; /** * Query compile time options for libgit2. * * @return A combination of GIT_FEATURE_* values. + */ +GIT_EXTERN(int) git_libgit2_features(void); + +/** + * Query the backend details for the compile-time feature in libgit2. * - * - GIT_FEATURE_THREADS - * Libgit2 was compiled with thread support. Note that thread support is - * still to be seen as a 'work in progress' - basic object lookups are - * believed to be threadsafe, but other operations may not be. + * This will return the "backend" for the feature, which is useful for + * things like HTTPS or SSH support, that can have multiple backends + * that could be compiled in. * - * - GIT_FEATURE_HTTPS - * Libgit2 supports the https:// protocol. This requires the openssl - * library to be found when compiling libgit2. + * For example, when libgit2 is compiled with dynamic OpenSSL support, + * the feature backend will be `openssl-dynamic`. The feature backend + * names reflect the compilation options specified to the build system + * (though in all lower case). The backend _may_ be "builtin" for + * features that are provided by libgit2 itself. * - * - GIT_FEATURE_SSH - * Libgit2 supports the SSH protocol for network operations. This requires - * the libssh2 library to be found when compiling libgit2 + * If the feature is not supported by the library, this API returns + * `NULL`. * - * - GIT_FEATURE_NSEC - * Libgit2 supports the sub-second resolution in file modification times. + * @param feature the feature to query details for + * @return the provider details, or NULL if the feature is not supported */ -GIT_EXTERN(int) git_libgit2_features(void); +GIT_EXTERN(const char *) git_libgit2_feature_backend( + git_feature_t feature); /** * Global library options diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 1375d87afc3..de72cfe7d2b 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -92,6 +92,177 @@ int git_libgit2_features(void) #endif #ifdef GIT_USE_NSEC | GIT_FEATURE_NSEC +#endif + | GIT_FEATURE_HTTP_PARSER + | GIT_FEATURE_REGEX +#ifdef GIT_USE_ICONV + | GIT_FEATURE_I18N +#endif +#if defined(GIT_NTLM) || defined(GIT_WIN32) + | GIT_FEATURE_AUTH_NTLM +#endif +#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) + | GIT_FEATURE_AUTH_NEGOTIATE +#endif + | GIT_FEATURE_COMPRESSION + | GIT_FEATURE_SHA1 +#ifdef GIT_EXPERIMENTAL_SHA256 + | GIT_FEATURE_SHA256 #endif ; } + +const char *git_libgit2_feature_backend(git_feature_t feature) +{ + switch (feature) { + case GIT_FEATURE_THREADS: +#if defined(GIT_THREADS) && defined(GIT_WIN32) + return "win32"; +#elif defined(GIT_THREADS) + return "pthread"; +#endif + break; + + case GIT_FEATURE_HTTPS: +#if defined(GIT_HTTPS) && defined(GIT_OPENSSL) + return "openssl"; +#elif defined(GIT_HTTPS) && defined(GIT_OPENSSL_DYNAMIC) + return "openssl-dynamic"; +#elif defined(GIT_HTTPS) && defined(GIT_MBEDTLS) + return "mbedtls"; +#elif defined(GIT_HTTPS) && defined(GIT_SECURE_TRANSPORT) + return "securetransport"; +#elif defined(GIT_HTTPS) && defined(GIT_SCHANNEL) + return "schannel"; +#elif defined(GIT_HTTPS) && defined(GIT_WINHTTP) + return "winhttp"; +#elif defined(GIT_HTTPS) + GIT_ASSERT_WITH_RETVAL(!"Unknown HTTPS backend", NULL); +#endif + break; + + case GIT_FEATURE_SSH: +#if defined(GIT_SSH_EXEC) + return "exec"; +#elif defined(GIT_SSH_LIBSSH2) + return "libssh2"; +#elif defined(GIT_SSH) + GIT_ASSERT_WITH_RETVAL(!"Unknown SSH backend", NULL); +#endif + break; + + case GIT_FEATURE_NSEC: +#if defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIMESPEC) + return "mtimespec"; +#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIM) + return "mtim"; +#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIME_NSEC) + return "mtime"; +#elif defined(GIT_USE_NSEC) && defined(GIT_WIN32) + return "win32"; +#elif defined(GIT_USE_NSEC) + GIT_ASSERT_WITH_RETVAL(!"Unknown high-resolution time backend", NULL); +#endif + break; + + case GIT_FEATURE_HTTP_PARSER: +#if defined(GIT_HTTPPARSER_HTTPPARSER) + return "httpparser"; +#elif defined(GIT_HTTPPARSER_LLHTTP) + return "llhttp"; +#elif defined(GIT_HTTPPARSER_BUILTIN) + return "builtin"; +#endif + GIT_ASSERT_WITH_RETVAL(!"Unknown HTTP parser backend", NULL); + break; + + case GIT_FEATURE_REGEX: +#if defined(GIT_REGEX_REGCOMP_L) + return "regcomp_l"; +#elif defined(GIT_REGEX_REGCOMP) + return "regcomp"; +#elif defined(GIT_REGEX_PCRE) + return "pcre"; +#elif defined(GIT_REGEX_PCRE2) + return "pcre2"; +#elif defined(GIT_REGEX_BUILTIN) + return "builtin"; +#endif + GIT_ASSERT_WITH_RETVAL(!"Unknown regular expression backend", NULL); + break; + + case GIT_FEATURE_I18N: +#if defined(GIT_USE_ICONV) + return "iconv"; +#endif + break; + + case GIT_FEATURE_AUTH_NTLM: +#if defined(GIT_NTLM) + return "ntlmclient"; +#elif defined(GIT_WIN32) + return "sspi"; +#endif + break; + + case GIT_FEATURE_AUTH_NEGOTIATE: +#if defined(GIT_GSSAPI) + return "gssapi"; +#elif defined(GIT_WIN32) + return "sspi"; +#endif + break; + + case GIT_FEATURE_COMPRESSION: +#if defined(GIT_COMPRESSION_ZLIB) + return "zlib"; +#elif defined(GIT_COMPRESSION_BUILTIN) + return "builtin"; +#else + GIT_ASSERT_WITH_RETVAL(!"Unknown compression backend", NULL); +#endif + break; + + case GIT_FEATURE_SHA1: +#if defined(GIT_SHA1_COLLISIONDETECT) + return "builtin"; +#elif defined(GIT_SHA1_OPENSSL) + return "openssl"; +#elif defined(GIT_SHA1_OPENSSL_FIPS) + return "openssl-fips"; +#elif defined(GIT_SHA1_OPENSSL_DYNAMIC) + return "openssl-dynamic"; +#elif defined(GIT_SHA1_MBEDTLS) + return "mbedtls"; +#elif defined(GIT_SHA1_COMMON_CRYPTO) + return "commoncrypto"; +#elif defined(GIT_SHA1_WIN32) + return "win32"; +#else + GIT_ASSERT_WITH_RETVAL(!"Unknown SHA1 backend", NULL); +#endif + break; + + case GIT_FEATURE_SHA256: +#if defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_BUILTIN) + return "builtin"; +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL) + return "openssl"; +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_FIPS) + return "openssl-fips"; +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_DYNAMIC) + return "openssl-dynamic"; +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_MBEDTLS) + return "mbedtls"; +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_COMMON_CRYPTO) + return "commoncrypto"; +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_WIN32) + return "win32"; +#elif defined(GIT_EXPERIMENTAL_SHA256) + GIT_ASSERT_WITH_RETVAL(!"Unknown SHA256 backend", NULL); +#endif + break; + } + + return NULL; +} diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 366eea1a34d..b7cd6014a57 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -25,4 +25,202 @@ void test_core_features__basic(void) #else cl_assert((caps & GIT_FEATURE_NSEC) == 0); #endif + + cl_assert((caps & GIT_FEATURE_HTTP_PARSER) != 0); + cl_assert((caps & GIT_FEATURE_REGEX) != 0); + +#if defined(GIT_USE_ICONV) + cl_assert((caps & GIT_FEATURE_I18N) != 0); +#endif + +#if defined(GIT_NTLM) || defined(GIT_WIN32) + cl_assert((caps & GIT_FEATURE_AUTH_NTLM) != 0); +#endif +#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) + cl_assert((caps & GIT_FEATURE_AUTH_NEGOTIATE) != 0); +#endif + + cl_assert((caps & GIT_FEATURE_COMPRESSION) != 0); + cl_assert((caps & GIT_FEATURE_SHA1) != 0); + +#if defined(GIT_EXPERIMENTAL_SHA256) + cl_assert((caps & GIT_FEATURE_SHA256) != 0); +#endif + + /* + * Ensure that our tests understand all the features; + * this test tries to ensure that if there's a new feature + * added that the backends test (below) is updated as well. + */ + cl_assert((caps & ~(GIT_FEATURE_THREADS | + GIT_FEATURE_HTTPS | + GIT_FEATURE_SSH | + GIT_FEATURE_NSEC | + GIT_FEATURE_HTTP_PARSER | + GIT_FEATURE_REGEX | + GIT_FEATURE_I18N | + GIT_FEATURE_AUTH_NTLM | + GIT_FEATURE_AUTH_NEGOTIATE | + GIT_FEATURE_COMPRESSION | + GIT_FEATURE_SHA1 | + GIT_FEATURE_SHA256 + )) == 0); +} + +void test_core_features__backends(void) +{ + const char *threads = git_libgit2_feature_backend(GIT_FEATURE_THREADS); + const char *https = git_libgit2_feature_backend(GIT_FEATURE_HTTPS); + const char *ssh = git_libgit2_feature_backend(GIT_FEATURE_SSH); + const char *nsec = git_libgit2_feature_backend(GIT_FEATURE_NSEC); + const char *http_parser = git_libgit2_feature_backend(GIT_FEATURE_HTTP_PARSER); + const char *regex = git_libgit2_feature_backend(GIT_FEATURE_REGEX); + const char *i18n = git_libgit2_feature_backend(GIT_FEATURE_I18N); + const char *ntlm = git_libgit2_feature_backend(GIT_FEATURE_AUTH_NTLM); + const char *negotiate = git_libgit2_feature_backend(GIT_FEATURE_AUTH_NEGOTIATE); + const char *compression = git_libgit2_feature_backend(GIT_FEATURE_COMPRESSION); + const char *sha1 = git_libgit2_feature_backend(GIT_FEATURE_SHA1); + const char *sha256 = git_libgit2_feature_backend(GIT_FEATURE_SHA256); + +#if defined(GIT_THREADS) && defined(GIT_WIN32) + cl_assert_equal_s("win32", threads); +#elif defined(GIT_THREADS) + cl_assert_equal_s("pthread", threads); +#else + cl_assert(threads == NULL); +#endif + +#if defined(GIT_HTTPS) && defined(GIT_OPENSSL) + cl_assert_equal_s("openssl", https); +#elif defined(GIT_HTTPS) && defined(GIT_OPENSSL_DYNAMIC) + cl_assert_equal_s("openssl-dynamic", https); +#elif defined(GIT_HTTPS) && defined(GIT_MBEDTLS) + cl_assert_equal_s("mbedtls", https); +#elif defined(GIT_HTTPS) && defined(GIT_SECURE_TRANSPORT) + cl_assert_equal_s("securetransport", https); +#elif defined(GIT_HTTPS) && defined(GIT_SCHANNEL) + cl_assert_equal_s("schannel", https); +#elif defined(GIT_HTTPS) && defined(GIT_WINHTTP) + cl_assert_equal_s("winhttp", https); +#elif defined(GIT_HTTPS) + cl_assert(0); +#else + cl_assert(https == NULL); +#endif + +#if defined(GIT_SSH) && defined(GIT_SSH_EXEC) + cl_assert_equal_s("exec", ssh); +#elif defined(GIT_SSH) && defined(GIT_SSH_LIBSSH2) + cl_assert_equal_s("libssh2", ssh); +#elif defined(GIT_SSH) + cl_assert(0); +#else + cl_assert(ssh == NULL); +#endif + +#if defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIMESPEC) + cl_assert_equal_s("mtimespec", nsec); +#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIM) + cl_assert_equal_s("mtim", nsec); +#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIME_NSEC) + cl_assert_equal_s("mtime", nsec); +#elif defined(GIT_USE_NSEC) && defined(GIT_WIN32) + cl_assert_equal_s("win32", nsec); +#elif defined(GIT_USE_NSEC) + cl_assert(0); +#else + cl_assert(nsec == NULL); +#endif + +#if defined(GIT_HTTPPARSER_HTTPPARSER) + cl_assert_equal_s("httpparser", http_parser); +#elif defined(GIT_HTTPPARSER_LLHTTP) + cl_assert_equal_s("llhttp", http_parser); +#elif defined(GIT_HTTPPARSER_BUILTIN) + cl_assert_equal_s("builtin", http_parser); +#else + cl_assert(0); +#endif + +#if defined(GIT_REGEX_REGCOMP_L) + cl_assert_equal_s("regcomp_l", regex); +#elif defined(GIT_REGEX_REGCOMP) + cl_assert_equal_s("regcomp", regex); +#elif defined(GIT_REGEX_PCRE) + cl_assert_equal_s("pcre", regex); +#elif defined(GIT_REGEX_PCRE2) + cl_assert_equal_s("pcre2", regex); +#elif defined(GIT_REGEX_BUILTIN) + cl_assert_equal_s("builtin", regex); +#else + cl_assert(0); +#endif + +#if defined(GIT_USE_ICONV) + cl_assert_equal_s("iconv", i18n); +#else + cl_assert(i18n == NULL); +#endif + +#if defined(GIT_NTLM) + cl_assert_equal_s("ntlmclient", ntlm); +#elif defined(GIT_WIN32) + cl_assert_equal_s("sspi", ntlm); +#else + cl_assert(ntlm == NULL); +#endif + +#if defined(GIT_GSSAPI) + cl_assert_equal_s("gssapi", negotiate); +#elif defined(GIT_WIN32) + cl_assert_equal_s("sspi", negotiate); +#else + cl_assert(negotiate == NULL); +#endif + +#if defined(GIT_COMPRESSION_BUILTIN) + cl_assert_equal_s("builtin", compression); +#elif defined(GIT_COMPRESSION_ZLIB) + cl_assert_equal_s("zlib", compression); +#else + cl_assert(0); +#endif + +#if defined(GIT_SHA1_COLLISIONDETECT) + cl_assert_equal_s("builtin", sha1); +#elif defined(GIT_SHA1_OPENSSL) + cl_assert_equal_s("openssl", sha1); +#elif defined(GIT_SHA1_OPENSSL_FIPS) + cl_assert_equal_s("openssl-fips", sha1); +#elif defined(GIT_SHA1_OPENSSL_DYNAMIC) + cl_assert_equal_s("openssl-dynamic", sha1); +#elif defined(GIT_SHA1_MBEDTLS) + cl_assert_equal_s("mbedtls", sha1); +#elif defined(GIT_SHA1_COMMON_CRYPTO) + cl_assert_equal_s("commoncrypto", sha1); +#elif defined(GIT_SHA1_WIN32) + cl_assert_equal_s("win32", sha1); +#else + cl_assert(0); +#endif + +#if defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_BUILTIN) + cl_assert_equal_s("builtin", sha256); +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL) + cl_assert_equal_s("openssl", sha256); +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_FIPS) + cl_assert_equal_s("openssl-fips", sha256); +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_DYNAMIC) + cl_assert_equal_s("openssl-dynamic", sha256); +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_MBEDTLS) + cl_assert_equal_s("mbedtls", sha256); +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_COMMON_CRYPTO) + cl_assert_equal_s("commoncrypto", sha256); +#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_WIN32) + cl_assert_equal_s("win32", sha256); +#elif defined(GIT_EXPERIMENTAL_SHA256) + cl_assert(0); +#else + cl_assert(sha256 == NULL); +#endif } From bed00cd032271c14ba5675aebdee3286683a1ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Sun, 22 Dec 2024 23:32:23 +0100 Subject: [PATCH 742/816] smart: ignore shallow/unshallow packets during ACK processing In RPC mode (https), the client sends its list of shallow commits at the beginning of each request during packfile negotiation, so that the remote endpoint keeps context. This causes the remote to prepend appropriate shallow/unshallow packets to each response sent back to the client. However, the store_common() helper function (used in multi_ack mode) does not cater for this, returning as soon as it encounters any packet different than an ACK packet and therefore leaving the rest of the HTTP buffer unprocessed. This in turn causes subsequent iterations of the while loop processing ACK packets to process data returned by older HTTP requests instead of the current one, messing up the packfile negotiation process. Given that the wait_while_ack() helper function (called after the client signals to the remote that it is ready to receive packfile data) correctly skips over shallow/unshallow packets, packfile contents can still be received successfully in some cases (depending on message framing); in some other ones, though (particularly when git_smart__download_pack() processes an HTTP buffer starting with shallow/unshallow packets), the fetching process fails with an "incomplete pack header" error due to the flush packet terminating a set of shallow/unshallow packets being incorrectly interpreted as the flush packet indicating the end of the packfile (making the code behave as if no packfile data was sent by the remote). Fix by ignoring shallow/unshallow packets in the store_common() helper function, therefore making the ACK processing logic work on the correct HTTP buffers and ensuring that git_smart__download_pack() is not called until packfile negotiation is actually finished. --- src/libgit2/transports/smart_protocol.c | 7 ++++ tests/libgit2/online/shallow.c | 46 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index b35b33b4347..87c1904589d 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -317,6 +317,13 @@ static int store_common(transport_smart *t) if ((error = recv_pkt(&pkt, NULL, t)) < 0) return error; + if (t->rpc && (pkt->type == GIT_PKT_SHALLOW || + pkt->type == GIT_PKT_UNSHALLOW || + pkt->type == GIT_PKT_FLUSH)) { + git__free(pkt); + continue; + } + if (pkt->type != GIT_PKT_ACK) { git__free(pkt); return 0; diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c index d7038cdd2dc..a5508c16d45 100644 --- a/tests/libgit2/online/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -165,6 +165,52 @@ void test_online_shallow__unshallow(void) git_repository_free(repo); } +void test_online_shallow__deepen_full(void) +{ + git_str path = GIT_STR_INIT; + git_repository *repo; + git_revwalk *walk; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + git_remote *origin = NULL; + git_oid oid; + git_oid *roots; + size_t roots_len; + size_t num_commits = 0; + int error = 0; + + clone_opts.fetch_opts.depth = 7; + clone_opts.remote_cb = remote_single_branch; + + git_str_joinpath(&path, clar_sandbox_path(), "deepen_full"); + cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + fetch_opts.depth = 8; + cl_git_pass(git_remote_lookup(&origin, repo, "origin")); + cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL)); + cl_assert_equal_b(false, git_repository_is_shallow(repo)); + + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(0, roots_len); + + git_revwalk_new(&walk, repo); + git_revwalk_push_head(walk); + + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + + cl_assert_equal_i(num_commits, 21); + cl_assert_equal_i(error, GIT_ITEROVER); + + git__free(roots); + git_remote_free(origin); + git_str_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +} + void test_online_shallow__deepen_six(void) { git_str path = GIT_STR_INIT; From 67900a0fcb6be70914eef14587279c2aa43a39a0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 23 Dec 2024 09:47:03 +0000 Subject: [PATCH 743/816] options: update X509 cert constant By placing the X509 cert constant option in the middle of the existing options, it renumbers everything unnecessarily. Move it to the end in to avoid breaking changes. --- include/git2/common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 006f7eeb1e1..40a3903ce72 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -225,7 +225,6 @@ typedef enum { GIT_OPT_GET_TEMPLATE_PATH, GIT_OPT_SET_TEMPLATE_PATH, GIT_OPT_SET_SSL_CERT_LOCATIONS, - GIT_OPT_ADD_SSL_X509_CERT, GIT_OPT_SET_USER_AGENT, GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, @@ -257,7 +256,8 @@ typedef enum { GIT_OPT_SET_SERVER_TIMEOUT, GIT_OPT_GET_SERVER_TIMEOUT, GIT_OPT_SET_USER_AGENT_PRODUCT, - GIT_OPT_GET_USER_AGENT_PRODUCT + GIT_OPT_GET_USER_AGENT_PRODUCT, + GIT_OPT_ADD_SSL_X509_CERT } git_libgit2_opt_t; /** From 53c14952baca9d1f20455c4552732dcfed58a60a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 23 Dec 2024 16:11:52 +0000 Subject: [PATCH 744/816] docs: properly parse enum values For enum values that are constructed, not literal integers, we need to parse the inner / implicit expression. For example: ``` GIT_DIFF_REVERSE = (1u << 0) ``` --- script/api-docs/api-generator.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/script/api-docs/api-generator.js b/script/api-docs/api-generator.js index 5204f491f0e..47c928acf01 100755 --- a/script/api-docs/api-generator.js +++ b/script/api-docs/api-generator.js @@ -652,12 +652,23 @@ function parseEnum(location, decl, options) { ensure('enum constant has a name', member.name); const explicitValue = single(member.inner, (attr => attr.kind === 'ConstantExpr')); + const implicitValue = single(member.inner, (attr => attr.kind === 'ImplicitCastExpr')); const commentText = single(member.inner, (attr => attr.kind === 'FullComment')); const commentData = commentText ? parseComment(`enum:${decl.name}:member:${member.name}`, location, commentText, options) : undefined; + let value = undefined; + + if (explicitValue && explicitValue.value) { + value = explicitValue.value; + } else if (implicitValue) { + const innerExplicit = single(implicitValue.inner, (attr => attr.kind === 'ConstantExpr')); + + value = innerExplicit?.value; + } + result.members.push({ name: member.name, - value: explicitValue ? explicitValue.value : undefined, + value: value, ...commentData }); } From 5d6e679e21466a517e7a7bf787f574bcf72a54df Mon Sep 17 00:00:00 2001 From: bmarques1995 Date: Mon, 23 Dec 2024 20:27:40 -0300 Subject: [PATCH 745/816] Rebase --- src/cli/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 7456daa7570..d121c588a6c 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -53,4 +53,4 @@ if(MSVC_IDE) set_source_files_properties(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h") endif() -install(TARGETS git2_cli EXPORT ${LIBGIT2_TARGETS_EXPORT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(TARGETS git2_cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) From 83994dafec424346b9f5752fd7a44bd95b9598cd Mon Sep 17 00:00:00 2001 From: Ryan Pham Date: Tue, 24 Dec 2024 10:39:27 +0900 Subject: [PATCH 746/816] remote: Remove unnecessary call `git_refspec_is_negative()` is already called by `git_refspec_src_matches_negative()`, so should not be necessary here. --- src/libgit2/remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 5d87d420785..c5b764d1595 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2635,7 +2635,7 @@ git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refnam if (spec->push) continue; - if (git_refspec_is_negative(spec) && git_refspec_src_matches_negative(spec, refname)) + if (git_refspec_src_matches_negative(spec, refname)) return NULL; if (git_refspec_src_matches(spec, refname)) From 6039d28d435faf6ce11f97956805f96f8a1fb94f Mon Sep 17 00:00:00 2001 From: Ryan Pham Date: Tue, 24 Dec 2024 10:40:37 +0900 Subject: [PATCH 747/816] remote: Return first matching refspec The previous behavior was to return the first match, so this reverts the clobbering behavior that was introduced in f7f30ec136907a2aad5e58ba95081ac94fe6aba6. --- src/libgit2/remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index c5b764d1595..92c5043b811 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2638,7 +2638,7 @@ git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refnam if (git_refspec_src_matches_negative(spec, refname)) return NULL; - if (git_refspec_src_matches(spec, refname)) + if (git_refspec_src_matches(spec, refname) && match == NULL) match = spec; } From 099e62ca03198b25e5b37445511d023bd6884178 Mon Sep 17 00:00:00 2001 From: Ryan Pham Date: Tue, 24 Dec 2024 10:42:56 +0900 Subject: [PATCH 748/816] remote: Don't use designated initializer --- tests/libgit2/remote/fetch.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/libgit2/remote/fetch.c b/tests/libgit2/remote/fetch.c index a24f09925ac..6b7cec923f0 100644 --- a/tests/libgit2/remote/fetch.c +++ b/tests/libgit2/remote/fetch.c @@ -205,10 +205,7 @@ static void do_fetch_repo_with_ref_matching_negative_refspec(git_oid *commit1id) /* fetch the remote with negative refspec for references prefixed with '_' */ { char *refspec_strs = { NEGATIVE_SPEC }; - git_strarray refspecs = { - .count = 1, - .strings = &refspec_strs, - }; + git_strarray refspecs = { &refspec_strs, 1 }; git_remote *remote; From 0c27a85b41051ca059c330193bce8c3a34578d1e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Dec 2024 16:20:11 +0000 Subject: [PATCH 749/816] repo: don't require option when `template_path` is specified When a `template_path` is explicitly specified, don't _also_ require an option to indicate that we should use templates. We, obviously, should. --- src/libgit2/repository.c | 3 ++- tests/libgit2/repo/template.c | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 82aea517a1c..ae6a1a5f441 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -2538,7 +2538,8 @@ static int repo_init_structure( int error = 0; repo_template_item *tpl; bool external_tpl = - ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0); + opts->template_path != NULL || + (opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0; mode_t dmode = pick_dir_mode(opts); bool chmod = opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK; diff --git a/tests/libgit2/repo/template.c b/tests/libgit2/repo/template.c index e8fe266cfc3..2b1ecf88c4a 100644 --- a/tests/libgit2/repo/template.c +++ b/tests/libgit2/repo/template.c @@ -228,8 +228,7 @@ void test_repo_template__extended_with_template_and_shared_mode(void) const char *repo_path; int filemode; - opts.flags = GIT_REPOSITORY_INIT_MKPATH | - GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE; + opts.flags = GIT_REPOSITORY_INIT_MKPATH; opts.template_path = "template"; opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP; From a844a6cf2301b32c7ac52619368d75573fd3cd4f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Dec 2024 15:32:29 +0000 Subject: [PATCH 750/816] repo: put a newline on the .git link file The `.git` file, when containing a `gitdir: ` link, should be suffixed with a trailing newline. --- src/libgit2/repository.c | 2 +- tests/libgit2/repo/init.c | 4 ++-- tests/libgit2/repo/setters.c | 2 +- tests/libgit2/submodule/add.c | 2 +- tests/libgit2/submodule/repository_init.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 82aea517a1c..d92fe62ffdd 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -2506,7 +2506,7 @@ static int repo_write_gitlink( error = git_fs_path_make_relative(&path_to_repo, in_dir); if (!error) - error = git_str_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr); + error = git_str_printf(&buf, "%s %s\n", GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr); if (!error) error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr); diff --git a/tests/libgit2/repo/init.c b/tests/libgit2/repo/init.c index 446ab735e4e..e23271d350d 100644 --- a/tests/libgit2/repo/init.c +++ b/tests/libgit2/repo/init.c @@ -489,7 +489,7 @@ void test_repo_init__relative_gitdir(void) /* Verify gitlink */ cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git")); - cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr); + cl_assert_equal_s("gitdir: ../my_repository/\n", dot_git_content.ptr); git_str_dispose(&dot_git_content); cleanup_repository("root"); @@ -526,7 +526,7 @@ void test_repo_init__relative_gitdir_2(void) /* Verify gitlink */ cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git")); - cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr); + cl_assert_equal_s("gitdir: ../my_repository/\n", dot_git_content.ptr); git_str_dispose(&dot_git_content); cleanup_repository("root"); diff --git a/tests/libgit2/repo/setters.c b/tests/libgit2/repo/setters.c index 5c91ed39005..1ad38bb8b80 100644 --- a/tests/libgit2/repo/setters.c +++ b/tests/libgit2/repo/setters.c @@ -56,7 +56,7 @@ void test_repo_setters__setting_a_workdir_creates_a_gitlink(void) cl_git_pass(git_futils_readbuffer(&content, "./new_workdir/.git")); cl_assert(git__prefixcmp(git_str_cstr(&content), "gitdir: ") == 0); - cl_assert(git__suffixcmp(git_str_cstr(&content), "testrepo.git/") == 0); + cl_assert(git__suffixcmp(git_str_cstr(&content), "testrepo.git/\n") == 0); git_str_dispose(&content); cl_git_pass(git_repository_config(&cfg, repo)); diff --git a/tests/libgit2/submodule/add.c b/tests/libgit2/submodule/add.c index a2a66e7f549..5208c7fcaa5 100644 --- a/tests/libgit2/submodule/add.c +++ b/tests/libgit2/submodule/add.c @@ -60,7 +60,7 @@ void test_submodule_add__url_absolute(void) /* Verify gitdir path is relative */ cl_git_pass(git_futils_readbuffer(&dot_git_content, "submod2/" "sm_libgit2" "/.git")); - cl_assert_equal_s("gitdir: ../.git/modules/sm_libgit2/", dot_git_content.ptr); + cl_assert_equal_s("gitdir: ../.git/modules/sm_libgit2/\n", dot_git_content.ptr); git_repository_free(repo); git_str_dispose(&dot_git_content); diff --git a/tests/libgit2/submodule/repository_init.c b/tests/libgit2/submodule/repository_init.c index 39b55c403df..f24ec1d2406 100644 --- a/tests/libgit2/submodule/repository_init.c +++ b/tests/libgit2/submodule/repository_init.c @@ -24,7 +24,7 @@ void test_submodule_repository_init__basic(void) /* Verify gitlink */ cl_git_pass(git_futils_readbuffer(&dot_git_content, "submod2/" "sm_gitmodules_only" "/.git")); - cl_assert_equal_s("gitdir: ../.git/modules/sm_gitmodules_only/", dot_git_content.ptr); + cl_assert_equal_s("gitdir: ../.git/modules/sm_gitmodules_only/\n", dot_git_content.ptr); cl_assert(git_fs_path_isfile("submod2/" "sm_gitmodules_only" "/.git")); From bf5f0b560060d067c783f81ec7e27eac82522d18 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Dec 2024 16:50:26 +0000 Subject: [PATCH 751/816] cli: add an `init` command --- src/cli/cmd.h | 1 + src/cli/cmd_init.c | 102 +++++++++++++++++++++++++++++++++++++++++++++ src/cli/main.c | 1 + 3 files changed, 104 insertions(+) create mode 100644 src/cli/cmd_init.c diff --git a/src/cli/cmd.h b/src/cli/cmd.h index 5ac67f52615..194a0b5058d 100644 --- a/src/cli/cmd.h +++ b/src/cli/cmd.h @@ -32,5 +32,6 @@ extern int cmd_config(int argc, char **argv); extern int cmd_hash_object(int argc, char **argv); extern int cmd_help(int argc, char **argv); extern int cmd_index_pack(int argc, char **argv); +extern int cmd_init(int argc, char **argv); #endif /* CLI_cmd_h__ */ diff --git a/src/cli/cmd_init.c b/src/cli/cmd_init.c new file mode 100644 index 00000000000..b6468961ee2 --- /dev/null +++ b/src/cli/cmd_init.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include "common.h" +#include "cmd.h" +#include "error.h" +#include "sighandler.h" +#include "progress.h" + +#include "fs_path.h" +#include "futils.h" + +#define COMMAND_NAME "init" + +static char *branch, *git_dir, *template_dir, *path; +static int quiet, bare; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, + + { CLI_OPT_TYPE_SWITCH, "quiet", 'q', &quiet, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "quiet mode; don't display informational messages" }, + { CLI_OPT_TYPE_SWITCH, "bare", 0, &bare, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "don't create a working directory" }, + { CLI_OPT_TYPE_VALUE, "initial-branch", 'b', &branch, 0, + CLI_OPT_USAGE_DEFAULT, "name", "initial branch name" }, + { CLI_OPT_TYPE_VALUE, "separate-git-dir", 0, &git_dir, 0, + CLI_OPT_USAGE_DEFAULT, "git-dir", "path to separate git directory" }, + { CLI_OPT_TYPE_VALUE, "template", 0, &template_dir, 0, + CLI_OPT_USAGE_DEFAULT, "template-dir", "path to git directory templates" }, + { CLI_OPT_TYPE_LITERAL }, + { CLI_OPT_TYPE_ARG, "directory", 0, &path, 0, + CLI_OPT_USAGE_DEFAULT, "directory", "directory to create repository in" }, + { 0 } +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); + printf("\n"); + + printf("Create a new git repository.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +int cmd_init(int argc, char **argv) +{ + git_repository *repo = NULL; + git_repository_init_options init_opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; + cli_opt invalid_opt; + const char *repo_path; + int ret = 0; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (cli_opt__show_help) { + print_help(); + return 0; + } + + init_opts.flags |= GIT_REPOSITORY_INIT_MKPATH | + GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE; + + if (bare && git_dir) + return cli_error_usage("the '--bare' and '--separate-git-dir' options cannot be used together"); + + if (bare) + init_opts.flags |= GIT_REPOSITORY_INIT_BARE; + + init_opts.template_path = template_dir; + init_opts.initial_head = branch; + + if (git_dir) { + init_opts.flags |= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; + init_opts.workdir_path = path; + + repo_path = git_dir; + } else { + repo_path = path; + } + + if (git_repository_init_ext(&repo, repo_path, &init_opts) < 0) { + ret = cli_error_git(); + } else if (!quiet) { + printf("Initialized empty Git repository in %s\n", + git_repository_path(repo)); + } + + git_repository_free(repo); + return ret; +} diff --git a/src/cli/main.c b/src/cli/main.c index 1cc8dd3e20a..be913ba64ec 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -37,6 +37,7 @@ const cli_cmd_spec cli_cmds[] = { { "hash-object", cmd_hash_object, "Hash a raw object and product its object ID" }, { "help", cmd_help, "Display help information" }, { "index-pack", cmd_index_pack, "Create an index for a packfile" }, + { "init", cmd_init, "Create a new git repository" }, { NULL } }; From 9f61001ad577ecca9d3dfbac5698eaff1453fc00 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Dec 2024 16:50:39 +0000 Subject: [PATCH 752/816] cli: improve option help --- src/cli/opt_usage.c | 107 ++++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/src/cli/opt_usage.c b/src/cli/opt_usage.c index ecb4f146198..b887509d7c2 100644 --- a/src/cli/opt_usage.c +++ b/src/cli/opt_usage.c @@ -8,32 +8,81 @@ #include "common.h" #include "str.h" -static int print_spec_name(git_str *out, const cli_opt_spec *spec) +#define is_switch_or_value(spec) \ + ((spec)->type == CLI_OPT_TYPE_SWITCH || \ + (spec)->type == CLI_OPT_TYPE_VALUE) + +static int print_spec_args(git_str *out, const cli_opt_spec *spec) { - if (spec->type == CLI_OPT_TYPE_VALUE && spec->alias && - !(spec->usage & CLI_OPT_USAGE_VALUE_OPTIONAL) && - !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) - return git_str_printf(out, "-%c <%s>", spec->alias, spec->value_name); - if (spec->type == CLI_OPT_TYPE_VALUE && spec->alias && - !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) - return git_str_printf(out, "-%c [<%s>]", spec->alias, spec->value_name); - if (spec->type == CLI_OPT_TYPE_VALUE && - !(spec->usage & CLI_OPT_USAGE_VALUE_OPTIONAL)) - return git_str_printf(out, "--%s[=<%s>]", spec->name, spec->value_name); - if (spec->type == CLI_OPT_TYPE_VALUE) - return git_str_printf(out, "--%s=<%s>", spec->name, spec->value_name); + GIT_ASSERT(!is_switch_or_value(spec)); + if (spec->type == CLI_OPT_TYPE_ARG) return git_str_printf(out, "<%s>", spec->value_name); if (spec->type == CLI_OPT_TYPE_ARGS) return git_str_printf(out, "<%s>...", spec->value_name); if (spec->type == CLI_OPT_TYPE_LITERAL) return git_str_printf(out, "--"); - if (spec->alias && !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) + + GIT_ASSERT(!"unknown option spec type"); + return -1; +} + +GIT_INLINE(int) print_spec_alias(git_str *out, const cli_opt_spec *spec) +{ + GIT_ASSERT(is_switch_or_value(spec) && spec->alias); + + if (spec->type == CLI_OPT_TYPE_VALUE && + !(spec->usage & CLI_OPT_USAGE_VALUE_OPTIONAL)) + return git_str_printf(out, "-%c <%s>", spec->alias, spec->value_name); + else if (spec->type == CLI_OPT_TYPE_VALUE) + return git_str_printf(out, "-%c [<%s>]", spec->alias, spec->value_name); + else return git_str_printf(out, "-%c", spec->alias); - if (spec->name) +} + +GIT_INLINE(int) print_spec_name(git_str *out, const cli_opt_spec *spec) +{ + GIT_ASSERT(is_switch_or_value(spec) && spec->name); + + if (spec->type == CLI_OPT_TYPE_VALUE && + !(spec->usage & CLI_OPT_USAGE_VALUE_OPTIONAL)) + return git_str_printf(out, "--%s=<%s>", spec->name, spec->value_name); + else if (spec->type == CLI_OPT_TYPE_VALUE) + return git_str_printf(out, "--%s[=<%s>]", spec->name, spec->value_name); + else return git_str_printf(out, "--%s", spec->name); +} + +GIT_INLINE(int) print_spec_full(git_str *out, const cli_opt_spec *spec) +{ + int error = 0; + + if (is_switch_or_value(spec)) { + if (spec->alias) + error |= print_spec_alias(out, spec); + + if (spec->alias && spec->name) + error |= git_str_printf(out, ", "); + + if (spec->name) + error |= print_spec_name(out, spec); + } else { + error |= print_spec_args(out, spec); + } + + return error; +} + +GIT_INLINE(int) print_spec(git_str *out, const cli_opt_spec *spec) +{ + if (is_switch_or_value(spec)) { + if (spec->alias && !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) + return print_spec_alias(out, spec); + else + return print_spec_name(out, spec); + } - GIT_ASSERT(0); + return print_spec_args(out, spec); } /* @@ -56,7 +105,7 @@ int cli_opt_usage_fprint( int error; /* TODO: query actual console width. */ - int console_width = 80; + int console_width = 78; if ((error = git_str_printf(&usage, "usage: %s", command)) < 0) goto done; @@ -88,7 +137,7 @@ int cli_opt_usage_fprint( if (!optional && !choice && next_choice) git_str_putc(&opt, '('); - if ((error = print_spec_name(&opt, spec)) < 0) + if ((error = print_spec(&opt, spec)) < 0) goto done; if (!optional && choice && !next_choice) @@ -113,11 +162,11 @@ int cli_opt_usage_fprint( git_str_putc(&usage, ' '); linelen = prefixlen; - } else { - git_str_putc(&usage, ' '); - linelen += git_str_len(&opt) + 1; } + git_str_putc(&usage, ' '); + linelen += git_str_len(&opt) + 1; + git_str_puts(&usage, git_str_cstr(&opt)); if (git_str_oom(&usage)) { @@ -169,13 +218,13 @@ int cli_opt_help_fprint( git_str_printf(&help, " "); - if ((error = print_spec_name(&help, spec)) < 0) + if ((error = print_spec_full(&help, spec)) < 0) goto done; - if (spec->help) - git_str_printf(&help, ": %s", spec->help); - git_str_printf(&help, "\n"); + + if (spec->help) + git_str_printf(&help, " %s\n", spec->help); } /* Display the remaining arguments */ @@ -192,13 +241,13 @@ int cli_opt_help_fprint( git_str_printf(&help, " "); - if ((error = print_spec_name(&help, spec)) < 0) + if ((error = print_spec_full(&help, spec)) < 0) goto done; - if (spec->help) - git_str_printf(&help, ": %s", spec->help); - git_str_printf(&help, "\n"); + + if (spec->help) + git_str_printf(&help, " %s\n", spec->help); } if (git_str_oom(&help) || From ded949495492294a7e88ed2860d7c23cee3a1bc3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 23 Dec 2024 16:15:43 +0000 Subject: [PATCH 753/816] cmake: only add package target for libgit2 itself --- src/CMakeLists.txt | 24 ------------------- src/libgit2/CMakeLists.txt | 25 +++++++++++++++++++- src/{cmake_utils => libgit2}/config.cmake.in | 0 3 files changed, 24 insertions(+), 25 deletions(-) rename src/{cmake_utils => libgit2}/config.cmake.in (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d35c851c16e..73c46e21043 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -199,30 +199,6 @@ add_feature_info(iconv GIT_USE_ICONV "iconv encoding conversion support") # Include child projects # -set(LIBGIT2_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") -set(LIBGIT2_VERSION_CONFIG "${LIBGIT2_GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake") -set(LIBGIT2_PROJECT_CONFIG "${LIBGIT2_GENERATED_DIR}/${PROJECT_NAME}Config.cmake") -set(LIBGIT2_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") -set(LIBGIT2_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") -set(LIBGIT2_NAMESPACE "${PROJECT_NAME}::") -set(LIBGIT2_VERSION ${PROJECT_VERSION}) - -include(CMakePackageConfigHelpers) -write_basic_package_version_file( - "${LIBGIT2_VERSION_CONFIG}" VERSION ${LIBGIT2_VERSION} COMPATIBILITY SameMajorVersion -) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_utils/config.cmake.in" "${LIBGIT2_PROJECT_CONFIG}" @ONLY) - -# Install cmake config files -install( - FILES "${LIBGIT2_PROJECT_CONFIG}" "${LIBGIT2_VERSION_CONFIG}" - DESTINATION "${LIBGIT2_CONFIG_INSTALL_DIR}") - -install( - EXPORT "${LIBGIT2_TARGETS_EXPORT_NAME}" - NAMESPACE "${LIBGIT2_NAMESPACE}" - DESTINATION "${LIBGIT2_CONFIG_INSTALL_DIR}") - add_subdirectory(libgit2) add_subdirectory(util) diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index be3ee8cd2ab..a7d3c7ca400 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(libgit2 OBJECT) include(PkgBuildConfig) +include(CMakePackageConfigHelpers) set(LIBGIT2_INCLUDES "${PROJECT_BINARY_DIR}/src/util" @@ -102,10 +103,32 @@ FILE(READ "${PROJECT_SOURCE_DIR}/include/git2.h" LIBGIT2_INCLUDE) STRING(REGEX REPLACE "#include \"git2\/" "#include \"${LIBGIT2_FILENAME}/" LIBGIT2_INCLUDE "${LIBGIT2_INCLUDE}") FILE(WRITE "${PROJECT_BINARY_DIR}/include/${LIBGIT2_FILENAME}.h" ${LIBGIT2_INCLUDE}) +# cmake package targets + +set(LIBGIT2_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") + +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + +configure_file(config.cmake.in + "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake" + @ONLY) + +install(FILES + "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION "lib/cmake/${PROJECT_NAME}") +install( + EXPORT ${LIBGIT2_TARGETS_EXPORT_NAME} + NAMESPACE "${PROJECT_NAME}::" + DESTINATION "lib/cmake/${PROJECT_NAME}") + # Install install(TARGETS libgit2package - EXPORT ${LIBGIT2_TARGETS_EXPORT_NAME} + EXPORT ${LIBGIT2_TARGETS_EXPORT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/cmake_utils/config.cmake.in b/src/libgit2/config.cmake.in similarity index 100% rename from src/cmake_utils/config.cmake.in rename to src/libgit2/config.cmake.in From e96e2504460543961b750670d884a77dc7e16d54 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 23 Dec 2024 17:05:01 +0000 Subject: [PATCH 754/816] v1.9: update changelog --- docs/changelog.md | 359 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 02bad65e17c..ce524b9e74e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,362 @@ +v1.9.0 +------ + +This is release v1.9.0, "Schwibbogen". As usual, it contains numerous +bug fixes, compatibility improvements, and new features. + +This is expected to be the final release in the libgit2 v1.x lineage. +libgit2 v2.0 is expected to be the next version, with support for +SHA256 moving to "supported" status (out of "experimental" status). +This means that v2.0 will have API and ABI changes to support SHA256. + +## Major changes + +* **Documentation improvements** + We've launched a new website for our API reference docs at + https://libgit2.org/docs/reference/main/. To support this, + we've updated the documentation to ensure that all APIs are + well-documented, and added docurium-style specifiers to indicate + more depth about the API surface. + + We now also publish a JSON blob with the API structure and the + documentation that may be helpful for binding authors. + +* **TLS cipher updates** + libgit2 has updated our TLS cipher selection to match the + "compatibility" cipher suite settings as [documented by + Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS). + +* **Blame improvements** + The blame API now contains committer information and commit summaries + for blame hunks, and the ability to get information about the line of + text that was modified. In addition, a CLI blame command has been added + so that the blame functionality can be benchmarked by our benchmark + suite. + +* **SONAME changed** + libgit2 will now properly update its SONAME version information when + ABI chnages occur. We hope that by correcting this oversight, users + and distribution vendors, will be able to integrate new versions of + libgit2 more easily. + +## Breaking changes + +There are several ABI-breaking changes that integrators, particularly +maintainers of bindings or FFI users, may want to be aware of. + +* **Blame hunk structure updates** (ABI breaking change) + There are numerous additions to the `git_blame_hunk` structure to + accommodate more information about the blame process. + +* **Checkout strategy updates** (ABI breaking change) + The values for `GIT_CHECKOUT_SAFE` and `GIT_CHECKOUT_NONE` have been + updated. `GIT_CHECKOUT_SAFE` is now `0`; this was implicitly the + default value (with the options constructors setting that as the + checkout strategy). It is now the default if the checkout strategy + is set to `0`. This allows for an overall code simplification in the + library. + +* **Configuration entry member removal** (ABI breaking change) + The `git_config_entry` structure no longer contains a `free` member; + this was an oversight as end-users should not try to free that + structure. + +* **Configuration backend function changes** (ABI breaking change) + `git_config_backend`s should now return `git_config_backend_entry` + objects instead of `git_config_entry` objects. This allows backends + to provide a mechanism to nicely free the configuration entries that + they provide. + +## Future Changes + +We're preparing for libgit2 v2.0, and this is expected to be +the last feature-release for the libgit2 v1.0 release line. We +will introduce a number of breaking changes in v2.0: + +* **SHA256 support** + Adding SHA256 support will change the API and ABI. + +* **TLS v1.2 as a minimum** + libgit2 will remove support for HTTPS versions prior to TLS v1.2 and + will update to the "intermediate" settings [documented by + Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS). + +* Removing the chromium zlib built-in + +* Removing the libssh2 embedded build system + +## What's Changed + +### New features + +* The `git_signature_default_from_env` API will now produce a pair + of `git_signature`s representing the author, and the committer, + taking the `GIT_AUTHOR_NAME` and `GIT_COMMITTER_NAME` environment + variables into account. Added by @u-quark in + https://github.com/libgit2/libgit2/pull/6706 + +* packbuilder can now be interrupted from a callback. Added @roberth + in https://github.com/libgit2/libgit2/pull/6874 + +* libgit2 now claims to honor the `preciousObject` repository extension. + This extension indicates that the client will never delete objects + (in other words, will not garbage collect). libgit2 has no functionality + to remove objects, so it implicitly obeys this in all cases. Added + by @ethomson in https://github.com/libgit2/libgit2/pull/6886 + +* Push status will be reported even when a push fails. This is useful + to give information from the server about possible updates, even when + the overall status failed. Added by @yerseg in + https://github.com/libgit2/libgit2/pull/6876 + +* You can now generate a thin pack from a mempack instance using + `git_mempack_write_thin_pack`. Added by @roberth in + https://github.com/libgit2/libgit2/pull/6875 + +* The new `LIBGIT2_VERSION_CHECK` macro will indicate whether the version + of libgit2 being compiled against is at least the version specified. + For example: `#if LIBGIT2_VERSION_CHECK(1, 6, 3)` is true for libgit2 + version 1.6.3 or newer. In addition, the new `LIBGIT2_VERSION_NUMBER` + macro will return an integer version representing the libgit2 version + number. For example, for version 1.6.3, `LIBGIT2_VERSION_NUMBER` will + evaluate to `010603`. Added by @HamedMasafi in + https://github.com/libgit2/libgit2/pull/6882 + +* Custom X509 certificates can be added to OpenSSL's certificate store + using the `GIT_OPT_ADD_SSL_X509_CERT` option. Added by @yerseg in + https://github.com/libgit2/libgit2/pull/6877 + +* The libgit2 compatibility CLI now has a `git blame` command. Added by + @ethomson in https://github.com/libgit2/libgit2/pull/6907 + +* Remote callbacks now provide an `update_refs` callback so that users + can now get the `refspec` of the updated reference during push. This + gives more complete information about the remote reference that was + updated. Added by @ethomson in + https://github.com/libgit2/libgit2/pull/6559 + +* An optional FIPS-compliant mode for hashing is now available; you + can set `-DUSE_SHA256=OpenSSL-FIPS` to enable it. Added by @marcind-dot + in https://github.com/libgit2/libgit2/pull/6906 + +* The git-compatible CLI now supports the `git init` command, which has + been useful in identifying API improvements and incompatibilities with + git. Added by @ethomson in https://github.com/libgit2/libgit2/pull/6984 + +* Consumers can now query more information about how libgit2 was + compiled, and query the "backends" that libgit2 uses. Added by + @ethomson in https://github.com/libgit2/libgit2/pull/6971 + +### Bug fixes + +* Fix constness issue introduced in #6716 by @ethomson in + https://github.com/libgit2/libgit2/pull/6829 +* odb: conditional `git_hash_ctx_cleanup` in `git_odb_stream` by + @gensmusic in https://github.com/libgit2/libgit2/pull/6836 +* Fix shallow root maintenance during fetch by @kcsaul in + https://github.com/libgit2/libgit2/pull/6846 +* Headers cleanup by @anatol in + https://github.com/libgit2/libgit2/pull/6842 +* http: Initialize `on_status` when using the http-parser backend by + @civodul in https://github.com/libgit2/libgit2/pull/6870 +* Leak in `truncate_racily_clean` in index.c by @lstoppa in + https://github.com/libgit2/libgit2/pull/6884 +* ssh: Omit port option from ssh command unless specified in remote url + by @jayong93 in https://github.com/libgit2/libgit2/pull/6845 +* diff: print the file header on `GIT_DIFF_FORMAT_PATCH_HEADER` by + @carlosmn in https://github.com/libgit2/libgit2/pull/6888 +* Add more robust reporting to SecureTransport errors on macos by + @vcfxb in https://github.com/libgit2/libgit2/pull/6848 +* transport: do not filter tags based on ref dir in local by @rindeal + in https://github.com/libgit2/libgit2/pull/6881 +* push: handle tags to blobs by @ethomson in + https://github.com/libgit2/libgit2/pull/6898 +* Fixes for OpenSSL dynamic by @ethomson in + https://github.com/libgit2/libgit2/pull/6901 +* realpath: unbreak build on OpenBSD by @ajacoutot in + https://github.com/libgit2/libgit2/pull/6932 +* util/win32: Continue if access is denied when deleting a folder by + @lrm29 in https://github.com/libgit2/libgit2/pull/6929 +* object: `git_object_short_id` fails with core.abbrev string values by + @lrm29 in https://github.com/libgit2/libgit2/pull/6944 +* Clear data after negotiation by @lrm29 in + https://github.com/libgit2/libgit2/pull/6947 +* smart: ignore shallow/unshallow packets during ACK processing by + @kempniu in https://github.com/libgit2/libgit2/pull/6973 + +### Security fixes + +* ssh: Include rsa-sha2-256 and rsa-sha2-512 in the list of hostkey types + by @lrm29 in https://github.com/libgit2/libgit2/pull/6938 +* TLS: v1.2 and updated cipher list by @ethomson in + https://github.com/libgit2/libgit2/pull/6960 + +### Code cleanups + +* checkout: make safe checkout the default by @ethomson in + https://github.com/libgit2/libgit2/pull/6037 +* url: track whether url explicitly specified a port by @ethomson in + https://github.com/libgit2/libgit2/pull/6851 +* config: remove `free` ptr from `git_config_entry` by @ethomson in + https://github.com/libgit2/libgit2/pull/6804 +* Add SecCopyErrorMessageString for iOS and update README for iOS by + @Kyle-Ye in https://github.com/libgit2/libgit2/pull/6862 +* vector: free is now dispose by @ethomson in + https://github.com/libgit2/libgit2/pull/6896 +* hashmap: a libgit2-idiomatic khash by @ethomson in + https://github.com/libgit2/libgit2/pull/6897 +* hashmap: asserts by @ethomson in + https://github.com/libgit2/libgit2/pull/6902 +* hashmap: further asserts by @ethomson in + https://github.com/libgit2/libgit2/pull/6904 +* Make `GIT_WIN32` an internal declaration by @ethomson in + https://github.com/libgit2/libgit2/pull/6940 +* pathspec: additional pathspec wildcard tests by @ethomson in + https://github.com/libgit2/libgit2/pull/6959 +* repo: don't require option when `template_path` is specified by @ethomson + in https://github.com/libgit2/libgit2/pull/6983 +* options: update X509 cert constant by @ethomson in + https://github.com/libgit2/libgit2/pull/6974 +* remote: Handle fetching negative refspecs by @ryan-ph in + https://github.com/libgit2/libgit2/pull/6962 +* Restore tls v1.0 support temporarily by @ethomson in + https://github.com/libgit2/libgit2/pull/6964 +* SHA256 improvements by @ethomson in + https://github.com/libgit2/libgit2/pull/6965 + +### Benchmarks + +* Add benchmarks for blame by @ethomson in + https://github.com/libgit2/libgit2/pull/6920 + +### Build and CI improvements + +* README: add experimental builds to ci table by @ethomson in + https://github.com/libgit2/libgit2/pull/6816 +* Update stransport.c by @ethomson in + https://github.com/libgit2/libgit2/pull/6891 +* stransport: initialize for iOS by @ethomson in + https://github.com/libgit2/libgit2/pull/6893 +* CI updates by @ethomson in + https://github.com/libgit2/libgit2/pull/6895 +* Configurable C standard by @ethomson in + https://github.com/libgit2/libgit2/pull/6911 +* cmake: update python locator by @ethomson in + https://github.com/libgit2/libgit2/pull/6915 +* ci: don't run Windows SHA256 gitdaemon tests by @ethomson in + https://github.com/libgit2/libgit2/pull/6916 +* cmake-standard c standards by @ethomson in + https://github.com/libgit2/libgit2/pull/6914 +* ci: don't run Windows SHA256 gitdaemon tests by @ethomson in + https://github.com/libgit2/libgit2/pull/6919 +* Improve dependency selection in CMake by @ethomson in + https://github.com/libgit2/libgit2/pull/6924 +* ci: port latest fixes to nightlies by @ethomson in + https://github.com/libgit2/libgit2/pull/6926 + +### Documentation improvements + +* Fix docs for `git_odb_stream_read` return value. by @ehuss in + https://github.com/libgit2/libgit2/pull/6837 +* docs: Add instructions to build examples by @thymusvulgaris in + https://github.com/libgit2/libgit2/pull/6839 +* Fix contradictory phrase in SECURITY.md by @Kyle-Ye in + https://github.com/libgit2/libgit2/pull/6859 +* Update README.md by @Kyle-Ye in + https://github.com/libgit2/libgit2/pull/6860 +* README updates by @ethomson in + https://github.com/libgit2/libgit2/pull/6908 +* typo: s/size on bytes/size in bytes/ by @John-Colvin in + https://github.com/libgit2/libgit2/pull/6909 +* readme: add OpenSSF best practices badge by @ethomson in + https://github.com/libgit2/libgit2/pull/6925 +* Update documentation of `merge_base_many` by @Caleb-T-Owens in + https://github.com/libgit2/libgit2/pull/6927 +* Include documentation generator by @ethomson in + https://github.com/libgit2/libgit2/pull/6945 +* Update documentation generation workflow by @ethomson in + https://github.com/libgit2/libgit2/pull/6948 +* Improve documentation and validate during CI by @ethomson in + https://github.com/libgit2/libgit2/pull/6949 +* Add search functionality to our docs generator by @ethomson in + https://github.com/libgit2/libgit2/pull/6953 +* Documentation: don't resort versions by @ethomson in + https://github.com/libgit2/libgit2/pull/6954 +* Documentation: update `refdb_backend` docs by @ethomson in + https://github.com/libgit2/libgit2/pull/6955 +* Documentation: clean up old documentation by @ethomson in + https://github.com/libgit2/libgit2/pull/6957 +* docs: remind people about `git_libgit2_init` by @ethomson in + https://github.com/libgit2/libgit2/pull/6958 +* Update changelog with v1.8.4 content by @ethomson in + https://github.com/libgit2/libgit2/pull/6961 + +### Git compatibility fixes + +* Limit `.gitattributes` and `.gitignore` files to 100 MiB by @csware in + https://github.com/libgit2/libgit2/pull/6834 +* refs: Handle normalizing negative refspecs by @ryan-ph in + https://github.com/libgit2/libgit2/pull/6951 +* repo: put a newline on the .git link file by @ethomson in + https://github.com/libgit2/libgit2/pull/6981 + +### Dependency updates + +* zlib: update bundled zlib to v1.3.1 by @ethomson in + https://github.com/libgit2/libgit2/pull/6905 +* Update ntlmclient dependency by @ethomson in + https://github.com/libgit2/libgit2/pull/6912 + +### Other changes + +* Create FUNDING.json by @BenJam in + https://github.com/libgit2/libgit2/pull/6853 + +## New Contributors + +* @gensmusic made their first contribution in + https://github.com/libgit2/libgit2/pull/6836 +* @u-quark made their first contribution in + https://github.com/libgit2/libgit2/pull/6706 +* @thymusvulgaris made their first contribution in + https://github.com/libgit2/libgit2/pull/6839 +* @anatol made their first contribution in + https://github.com/libgit2/libgit2/pull/6842 +* @BenJam made their first contribution in + https://github.com/libgit2/libgit2/pull/6853 +* @Kyle-Ye made their first contribution in + https://github.com/libgit2/libgit2/pull/6859 +* @civodul made their first contribution in + https://github.com/libgit2/libgit2/pull/6870 +* @lstoppa made their first contribution in + https://github.com/libgit2/libgit2/pull/6884 +* @jayong93 made their first contribution in + https://github.com/libgit2/libgit2/pull/6845 +* @roberth made their first contribution in + https://github.com/libgit2/libgit2/pull/6874 +* @vcfxb made their first contribution in + https://github.com/libgit2/libgit2/pull/6848 +* @yerseg made their first contribution in + https://github.com/libgit2/libgit2/pull/6876 +* @rindeal made their first contribution in + https://github.com/libgit2/libgit2/pull/6881 +* @HamedMasafi made their first contribution in + https://github.com/libgit2/libgit2/pull/6882 +* @John-Colvin made their first contribution in + https://github.com/libgit2/libgit2/pull/6909 +* @marcind-dot made their first contribution in + https://github.com/libgit2/libgit2/pull/6906 +* @ajacoutot made their first contribution in + https://github.com/libgit2/libgit2/pull/6932 +* @Caleb-T-Owens made their first contribution in + https://github.com/libgit2/libgit2/pull/6927 +* @ryan-ph made their first contribution in + https://github.com/libgit2/libgit2/pull/6951 +* @bmarques1995 made their first contribution in + https://github.com/libgit2/libgit2/pull/6840 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.8.4...v1.9.0 + v1.8.4 ------ From c536fcbb858272a4667ff8bc40280dedc3715b8a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 23 Dec 2024 17:08:20 +0000 Subject: [PATCH 755/816] v1.9: update version numbers Update the library's (API) version number to v1.9.0. Also update the soname version number to 2.0, since we've had breaking ABI changes to the library. --- CMakeLists.txt | 2 +- include/git2/version.h | 10 +++++----- package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a864cb1f4a..a90524b32bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.8.2" LANGUAGES C) +project(libgit2 VERSION "1.9.0" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") diff --git a/include/git2/version.h b/include/git2/version.h index d512bbb06d0..8acffca9c57 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -19,16 +19,16 @@ GIT_BEGIN_DECL * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.8.2" +#define LIBGIT2_VERSION "1.9.0" /** The major version number for this version of libgit2. */ #define LIBGIT2_VERSION_MAJOR 1 /** The minor version number for this version of libgit2. */ -#define LIBGIT2_VERSION_MINOR 8 +#define LIBGIT2_VERSION_MINOR 9 /** The revision ("teeny") version number for this version of libgit2. */ -#define LIBGIT2_VERSION_REVISION 2 +#define LIBGIT2_VERSION_REVISION 0 /** The Windows DLL patch number for this version of libgit2. */ #define LIBGIT2_VERSION_PATCH 0 @@ -44,9 +44,9 @@ GIT_BEGIN_DECL /** * The library ABI soversion for this version of libgit2. This should * only be changed when the library has a breaking ABI change, and so - * may trail the library's version number. + * may not reflect the library's API version number. */ -#define LIBGIT2_SOVERSION "1.8" +#define LIBGIT2_SOVERSION "2.0" /** * An integer value representing the libgit2 version number. For example, diff --git a/package.json b/package.json index df10dee2733..2bea37ef30b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.8.2", + "version": "1.9.0", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." From 3aeb5bd0f6528d4904d05520052eebf493853f08 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 28 Dec 2024 08:28:35 +0000 Subject: [PATCH 756/816] meta: revert soname version update Changing our SONAME / ABI version update policy without an announcement is a breaking change. Provide time to announce a policy update. --- docs/changelog.md | 9 ++++----- include/git2/version.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index ce524b9e74e..b0655f7d078 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -33,11 +33,10 @@ This means that v2.0 will have API and ABI changes to support SHA256. so that the blame functionality can be benchmarked by our benchmark suite. -* **SONAME changed** - libgit2 will now properly update its SONAME version information when - ABI chnages occur. We hope that by correcting this oversight, users - and distribution vendors, will be able to integrate new versions of - libgit2 more easily. +* **More CLI commands** + libgit2 has added `blame` and `init` commands, which have allowed for + [further benchmarking](https://benchmarks.libgit2.org/) and several API + improvements and git compatibility updates. ## Breaking changes diff --git a/include/git2/version.h b/include/git2/version.h index 8acffca9c57..6a352e1a53a 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -46,7 +46,7 @@ GIT_BEGIN_DECL * only be changed when the library has a breaking ABI change, and so * may not reflect the library's API version number. */ -#define LIBGIT2_SOVERSION "2.0" +#define LIBGIT2_SOVERSION "1.9" /** * An integer value representing the libgit2 version number. For example, From 550cf62021f16da994220d6a8e7e94fbde612d7b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 28 Dec 2024 09:49:28 +0000 Subject: [PATCH 757/816] cmake: warn for not using sha1dc git's hash algorithm is sha1dc, it is not sha1. Per Linus: > Honestly, git has effectively already moved from SHA1 to SHA1DC. > > So the actual known attack and weakness of SHA1 should simply not be > part of the discussion for the next hash. You can basically say "we're > _already_ on the second hash, we just picked one that was so > compatible with SHA1 that nobody even really noticed. Warn users who try to compile with SHA1 instead of SHA1DC. --- CMakeLists.txt | 6 ++++++ cmake/SelectHashes.cmake | 7 +++++++ docs/changelog.md | 2 ++ 3 files changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a90524b32bd..31da49a8856 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,3 +150,9 @@ endif() feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:") feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:") + +# warn for not using sha1dc + +foreach(WARNING ${WARNINGS}) + message(WARNING ${WARNING}) +endforeach() diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 92ec8d2e23c..35fea3ece0b 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -112,3 +112,10 @@ endif() add_feature_info(SHA1 ON "using ${USE_SHA1}") add_feature_info(SHA256 ON "using ${USE_SHA256}") + +# warn for users who do not use sha1dc + +if(NOT "${USE_SHA1}" STREQUAL "CollisionDetection") + list(APPEND WARNINGS "SHA1 support is set to ${USE_SHA1} which is not recommended - git's hash algorithm is sha1dc, it is *not* SHA1. Using SHA1 may leave you and your users susceptible to SHAttered-style attacks.") + set(WARNINGS ${WARNINGS} PARENT_SCOPE) +endif() diff --git a/docs/changelog.md b/docs/changelog.md index ce524b9e74e..620b0b5816e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -253,6 +253,8 @@ will introduce a number of breaking changes in v2.0: https://github.com/libgit2/libgit2/pull/6924 * ci: port latest fixes to nightlies by @ethomson in https://github.com/libgit2/libgit2/pull/6926 +* cmake: warn for not using sha1dc by @ethomson in + https://github.com/libgit2/libgit2/pull/6986 ### Documentation improvements From 1329f1a1dba28a3fdd4c0312a9c63adf424f1cdb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 28 Dec 2024 10:02:09 +0000 Subject: [PATCH 758/816] v1.9: final changelog updates --- docs/changelog.md | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 8ac256e2b7c..9824d994bc7 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -38,6 +38,11 @@ This means that v2.0 will have API and ABI changes to support SHA256. [further benchmarking](https://benchmarks.libgit2.org/) and several API improvements and git compatibility updates. +* **Warning when configuring without SHA1DC** + Users are encouraged to use SHA1DC, which is _git's hash_; users + should not use SHA1 in the general case. Users will now be warned + if they try to configure cmake with a SHA1 backend (`-DUSE_SHA1=...`). + ## Breaking changes There are several ABI-breaking changes that integrators, particularly @@ -66,24 +71,6 @@ maintainers of bindings or FFI users, may want to be aware of. to provide a mechanism to nicely free the configuration entries that they provide. -## Future Changes - -We're preparing for libgit2 v2.0, and this is expected to be -the last feature-release for the libgit2 v1.0 release line. We -will introduce a number of breaking changes in v2.0: - -* **SHA256 support** - Adding SHA256 support will change the API and ABI. - -* **TLS v1.2 as a minimum** - libgit2 will remove support for HTTPS versions prior to TLS v1.2 and - will update to the "intermediate" settings [documented by - Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS). - -* Removing the chromium zlib built-in - -* Removing the libssh2 embedded build system - ## What's Changed ### New features From d7f3fb568e2a49d98e2deb1781481904d3d414dc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 28 Dec 2024 10:27:39 +0000 Subject: [PATCH 759/816] README: add v1.9 builds --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d893b5376f9..7e0f157184d 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | | **main** branch builds | [![CI Build](https://github.com/libgit2/libgit2/actions/workflows/main.yml/badge.svg?branch=main&event=push)](https://github.com/libgit2/libgit2/actions/workflows/main.yml?query=event%3Apush+branch%3Amain) [![Experimental Features](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml/badge.svg?branch=main)](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml?query=event%3Apush+branch%3Amain) | +| **v1.9 branch** builds | [![CI Build](https://github.com/libgit2/libgit2/actions/workflows/main.yml/badge.svg?branch=maint%2Fv1.9&event=push)](https://github.com/libgit2/libgit2/actions/workflows/main.yml?query=event%3Apush+branch%3Amaint%2Fv1.9) [![Experimental Features](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml/badge.svg?branch=maint%2Fv1.9)](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml?query=event%3Apush+branch%3Amaint%2Fv1.9) | | **v1.8 branch** builds | [![CI Build](https://github.com/libgit2/libgit2/actions/workflows/main.yml/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions/workflows/main.yml?query=event%3Apush+branch%3Amaint%2Fv1.8) [![Experimental Features](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml/badge.svg?branch=maint%2Fv1.8)](https://github.com/libgit2/libgit2/actions/workflows/experimental.yml?query=event%3Apush+branch%3Amaint%2Fv1.8) | -| **v1.7 branch** builds | [![CI Build](https://github.com/libgit2/libgit2/actions/workflows/main.yml/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions/workflows/main.yml?query=event%3Apush+branch%3Amaint%2Fv1.7) | | **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/actions/workflows/nightly.yml/badge.svg?branch=main&event=schedule)](https://github.com/libgit2/libgit2/actions/workflows/nightly.yml) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | `libgit2` is a portable, pure C implementation of the Git core methods From e447de936d4a0838f235e321cbb3dc3d50a9c3cf Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 28 Dec 2024 10:57:33 +0000 Subject: [PATCH 760/816] ci: only build docs on main branch pushes Don't build docs on pushes to maint branches; those docs should only be built _on release_. In addition, be safer about not creating an existing branch from a tracking branch. --- .github/workflows/documentation.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index da3effd8e24..d82887d2741 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -3,7 +3,7 @@ name: Generate Documentation on: push: - branches: [ main, maint/* ] + branches: [ main ] release: workflow_dispatch: inputs: @@ -37,12 +37,10 @@ jobs: ssh-key: ${{ secrets.DOCS_PUBLISH_KEY }} - name: Prepare branches run: | - if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then - git branch --track main origin/main - fi - - for a in $(git branch -r --list 'origin/maint/*' | sed -e "s/^ origin\///"); do - git branch --track "$a" "origin/$a" + for a in main $(git branch -r --list 'origin/maint/*' | sed -e "s/^ origin\///"); do + if [ "$(git rev-parse --abbrev-ref HEAD)" != "${a}" ]; then + git branch --track "$a" "origin/$a" + fi done working-directory: source - name: Generate documentation From ca2a241e4c0afb1302c24383b32199300c2692db Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 27 Dec 2024 15:36:06 +0000 Subject: [PATCH 761/816] repo: `workdir_path` implies no dotgit in init When specifying a separate working directory path, the given repository path should never have a `.git` directory created beneath it. That simply doesn't make sense. As a result, the `GIT_REPOSITORY_INIT_NO_DOTGIT_DIR` now _also_ no longer makes sense. It would only ever be a sensible option when one wanted a separate `.git` directory and working directory, otherwise the git files and working directory files would be comingled. Remove the option entirely. --- include/git2/deprecated.h | 11 +++++++++++ include/git2/repository.h | 7 ------- src/cli/cmd_init.c | 2 -- src/libgit2/repository.c | 3 +-- src/libgit2/submodule.c | 2 -- tests/libgit2/repo/init.c | 13 +++++++------ 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/git2/deprecated.h b/include/git2/deprecated.h index b8b0238da66..d10143a5cbb 100644 --- a/include/git2/deprecated.h +++ b/include/git2/deprecated.h @@ -748,6 +748,17 @@ GIT_EXTERN(int) git_tag_create_frombuffer( /**@}*/ +/** @name Deprecated Repository Constants + * + * These enumeration values are retained for backward compatibility. + */ + +/** + * @deprecated This option is deprecated; it is now implied when + * a separate working directory is specified to `git_repository_init`. + */ +#define GIT_REPOSITORY_INIT_NO_DOTGIT_DIR 0 + /** @name Deprecated Revspec Constants * * These enumeration values are retained for backward compatibility. diff --git a/include/git2/repository.h b/include/git2/repository.h index b203576affc..4bdcee37a76 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -258,13 +258,6 @@ typedef enum { */ GIT_REPOSITORY_INIT_NO_REINIT = (1u << 1), - /** - * Normally a "/.git/" will be appended to the repo path for - * non-bare repos (if it is not already there), but passing this flag - * prevents that behavior. - */ - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR = (1u << 2), - /** * Make the repo_path (and workdir_path) as needed. Init is always willing * to create the ".git" directory even without this flag. This flag tells diff --git a/src/cli/cmd_init.c b/src/cli/cmd_init.c index b6468961ee2..40037d6d6b4 100644 --- a/src/cli/cmd_init.c +++ b/src/cli/cmd_init.c @@ -82,9 +82,7 @@ int cmd_init(int argc, char **argv) init_opts.initial_head = branch; if (git_dir) { - init_opts.flags |= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; init_opts.workdir_path = path; - repo_path = git_dir; } else { repo_path = path; diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 73876424a88..2c36458b367 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -2690,8 +2690,7 @@ static int repo_init_directories( is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0); add_dotgit = - (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 && - !is_bare && + !is_bare && !opts->workdir_path && git__suffixcmp(given_repo, "/" DOT_GIT) != 0 && git__suffixcmp(given_repo, "/" GIT_DIR) != 0; diff --git a/src/libgit2/submodule.c b/src/libgit2/submodule.c index a3bfc787274..7444e8c678b 100644 --- a/src/libgit2/submodule.c +++ b/src/libgit2/submodule.c @@ -757,7 +757,6 @@ static int submodule_repo_init( initopt.workdir_path = workdir.ptr; initopt.flags |= - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR | GIT_REPOSITORY_INIT_RELATIVE_GITLINK; error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt); @@ -1289,7 +1288,6 @@ static int submodule_repo_create( initopt.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT | - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR | GIT_REPOSITORY_INIT_RELATIVE_GITLINK; /* Workdir: path to sub-repo working directory */ diff --git a/tests/libgit2/repo/init.c b/tests/libgit2/repo/init.c index e23271d350d..70624b6f259 100644 --- a/tests/libgit2/repo/init.c +++ b/tests/libgit2/repo/init.c @@ -425,8 +425,7 @@ void test_repo_init__extended_1(void) struct stat st; git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; - opts.flags = GIT_REPOSITORY_INIT_MKPATH | - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; + opts.flags = GIT_REPOSITORY_INIT_MKPATH; opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP; opts.workdir_path = "../c_wd"; opts.description = "Awesomest test repository evah"; @@ -466,16 +465,18 @@ void test_repo_init__extended_1(void) void test_repo_init__relative_gitdir(void) { git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; + git_str head_content = GIT_STR_INIT; git_str dot_git_content = GIT_STR_INIT; opts.workdir_path = "../c_wd"; opts.flags = GIT_REPOSITORY_INIT_MKPATH | - GIT_REPOSITORY_INIT_RELATIVE_GITLINK | - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; + GIT_REPOSITORY_INIT_RELATIVE_GITLINK; /* make the directory first, then it should succeed */ cl_git_pass(git_repository_init_ext(&g_repo, "root/b/my_repository", &opts)); + cl_git_pass(git_futils_readbuffer(&head_content, "root/b/my_repository/HEAD")); + cl_assert_equal_s("ref: refs/heads/master\n", head_content.ptr); cl_assert(!git__suffixcmp(git_repository_workdir(g_repo), "root/b/c_wd/")); cl_assert(!git__suffixcmp(git_repository_path(g_repo), "root/b/my_repository/")); @@ -491,6 +492,7 @@ void test_repo_init__relative_gitdir(void) cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git")); cl_assert_equal_s("gitdir: ../my_repository/\n", dot_git_content.ptr); + git_str_dispose(&head_content); git_str_dispose(&dot_git_content); cleanup_repository("root"); } @@ -507,8 +509,7 @@ void test_repo_init__relative_gitdir_2(void) opts.workdir_path = full_path.ptr; opts.flags = GIT_REPOSITORY_INIT_MKPATH | - GIT_REPOSITORY_INIT_RELATIVE_GITLINK | - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; + GIT_REPOSITORY_INIT_RELATIVE_GITLINK; /* make the directory first, then it should succeed */ cl_git_pass(git_repository_init_ext(&g_repo, "root/b/my_repository", &opts)); From c4a65c34c298c314da5feafed808e49aea12cd12 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 28 Dec 2024 15:34:04 +0000 Subject: [PATCH 762/816] cmake: standardize builtin sha1dc selection All `USE_*` options are now `builtin`. Use that for the builtin sha1dc implementation, keeping `CollisionDetection` for backward compatibility. --- CMakeLists.txt | 2 +- cmake/SelectHashes.cmake | 13 +++++++++---- src/libgit2/libgit2.c | 2 +- src/util/CMakeLists.txt | 4 +++- src/util/git2_features.h.in | 2 +- src/util/hash/sha.h | 8 ++++---- tests/libgit2/core/features.c | 2 +- tests/util/sha1.c | 2 +- 8 files changed, 21 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31da49a8856..bc9369bafd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ option(USE_NSEC "Support nanosecond precision file mtimes and cti # Backend selection set(USE_SSH "" CACHE STRING "Enables SSH support and optionally selects provider. One of ON, OFF, or a specific provider: libssh2 or exec. (Defaults to OFF.)") set(USE_HTTPS "" CACHE STRING "Enable HTTPS support and optionally selects the provider. One of ON, OFF, or a specific provider: OpenSSL, OpenSSL-FIPS, OpenSSL-Dynamic, mbedTLS, SecureTransport, Schannel, or WinHTTP. (Defaults to ON.)") - set(USE_SHA1 "" CACHE STRING "Selects SHA1 provider. One of CollisionDetection, HTTPS, or a specific provider. (Defaults to CollisionDetection.)") + set(USE_SHA1 "" CACHE STRING "Selects SHA1 provider. One of builtin, HTTPS, or a specific provider. (Defaults to builtin.)") set(USE_SHA256 "" CACHE STRING "Selects SHA256 provider. One of Builtin, HTTPS, or a specific provider. (Defaults to HTTPS.)") option(USE_GSSAPI "Enable SPNEGO authentication using GSSAPI" OFF) set(USE_HTTP_PARSER "" CACHE STRING "Selects HTTP Parser support: http-parser, llhttp, or builtin. (Defaults to builtin.)") diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 35fea3ece0b..6f6e0f056dd 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -8,7 +8,7 @@ sanitizebool(USE_SHA256) # sha1 if(USE_SHA1 STREQUAL "" OR USE_SHA1 STREQUAL ON) - SET(USE_SHA1 "CollisionDetection") + SET(USE_SHA1 "builtin") elseif(USE_SHA1 STREQUAL "HTTPS") if(USE_HTTPS STREQUAL "SecureTransport") set(USE_SHA1 "CommonCrypto") @@ -23,8 +23,12 @@ elseif(USE_SHA1 STREQUAL "HTTPS") endif() endif() -if(USE_SHA1 STREQUAL "CollisionDetection") - set(GIT_SHA1_COLLISIONDETECT 1) +if(USE_SHA1 STREQUAL "Builtin" OR USE_SHA1 STREQUAL "CollisionDetection") + set(USE_SHA1 "builtin") +endif() + +if(USE_SHA1 STREQUAL "builtin") + set(GIT_SHA1_BUILTIN 1) elseif(USE_SHA1 STREQUAL "OpenSSL") set(GIT_SHA1_OPENSSL 1) elseif(USE_SHA1 STREQUAL "OpenSSL-FIPS") @@ -90,6 +94,7 @@ else() endif() # add library requirements + if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-FIPS" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") @@ -115,7 +120,7 @@ add_feature_info(SHA256 ON "using ${USE_SHA256}") # warn for users who do not use sha1dc -if(NOT "${USE_SHA1}" STREQUAL "CollisionDetection") +if(NOT "${USE_SHA1}" STREQUAL "builtin") list(APPEND WARNINGS "SHA1 support is set to ${USE_SHA1} which is not recommended - git's hash algorithm is sha1dc, it is *not* SHA1. Using SHA1 may leave you and your users susceptible to SHAttered-style attacks.") set(WARNINGS ${WARNINGS} PARENT_SCOPE) endif() diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index de72cfe7d2b..a75fb0f9136 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -224,7 +224,7 @@ const char *git_libgit2_feature_backend(git_feature_t feature) break; case GIT_FEATURE_SHA1: -#if defined(GIT_SHA1_COLLISIONDETECT) +#if defined(GIT_SHA1_BUILTIN) return "builtin"; #elif defined(GIT_SHA1_OPENSSL) return "openssl"; diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 3692dc3d332..5831c213b7b 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -29,11 +29,13 @@ endif() # Hash backend selection # -if(USE_SHA1 STREQUAL "CollisionDetection") +if(USE_SHA1 STREQUAL "builtin") file(GLOB UTIL_SRC_SHA1 hash/collisiondetect.* hash/sha1dc/*) target_compile_definitions(util PRIVATE SHA1DC_NO_STANDARD_INCLUDES=1) target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_SHA1_C=\"git2_util.h\") target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"git2_util.h\") +elseif(USE_SHA1 STREQUAL "SHA1CollisionDetection") + file(GLOB UTIL_SRC_SHA1 hash/collisiondetect.*) elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic" OR USE_SHA1 STREQUAL "OpenSSL-FIPS") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) file(GLOB UTIL_SRC_SHA1 hash/openssl.*) diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index cd14cc2347d..c889202d76f 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -50,7 +50,7 @@ #cmakedefine GIT_HTTPPARSER_LLHTTP 1 #cmakedefine GIT_HTTPPARSER_BUILTIN 1 -#cmakedefine GIT_SHA1_COLLISIONDETECT 1 +#cmakedefine GIT_SHA1_BUILTIN 1 #cmakedefine GIT_SHA1_WIN32 1 #cmakedefine GIT_SHA1_COMMON_CRYPTO 1 #cmakedefine GIT_SHA1_OPENSSL 1 diff --git a/src/util/hash/sha.h b/src/util/hash/sha.h index 8e7eeae8c34..eb418c0d631 100644 --- a/src/util/hash/sha.h +++ b/src/util/hash/sha.h @@ -13,6 +13,10 @@ typedef struct git_hash_sha1_ctx git_hash_sha1_ctx; typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; +#if defined(GIT_SHA1_BUILTIN) +# include "collisiondetect.h" +#endif + #if defined(GIT_SHA1_COMMON_CRYPTO) || defined(GIT_SHA256_COMMON_CRYPTO) # include "common_crypto.h" #endif @@ -32,10 +36,6 @@ typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; # include "mbedtls.h" #endif -#if defined(GIT_SHA1_COLLISIONDETECT) -# include "collisiondetect.h" -#endif - #if defined(GIT_SHA256_BUILTIN) # include "builtin.h" #endif diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index b7cd6014a57..8dba8e1a961 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -186,7 +186,7 @@ void test_core_features__backends(void) cl_assert(0); #endif -#if defined(GIT_SHA1_COLLISIONDETECT) +#if defined(GIT_SHA1_BUILTIN) cl_assert_equal_s("builtin", sha1); #elif defined(GIT_SHA1_OPENSSL) cl_assert_equal_s("openssl", sha1); diff --git a/tests/util/sha1.c b/tests/util/sha1.c index fe4032c13ec..c144def714f 100644 --- a/tests/util/sha1.c +++ b/tests/util/sha1.c @@ -70,7 +70,7 @@ void test_sha1__detect_collision_attack(void) 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a }; -#ifdef GIT_SHA1_COLLISIONDETECT +#ifdef GIT_SHA1_BUILTIN GIT_UNUSED(&expected); cl_git_fail(sha1_file(actual, FIXTURE_DIR "/shattered-1.pdf")); cl_assert_equal_s("SHA1 collision attack detected", git_error_last()->message); From fdb73f5d1d25f5f6ab5176e964ccd6126994708b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 22 Dec 2024 12:32:10 +0000 Subject: [PATCH 763/816] cmake: simplify compression selection --- CMakeLists.txt | 2 +- cmake/SelectCompression.cmake | 53 +++++++++++++++++++++++++++++++++++ cmake/SelectZlib.cmake | 38 ------------------------- src/CMakeLists.txt | 2 +- 4 files changed, 55 insertions(+), 40 deletions(-) create mode 100644 cmake/SelectCompression.cmake delete mode 100644 cmake/SelectZlib.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index bc9369bafd2..883f2347982 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ option(USE_GSSAPI "Enable SPNEGO authentication using GSSAPI" OFF) set(USE_HTTP_PARSER "" CACHE STRING "Selects HTTP Parser support: http-parser, llhttp, or builtin. (Defaults to builtin.)") # set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") set(REGEX_BACKEND "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") -option(USE_BUNDLED_ZLIB "Use the bundled version of zlib. Can be set to one of Bundled(ON)/Chromium. The Chromium option requires a x86_64 processor with SSE4.2 and CLMUL" OFF) + set(USE_COMPRESSION "" CACHE STRING "Selects compression backend. Either builtin or zlib.") # Debugging options option(USE_LEAK_CHECKER "Run tests with leak checker" OFF) diff --git a/cmake/SelectCompression.cmake b/cmake/SelectCompression.cmake new file mode 100644 index 00000000000..50c4706f415 --- /dev/null +++ b/cmake/SelectCompression.cmake @@ -0,0 +1,53 @@ +include(SanitizeBool) + +# Fall back to the previous cmake configuration, "USE_BUNDLED_ZLIB" +if(NOT USE_COMPRESSION AND USE_BUNDLED_ZLIB) + SanitizeBool(USE_BUNDLED_ZLIB) + + if(USE_BUNDLED_ZLIB STREQUAL ON) + set(USE_COMPRESSION "builtin") + elseif(USE_BUNDLED_ZLIB STREQUAL OFF) + set(USE_COMPRESSION "zlib") + else() + message(FATAL_ERROR "unknown setting to USE_BUNDLED_ZLIB: ${USE_BUNDLED_ZLIB}") + endif() +endif() + +if(NOT USE_COMPRESSION) + find_package(ZLIB) + + if(ZLIB_FOUND) + set(GIT_COMPRESSION_ZLIB 1) + else() + message(STATUS "zlib was not found; using bundled 3rd-party sources." ) + set(GIT_COMPRESSION_BUILTIN 1) + endif() +elseif(USE_COMPRESSION STREQUAL "zlib") + find_package(ZLIB) + + if(NOT ZLIB_FOUND) + message(FATAL_ERROR "system zlib was requested but not found") + endif() + + set(GIT_COMPRESSION_ZLIB 1) +elseif(USE_COMPRESSION STREQUAL "builtin") + set(GIT_COMPRESSION_BUILTIN 1) +endif() + +if(GIT_COMPRESSION_ZLIB) + list(APPEND LIBGIT2_SYSTEM_INCLUDES ${ZLIB_INCLUDE_DIRS}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${ZLIB_LIBRARIES}) + if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + list(APPEND LIBGIT2_PC_LIBS "-lz") + else() + list(APPEND LIBGIT2_PC_REQUIRES "zlib") + endif() + add_feature_info(compression ON "using system zlib") +elseif(GIT_COMPRESSION_BUILTIN) + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/zlib" "${PROJECT_BINARY_DIR}/deps/zlib") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/zlib") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $) + add_feature_info(compression ON "using bundled zlib") +else() + message(FATAL_ERROR "unknown compression backend") +endif() diff --git a/cmake/SelectZlib.cmake b/cmake/SelectZlib.cmake deleted file mode 100644 index 25c7b2f94fa..00000000000 --- a/cmake/SelectZlib.cmake +++ /dev/null @@ -1,38 +0,0 @@ -# Optional external dependency: zlib -include(SanitizeBool) - -SanitizeBool(USE_BUNDLED_ZLIB) -if(USE_BUNDLED_ZLIB STREQUAL ON) - set(USE_BUNDLED_ZLIB "Bundled") - set(GIT_COMPRESSION_BUILTIN) -endif() - -if(USE_BUNDLED_ZLIB STREQUAL "OFF") - find_package(ZLIB) - if(ZLIB_FOUND) - list(APPEND LIBGIT2_SYSTEM_INCLUDES ${ZLIB_INCLUDE_DIRS}) - list(APPEND LIBGIT2_SYSTEM_LIBS ${ZLIB_LIBRARIES}) - if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - list(APPEND LIBGIT2_PC_LIBS "-lz") - else() - list(APPEND LIBGIT2_PC_REQUIRES "zlib") - endif() - add_feature_info(zlib ON "using system zlib") - set(GIT_COMPRESSION_ZLIB 1) - else() - message(STATUS "zlib was not found; using bundled 3rd-party sources." ) - endif() -endif() -if(USE_BUNDLED_ZLIB STREQUAL "Chromium") - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/chromium-zlib" "${PROJECT_BINARY_DIR}/deps/chromium-zlib") - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/chromium-zlib") - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $) - add_feature_info(zlib ON "using (Chromium) bundled zlib") - set(GIT_COMPRESSION_BUILTIN 1) -elseif(USE_BUNDLED_ZLIB OR NOT ZLIB_FOUND) - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/zlib" "${PROJECT_BINARY_DIR}/deps/zlib") - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/zlib") - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $) - add_feature_info(zlib ON "using bundled zlib") - set(GIT_COMPRESSION_BUILTIN 1) -endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73c46e21043..90996aa5d3c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,7 +43,7 @@ include(SelectHTTPParser) include(SelectRegex) include(SelectXdiff) include(SelectSSH) -include(SelectZlib) +include(SelectCompression) # # Platform support From 78a8c44cc160ffa26de857a19702fb395d28b3d9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Dec 2024 16:26:38 +0000 Subject: [PATCH 764/816] cmake: standardize regex options Selecting regular expression backend should be specified in the same way as everything else; `USE_REGEX`. Keep `REGEX_BACKEND` as an optional fallback. --- CMakeLists.txt | 2 +- cmake/SelectRegex.cmake | 32 ++++++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 883f2347982..87be33af676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ option(USE_NSEC "Support nanosecond precision file mtimes and cti option(USE_GSSAPI "Enable SPNEGO authentication using GSSAPI" OFF) set(USE_HTTP_PARSER "" CACHE STRING "Selects HTTP Parser support: http-parser, llhttp, or builtin. (Defaults to builtin.)") # set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") - set(REGEX_BACKEND "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") + set(USE_REGEX "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") set(USE_COMPRESSION "" CACHE STRING "Selects compression backend. Either builtin or zlib.") # Debugging options diff --git a/cmake/SelectRegex.cmake b/cmake/SelectRegex.cmake index 840ec7f349f..64cc2f14815 100644 --- a/cmake/SelectRegex.cmake +++ b/cmake/SelectRegex.cmake @@ -1,27 +1,35 @@ # Specify regular expression implementation find_package(PCRE) -if(REGEX_BACKEND STREQUAL "") +set(OPTION_NAME "USE_REGEX") + +# Fall back to the previous cmake configuration, "USE_BUNDLED_ZLIB" +if(NOT USE_REGEX AND REGEX_BACKEND) + set(USE_REGEX "${REGEX_BACKEND}") + set(OPTION_NAME "REGEX_BACKEND") +endif() + +if(NOT USE_REGEX) check_symbol_exists(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L) if(HAVE_REGCOMP_L) # 'regcomp_l' has been explicitly marked unavailable on iOS_SDK if(CMAKE_SYSTEM_NAME MATCHES "iOS") - set(REGEX_BACKEND "regcomp") + set(USE_REGEX "regcomp") else() - set(REGEX_BACKEND "regcomp_l") + set(USE_REGEX "regcomp_l") endif() elseif(PCRE_FOUND) - set(REGEX_BACKEND "pcre") + set(USE_REGEX "pcre") else() - set(REGEX_BACKEND "builtin") + set(USE_REGEX "builtin") endif() endif() -if(REGEX_BACKEND STREQUAL "regcomp_l") +if(USE_REGEX STREQUAL "regcomp_l") add_feature_info(regex ON "using system regcomp_l") set(GIT_REGEX_REGCOMP_L 1) -elseif(REGEX_BACKEND STREQUAL "pcre2") +elseif(USE_REGEX STREQUAL "pcre2") find_package(PCRE2) if(NOT PCRE2_FOUND) @@ -34,23 +42,23 @@ elseif(REGEX_BACKEND STREQUAL "pcre2") list(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE2_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${PCRE2_LIBRARIES}) list(APPEND LIBGIT2_PC_REQUIRES "libpcre2-8") -elseif(REGEX_BACKEND STREQUAL "pcre") +elseif(USE_REGEX STREQUAL "pcre") add_feature_info(regex ON "using system PCRE") set(GIT_REGEX_PCRE 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${PCRE_LIBRARIES}) list(APPEND LIBGIT2_PC_REQUIRES "libpcre") -elseif(REGEX_BACKEND STREQUAL "regcomp") +elseif(USE_REGEX STREQUAL "regcomp") add_feature_info(regex ON "using system regcomp") set(GIT_REGEX_REGCOMP 1) -elseif(REGEX_BACKEND STREQUAL "builtin") - add_feature_info(regex ON "using bundled PCRE") +elseif(USE_REGEX STREQUAL "builtin") + add_feature_info(regex ON "using builtin") set(GIT_REGEX_BUILTIN 1) add_subdirectory("${PROJECT_SOURCE_DIR}/deps/pcre" "${PROJECT_BINARY_DIR}/deps/pcre") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/pcre") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $) else() - message(FATAL_ERROR "The REGEX_BACKEND option provided is not supported") + message(FATAL_ERROR "unknown setting to ${OPTION_NAME}: ${USE_REGEX}") endif() From 9ea1f6d4ed11d93ec42440a07e6c178a7cc4265f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sun, 29 Dec 2024 23:28:12 +0000 Subject: [PATCH 765/816] cmake: standardize iconv options --- CMakeLists.txt | 9 ++++---- cmake/SelectI18n.cmake | 40 ++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 16 +------------- src/libgit2/libgit2.c | 6 +++-- src/libgit2/refs.c | 6 ++--- src/libgit2/repository.c | 2 +- src/util/fs_path.c | 16 +++++++------- src/util/fs_path.h | 6 ++--- src/util/git2_features.h.in | 20 +++++++++-------- tests/libgit2/core/features.c | 6 +++-- tests/libgit2/refs/unicode.c | 2 +- tests/libgit2/repo/init.c | 2 +- tests/libgit2/status/renames.c | 6 ++--- tests/util/iconv.c | 12 +++++----- 14 files changed, 91 insertions(+), 58 deletions(-) create mode 100644 cmake/SelectI18n.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 87be33af676..95c8c62f609 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,11 @@ option(USE_GSSAPI "Enable SPNEGO authentication using GSSAPI" OFF) set(USE_REGEX "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") set(USE_COMPRESSION "" CACHE STRING "Selects compression backend. Either builtin or zlib.") +if(APPLE) + # Currently only available on macOS for `precomposeUnicode` support + set(USE_I18N "" CACHE STRING "Enables internationalization support.") +endif() + # Debugging options option(USE_LEAK_CHECKER "Run tests with leak checker" OFF) option(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF) @@ -73,10 +78,6 @@ if(UNIX) option(ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds" OFF) endif() -if(APPLE) - option(USE_ICONV "Link with and use iconv library" ON) -endif() - if(MSVC) # This option must match the settings used in your program, in particular if you # are linking statically diff --git a/cmake/SelectI18n.cmake b/cmake/SelectI18n.cmake new file mode 100644 index 00000000000..1b4c6d7803b --- /dev/null +++ b/cmake/SelectI18n.cmake @@ -0,0 +1,40 @@ +include(SanitizeBool) + +find_package(IntlIconv) + +if(USE_I18N STREQUAL "" AND NOT USE_ICONV STREQUAL "") + sanitizebool(USE_ICONV) + set(USE_I18N "${USE_ICONV}") +endif() + +if(USE_I18N STREQUAL "") + set(USE_I18N ON) +endif() + +sanitizebool(USE_I18N) + +if(USE_I18N) + if(USE_I18N STREQUAL ON) + if(ICONV_FOUND) + set(USE_I18N "iconv") + else() + message(FATAL_ERROR "Unable to detect internationalization support") + endif() + endif() + + if(USE_I18N STREQUAL "iconv") + else() + message(FATAL_ERROR "unknown internationalization backend: ${USE_I18N}") + endif() + + list(APPEND LIBGIT2_SYSTEM_INCLUDES ${ICONV_INCLUDE_DIR}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${ICONV_LIBRARIES}) + list(APPEND LIBGIT2_PC_LIBS ${ICONV_LIBRARIES}) + + set(GIT_I18N 1) + set(GIT_I18N_ICONV 1) + add_feature_info(i18n ON "using ${USE_I18N}") +else() + set(GIT_I18N 0) + add_feature_info(i18n NO "internationalization support is disabled") +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90996aa5d3c..7e0106cfa24 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ include(SelectRegex) include(SelectXdiff) include(SelectSSH) include(SelectCompression) +include(SelectI18n) # # Platform support @@ -180,21 +181,6 @@ if(USE_NTLMCLIENT) endif() add_feature_info(ntlmclient GIT_NTLM "NTLM authentication support for Unix") -# -# Optional external dependencies - -# iconv -if(USE_ICONV) - find_package(IntlIconv) -endif() -if(ICONV_FOUND) - set(GIT_USE_ICONV 1) - list(APPEND LIBGIT2_SYSTEM_INCLUDES ${ICONV_INCLUDE_DIR}) - list(APPEND LIBGIT2_SYSTEM_LIBS ${ICONV_LIBRARIES}) - list(APPEND LIBGIT2_PC_LIBS ${ICONV_LIBRARIES}) -endif() -add_feature_info(iconv GIT_USE_ICONV "iconv encoding conversion support") - # # Include child projects # diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index a75fb0f9136..36a001e492d 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -95,7 +95,7 @@ int git_libgit2_features(void) #endif | GIT_FEATURE_HTTP_PARSER | GIT_FEATURE_REGEX -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV | GIT_FEATURE_I18N #endif #if defined(GIT_NTLM) || defined(GIT_WIN32) @@ -192,8 +192,10 @@ const char *git_libgit2_feature_backend(git_feature_t feature) break; case GIT_FEATURE_I18N: -#if defined(GIT_USE_ICONV) +#if defined(GIT_I18N_ICONV) return "iconv"; +#elif defined(GIT_I18N) + GIT_ASSERT_WITH_RETVAL(!"Unknown internationalization backend", NULL); #endif break; diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index 12dbd7aca9d..9bf1c6b45a1 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -917,7 +917,7 @@ int git_reference__normalize_name( bool allow_caret_prefix = true; bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0; -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_fs_path_iconv_t ic = GIT_PATH_ICONV_INIT; #endif @@ -932,7 +932,7 @@ int git_reference__normalize_name( if (normalize) git_str_clear(buf); -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV if ((flags & GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE) != 0) { size_t namelen = strlen(current); if ((error = git_fs_path_iconv_init_precompose(&ic)) < 0 || @@ -1032,7 +1032,7 @@ int git_reference__normalize_name( if (error && normalize) git_str_dispose(buf); -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_fs_path_iconv_clear(&ic); #endif diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 2c36458b367..5d6bf663d8f 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -2297,7 +2297,7 @@ static int repo_init_fs_configs( git_error_clear(); } -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV if ((error = git_config_set_bool( cfg, "core.precomposeunicode", git_fs_path_does_decompose_unicode(work_dir))) < 0) diff --git a/src/util/fs_path.c b/src/util/fs_path.c index 9d5c99eab81..e24836becaa 100644 --- a/src/util/fs_path.c +++ b/src/util/fs_path.c @@ -984,7 +984,7 @@ bool git_fs_path_has_non_ascii(const char *path, size_t pathlen) return false; } -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV int git_fs_path_iconv_init_precompose(git_fs_path_iconv_t *ic) { @@ -1136,7 +1136,7 @@ int git_fs_path_direach( DIR *dir; struct dirent *de; -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_fs_path_iconv_t ic = GIT_PATH_ICONV_INIT; #endif @@ -1155,7 +1155,7 @@ int git_fs_path_direach( return -1; } -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV if ((flags & GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE) != 0) (void)git_fs_path_iconv_init_precompose(&ic); #endif @@ -1167,7 +1167,7 @@ int git_fs_path_direach( if (git_fs_path_is_dot_or_dotdot(de_path)) continue; -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV if ((error = git_fs_path_iconv(&ic, &de_path, &de_len)) < 0) break; #endif @@ -1191,7 +1191,7 @@ int git_fs_path_direach( closedir(dir); -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_fs_path_iconv_clear(&ic); #endif @@ -1395,7 +1395,7 @@ int git_fs_path_diriter_init( return -1; } -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV if ((flags & GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE) != 0) (void)git_fs_path_iconv_init_precompose(&diriter->ic); #endif @@ -1432,7 +1432,7 @@ int git_fs_path_diriter_next(git_fs_path_diriter *diriter) filename = de->d_name; filename_len = strlen(filename); -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV if ((diriter->flags & GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE) != 0 && (error = git_fs_path_iconv(&diriter->ic, &filename, &filename_len)) < 0) return error; @@ -1499,7 +1499,7 @@ void git_fs_path_diriter_free(git_fs_path_diriter *diriter) diriter->dir = NULL; } -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_fs_path_iconv_clear(&diriter->ic); #endif diff --git a/src/util/fs_path.h b/src/util/fs_path.h index 43f7951adde..78b4c3dc0d9 100644 --- a/src/util/fs_path.h +++ b/src/util/fs_path.h @@ -449,7 +449,7 @@ extern bool git_fs_path_has_non_ascii(const char *path, size_t pathlen); #define GIT_PATH_NATIVE_ENCODING "UTF-8" #endif -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV #include @@ -473,7 +473,7 @@ extern void git_fs_path_iconv_clear(git_fs_path_iconv_t *ic); */ extern int git_fs_path_iconv(git_fs_path_iconv_t *ic, const char **in, size_t *inlen); -#endif /* GIT_USE_ICONV */ +#endif /* GIT_I18N_ICONV */ extern bool git_fs_path_does_decompose_unicode(const char *root); @@ -511,7 +511,7 @@ struct git_fs_path_diriter DIR *dir; -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_fs_path_iconv_t ic; #endif }; diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index c889202d76f..af7b5dd279d 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -11,23 +11,25 @@ #cmakedefine GIT_ARCH_64 1 #cmakedefine GIT_ARCH_32 1 -#cmakedefine GIT_USE_ICONV 1 +#cmakedefine GIT_I18N 1 +#cmakedefine GIT_I18N_ICONV 1 + #cmakedefine GIT_USE_NSEC 1 #cmakedefine GIT_USE_STAT_MTIM 1 #cmakedefine GIT_USE_STAT_MTIMESPEC 1 #cmakedefine GIT_USE_STAT_MTIME_NSEC 1 #cmakedefine GIT_USE_FUTIMENS 1 -#cmakedefine GIT_REGEX_REGCOMP_L -#cmakedefine GIT_REGEX_REGCOMP -#cmakedefine GIT_REGEX_PCRE -#cmakedefine GIT_REGEX_PCRE2 +#cmakedefine GIT_REGEX_REGCOMP_L 1 +#cmakedefine GIT_REGEX_REGCOMP 1 +#cmakedefine GIT_REGEX_PCRE 1 +#cmakedefine GIT_REGEX_PCRE2 1 #cmakedefine GIT_REGEX_BUILTIN 1 -#cmakedefine GIT_QSORT_BSD -#cmakedefine GIT_QSORT_GNU -#cmakedefine GIT_QSORT_C11 -#cmakedefine GIT_QSORT_MSC +#cmakedefine GIT_QSORT_BSD 1 +#cmakedefine GIT_QSORT_GNU 1 +#cmakedefine GIT_QSORT_C11 1 +#cmakedefine GIT_QSORT_MSC 1 #cmakedefine GIT_SSH 1 #cmakedefine GIT_SSH_EXEC 1 diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 8dba8e1a961..69426c04020 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -29,7 +29,7 @@ void test_core_features__basic(void) cl_assert((caps & GIT_FEATURE_HTTP_PARSER) != 0); cl_assert((caps & GIT_FEATURE_REGEX) != 0); -#if defined(GIT_USE_ICONV) +#if defined(GIT_I18N_ICONV) cl_assert((caps & GIT_FEATURE_I18N) != 0); #endif @@ -156,8 +156,10 @@ void test_core_features__backends(void) cl_assert(0); #endif -#if defined(GIT_USE_ICONV) +#if defined(GIT_I18N_ICONV) cl_assert_equal_s("iconv", i18n); +#elif defined(GIT_I18N) + cl_assert(0); #else cl_assert(i18n == NULL); #endif diff --git a/tests/libgit2/refs/unicode.c b/tests/libgit2/refs/unicode.c index a279d5006b3..5c69bc7c2bc 100644 --- a/tests/libgit2/refs/unicode.c +++ b/tests/libgit2/refs/unicode.c @@ -36,7 +36,7 @@ void test_refs_unicode__create_and_lookup(void) cl_assert_equal_s(REFNAME, git_reference_name(ref2)); git_reference_free(ref2); -#if GIT_USE_ICONV +#if GIT_I18N_ICONV /* Lookup reference by decomposed unicode name */ #define REFNAME_DECOMPOSED "refs/heads/" "A" "\314\212" "ngstro" "\314\210" "m" diff --git a/tests/libgit2/repo/init.c b/tests/libgit2/repo/init.c index 70624b6f259..063c4fc7c1c 100644 --- a/tests/libgit2/repo/init.c +++ b/tests/libgit2/repo/init.c @@ -328,7 +328,7 @@ void test_repo_init__symlinks_posix_detected(void) void test_repo_init__detect_precompose_unicode_required(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV char *composed = "ḱṷṓn", *decomposed = "ḱṷṓn"; struct stat st; bool found_with_nfd; diff --git a/tests/libgit2/status/renames.c b/tests/libgit2/status/renames.c index d5cf87d07e9..f31e3be9f34 100644 --- a/tests/libgit2/status/renames.c +++ b/tests/libgit2/status/renames.c @@ -584,7 +584,7 @@ void test_status_renames__zero_byte_file_does_not_fail(void) git_status_list_free(statuslist); } -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV static char *nfc = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D"; static char *nfd = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D"; #endif @@ -597,7 +597,7 @@ static char *nfd = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D"; */ void test_status_renames__precomposed_unicode_rename(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected0[] = { @@ -649,7 +649,7 @@ void test_status_renames__precomposed_unicode_rename(void) void test_status_renames__precomposed_unicode_toggle_is_rename(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected0[] = { diff --git a/tests/util/iconv.c b/tests/util/iconv.c index e14aebb9908..4eb2aa5bb4a 100644 --- a/tests/util/iconv.c +++ b/tests/util/iconv.c @@ -1,7 +1,7 @@ #include "clar_libgit2.h" #include "fs_path.h" -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV static git_fs_path_iconv_t ic; static char *nfc = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D"; static char *nfd = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D"; @@ -9,21 +9,21 @@ static char *nfd = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D"; void test_iconv__initialize(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV cl_git_pass(git_fs_path_iconv_init_precompose(&ic)); #endif } void test_iconv__cleanup(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV git_fs_path_iconv_clear(&ic); #endif } void test_iconv__unchanged(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV const char *data = "Ascii data", *original = data; size_t datalen = strlen(data); @@ -37,7 +37,7 @@ void test_iconv__unchanged(void) void test_iconv__decomposed_to_precomposed(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV const char *data = nfd; size_t datalen, nfdlen = strlen(nfd); @@ -63,7 +63,7 @@ void test_iconv__decomposed_to_precomposed(void) void test_iconv__precomposed_is_unmodified(void) { -#ifdef GIT_USE_ICONV +#ifdef GIT_I18N_ICONV const char *data = nfc; size_t datalen = strlen(nfc); From fb59acb24652383baf46744892058a044d12724f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 30 Dec 2024 22:28:34 +0000 Subject: [PATCH 766/816] cmake: update NTLM feature enablement --- CMakeLists.txt | 8 +---- cmake/SelectAuthNTLM.cmake | 46 ++++++++++++++++++++++++ src/CMakeLists.txt | 14 +------- src/libgit2/libgit2.c | 10 +++--- src/libgit2/transports/auth_ntlm.h | 4 +-- src/libgit2/transports/auth_ntlmclient.c | 4 +-- src/util/git2_features.h.in | 5 ++- tests/libgit2/core/features.c | 10 +++--- 8 files changed, 68 insertions(+), 33 deletions(-) create mode 100644 cmake/SelectAuthNTLM.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 95c8c62f609..33a392c632b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ option(USE_NSEC "Support nanosecond precision file mtimes and cti set(USE_SHA256 "" CACHE STRING "Selects SHA256 provider. One of Builtin, HTTPS, or a specific provider. (Defaults to HTTPS.)") option(USE_GSSAPI "Enable SPNEGO authentication using GSSAPI" OFF) set(USE_HTTP_PARSER "" CACHE STRING "Selects HTTP Parser support: http-parser, llhttp, or builtin. (Defaults to builtin.)") + set(USE_AUTH_NTLM "" CACHE STRING "Enables NTLM authentication support. One of Builtin or win32.") # set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") set(USE_REGEX "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") set(USE_COMPRESSION "" CACHE STRING "Selects compression backend. Either builtin or zlib.") @@ -68,13 +69,6 @@ option(CMAKE_C_EXTENSIONS "Whether compiler extensions are supported" option(ENABLE_WERROR "Enable compilation with -Werror" OFF) if(UNIX) - # NTLM client requires crypto libraries from the system HTTPS stack - if(USE_HTTPS STREQUAL "OFF") - option(USE_NTLMCLIENT "Enable NTLM support on Unix." OFF) - else() - option(USE_NTLMCLIENT "Enable NTLM support on Unix." ON) - endif() - option(ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds" OFF) endif() diff --git a/cmake/SelectAuthNTLM.cmake b/cmake/SelectAuthNTLM.cmake new file mode 100644 index 00000000000..105c4bbc38e --- /dev/null +++ b/cmake/SelectAuthNTLM.cmake @@ -0,0 +1,46 @@ +include(SanitizeBool) + +if(USE_AUTH_NTLM STREQUAL "" AND NOT USE_NTLMCLIENT STREQUAL "") + sanitizebool(USE_NTLMCLIENT) + set(USE_AUTH_NTLM "${USE_NTLMCLIENT}") +endif() + +sanitizebool(USE_AUTH_NTLM) + +if(USE_AUTH_NTLM STREQUAL "") + set(USE_AUTH_NTLM ON) +endif() + +if(USE_AUTH_NTLM STREQUAL ON AND UNIX) + set(USE_AUTH_NTLM "builtin") +elseif(USE_AUTH_NTLM STREQUAL ON AND WIN32) + set(USE_AUTH_NTLM "sspi") +elseif(USE_AUTH_NTLM STREQUAL ON) + message(FATAL_ERROR "ntlm support was requested but no backend is available") +endif() + +if(USE_AUTH_NTLM STREQUAL "builtin") + if(NOT UNIX) + message(FATAL_ERROR "ntlm support requested via builtin provider, but builtin ntlmclient only supports posix platforms") + endif() + + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/ntlmclient" "${PROJECT_BINARY_DIR}/deps/ntlmclient") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/ntlmclient") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") + + set(GIT_AUTH_NTLM 1) + set(GIT_AUTH_NTLM_BUILTIN 1) + add_feature_info("NTLM authentication" ON "using bundled ntlmclient") +elseif(USE_AUTH_NTLM STREQUAL "sspi") + if(NOT WIN32) + message(FATAL_ERROR "SSPI is only available on Win32") + endif() + + set(GIT_AUTH_NTLM 1) + set(GIT_AUTH_NTLM_SSPI 1) + add_feature_info("NTLM authentication" ON "using Win32 SSPI") +elseif(USE_AUTH_NTLM STREQUAL OFF OR USE_AUTH_NTLM STREQUAL "") + add_feature_info("NTLM authentication" OFF "NTLM support is disabled") +else() + message(FATAL_ERROR "unknown ntlm option: ${USE_AUTH_NTLM}") +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7e0106cfa24..02895f98096 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -45,6 +45,7 @@ include(SelectXdiff) include(SelectSSH) include(SelectCompression) include(SelectI18n) +include(SelectAuthNTLM) # # Platform support @@ -168,19 +169,6 @@ if(USE_THREADS) endif() add_feature_info(threadsafe USE_THREADS "threadsafe support") -# -# Optional bundled features -# - -# ntlmclient -if(USE_NTLMCLIENT) - set(GIT_NTLM 1) - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/ntlmclient" "${PROJECT_BINARY_DIR}/deps/ntlmclient") - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/ntlmclient") - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") -endif() -add_feature_info(ntlmclient GIT_NTLM "NTLM authentication support for Unix") - # # Include child projects # diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 36a001e492d..f51dce3e082 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -98,7 +98,7 @@ int git_libgit2_features(void) #ifdef GIT_I18N_ICONV | GIT_FEATURE_I18N #endif -#if defined(GIT_NTLM) || defined(GIT_WIN32) +#if defined(GIT_AUTH_NTLM) | GIT_FEATURE_AUTH_NTLM #endif #if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) @@ -200,10 +200,12 @@ const char *git_libgit2_feature_backend(git_feature_t feature) break; case GIT_FEATURE_AUTH_NTLM: -#if defined(GIT_NTLM) - return "ntlmclient"; -#elif defined(GIT_WIN32) +#if defined(GIT_AUTH_NTLM_BUILTIN) + return "builtin"; +#elif defined(GIT_AUTH_NTLM_SSPI) return "sspi"; +#elif defined(GIT_AUTH_NTLM) + GIT_ASSERT_WITH_RETVAL(!"Unknown NTLM backend", NULL); #endif break; diff --git a/src/libgit2/transports/auth_ntlm.h b/src/libgit2/transports/auth_ntlm.h index 33406ae94c3..b6610d94018 100644 --- a/src/libgit2/transports/auth_ntlm.h +++ b/src/libgit2/transports/auth_ntlm.h @@ -13,7 +13,7 @@ /* NTLM requires a full request/challenge/response */ #define GIT_AUTH_STEPS_NTLM 2 -#if defined(GIT_NTLM) || defined(GIT_WIN32) +#if defined(GIT_AUTH_NTLM) #if defined(GIT_OPENSSL) # define CRYPT_OPENSSL @@ -31,7 +31,7 @@ extern int git_http_auth_ntlm( #define git_http_auth_ntlm git_http_auth_dummy -#endif /* GIT_NTLM */ +#endif /* GIT_AUTH_NTLM */ #endif diff --git a/src/libgit2/transports/auth_ntlmclient.c b/src/libgit2/transports/auth_ntlmclient.c index 6f26a6179c6..b8c6e2353c1 100644 --- a/src/libgit2/transports/auth_ntlmclient.c +++ b/src/libgit2/transports/auth_ntlmclient.c @@ -12,7 +12,7 @@ #include "auth.h" #include "git2/sys/credential.h" -#ifdef GIT_NTLM +#ifdef GIT_AUTH_NTLM_BUILTIN #include "ntlmclient.h" @@ -224,4 +224,4 @@ int git_http_auth_ntlm( return 0; } -#endif /* GIT_NTLM */ +#endif /* GIT_AUTH_NTLM_BUILTIN */ diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index af7b5dd279d..27c2f688f83 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -36,7 +36,10 @@ #cmakedefine GIT_SSH_LIBSSH2 1 #cmakedefine GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1 -#cmakedefine GIT_NTLM 1 +#cmakedefine GIT_AUTH_NTLM 1 +#cmakedefine GIT_AUTH_NTLM_BUILTIN 1 +#cmakedefine GIT_AUTH_NTLM_SSPI 1 + #cmakedefine GIT_GSSAPI 1 #cmakedefine GIT_GSSFRAMEWORK 1 diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 69426c04020..26e3e51b1d1 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -33,7 +33,7 @@ void test_core_features__basic(void) cl_assert((caps & GIT_FEATURE_I18N) != 0); #endif -#if defined(GIT_NTLM) || defined(GIT_WIN32) +#if defined(GIT_AUTH_NTLM) cl_assert((caps & GIT_FEATURE_AUTH_NTLM) != 0); #endif #if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) @@ -164,10 +164,12 @@ void test_core_features__backends(void) cl_assert(i18n == NULL); #endif -#if defined(GIT_NTLM) - cl_assert_equal_s("ntlmclient", ntlm); -#elif defined(GIT_WIN32) +#if defined(GIT_AUTH_NTLM_BUILTIN) + cl_assert_equal_s("builtin", ntlm); +#elif defined(GIT_AUTH_NTLM_SSPI) cl_assert_equal_s("sspi", ntlm); +#elif defined(GIT_AUTH_NTLM) + cl_assert(0); #else cl_assert(ntlm == NULL); #endif From c9974d28b2f00d69525085390b54817c77d1b6bb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 10:46:26 +0000 Subject: [PATCH 767/816] cmake: update Negotiate backend selection --- CMakeLists.txt | 2 +- cmake/SelectAuthNegotiate.cmake | 61 +++++++++++++++++++++++++ cmake/SelectGSSAPI.cmake | 48 ------------------- src/CMakeLists.txt | 2 +- src/libgit2/libgit2.c | 10 ++-- src/libgit2/transports/auth_gssapi.c | 16 +++---- src/libgit2/transports/auth_negotiate.h | 4 +- src/util/git2_features.h.in | 6 ++- tests/libgit2/core/features.c | 10 ++-- 9 files changed, 91 insertions(+), 68 deletions(-) create mode 100644 cmake/SelectAuthNegotiate.cmake delete mode 100644 cmake/SelectGSSAPI.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 33a392c632b..04dab76e7aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,9 +34,9 @@ option(USE_NSEC "Support nanosecond precision file mtimes and cti set(USE_HTTPS "" CACHE STRING "Enable HTTPS support and optionally selects the provider. One of ON, OFF, or a specific provider: OpenSSL, OpenSSL-FIPS, OpenSSL-Dynamic, mbedTLS, SecureTransport, Schannel, or WinHTTP. (Defaults to ON.)") set(USE_SHA1 "" CACHE STRING "Selects SHA1 provider. One of builtin, HTTPS, or a specific provider. (Defaults to builtin.)") set(USE_SHA256 "" CACHE STRING "Selects SHA256 provider. One of Builtin, HTTPS, or a specific provider. (Defaults to HTTPS.)") -option(USE_GSSAPI "Enable SPNEGO authentication using GSSAPI" OFF) set(USE_HTTP_PARSER "" CACHE STRING "Selects HTTP Parser support: http-parser, llhttp, or builtin. (Defaults to builtin.)") set(USE_AUTH_NTLM "" CACHE STRING "Enables NTLM authentication support. One of Builtin or win32.") + set(USE_AUTH_NEGOTIATE "" CACHE STRING "Enable Negotiate (SPNEGO) authentication support. One of GSSAPI or win32.") # set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") set(USE_REGEX "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") set(USE_COMPRESSION "" CACHE STRING "Selects compression backend. Either builtin or zlib.") diff --git a/cmake/SelectAuthNegotiate.cmake b/cmake/SelectAuthNegotiate.cmake new file mode 100644 index 00000000000..3615571bc27 --- /dev/null +++ b/cmake/SelectAuthNegotiate.cmake @@ -0,0 +1,61 @@ +include(SanitizeBool) + +find_package(GSSAPI) + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "iOS") + include(FindGSSFramework) +endif() + +if(USE_AUTH_NEGOTIATE STREQUAL "" AND NOT USE_GSSAPI STREQUAL "") + sanitizebool(USE_GSSAPI) + set(USE_AUTH_NEGOTIATE "${USE_GSSAPI}") +endif() + +sanitizebool(USE_AUTH_NEGOTIATE) + +if((USE_AUTH_NEGOTIATE STREQUAL ON OR USE_AUTH_NEGOTIATE STREQUAL "") AND GSSFRAMEWORK_FOUND) + set(USE_AUTH_NEGOTIATE "GSS.framework") +elseif((USE_AUTH_NEGOTIATE STREQUAL ON OR USE_AUTH_NEGOTIATE STREQUAL "") AND GSSAPI_FOUND) + set(USE_AUTH_NEGOTIATE "gssapi") +elseif((USE_AUTH_NEGOTIATE STREQUAL ON OR USE_AUTH_NEGOTIATE STREQUAL "") AND WIN32) + set(USE_AUTH_NEGOTIATE "sspi") +elseif(USE_AUTH_NEGOTIATE STREQUAL "") + set(USE_AUTH_NEGOTIATE OFF) +elseif(USE_AUTH_NEGOTIATE STREQUAL ON) + message(FATAL_ERROR "negotiate support was requested but no backend is available") +endif() + +if(USE_AUTH_NEGOTIATE STREQUAL "GSS.framework") + if(NOT GSSFRAMEWORK_FOUND) + message(FATAL_ERROR "GSS.framework could not be found") + endif() + + list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSFRAMEWORK_LIBRARIES}) + + set(GIT_AUTH_NEGOTIATE 1) + set(GIT_AUTH_NEGOTIATE_GSSFRAMEWORK 1) + add_feature_info("Negotiate authentication" ON "using GSS.framework") +elseif(USE_AUTH_NEGOTIATE STREQUAL "gssapi") + if(NOT GSSAPI_FOUND) + message(FATAL_ERROR "GSSAPI could not be found") + endif() + + list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSAPI_LIBRARIES}) + + set(GIT_AUTH_NEGOTIATE 1) + set(GIT_AUTH_NEGOTIATE_GSSAPI 1) + add_feature_info("Negotiate authentication" ON "using GSSAPI") +elseif(USE_AUTH_NEGOTIATE STREQUAL "sspi") + if(NOT WIN32) + message(FATAL_ERROR "SSPI is only available on Win32") + endif() + + set(GIT_AUTH_NEGOTIATE 1) + set(GIT_AUTH_NEGOTIATE_SSPI 1) + add_feature_info("Negotiate authentication" ON "using Win32 SSPI") +elseif(USE_AUTH_NEGOTIATE STREQUAL OFF) + set(GIT_AUTH_NEGOTIATE 0) + add_feature_info("Negotiate authentication" OFF "SPNEGO support is disabled") +else() + message(FATAL_ERROR "unknown negotiate option: ${USE_AUTH_NEGOTIATE}") +endif() diff --git a/cmake/SelectGSSAPI.cmake b/cmake/SelectGSSAPI.cmake deleted file mode 100644 index 829850a4de9..00000000000 --- a/cmake/SelectGSSAPI.cmake +++ /dev/null @@ -1,48 +0,0 @@ -include(SanitizeBool) - -# We try to find any packages our backends might use -find_package(GSSAPI) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "iOS") - include(FindGSSFramework) -endif() - -if(USE_GSSAPI) - # Auto-select GSS backend - sanitizebool(USE_GSSAPI) - if(USE_GSSAPI STREQUAL ON) - if(GSSFRAMEWORK_FOUND) - set(USE_GSSAPI "GSS.framework") - elseif(GSSAPI_FOUND) - set(USE_GSSAPI "gssapi") - else() - message(FATAL_ERROR "Unable to autodetect a usable GSS backend." - "Please pass the backend name explicitly (-DUSE_GSS=backend)") - endif() - endif() - - # Check that we can find what's required for the selected backend - if(USE_GSSAPI STREQUAL "GSS.framework") - if(NOT GSSFRAMEWORK_FOUND) - message(FATAL_ERROR "Asked for GSS.framework backend, but it wasn't found") - endif() - - list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSFRAMEWORK_LIBRARIES}) - - set(GIT_GSSFRAMEWORK 1) - add_feature_info(GSSAPI GIT_GSSFRAMEWORK "GSSAPI support for SPNEGO authentication (${USE_GSSAPI})") - elseif(USE_GSSAPI STREQUAL "gssapi") - if(NOT GSSAPI_FOUND) - message(FATAL_ERROR "Asked for gssapi GSS backend, but it wasn't found") - endif() - - list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSAPI_LIBRARIES}) - - set(GIT_GSSAPI 1) - add_feature_info(GSSAPI GIT_GSSAPI "GSSAPI support for SPNEGO authentication (${USE_GSSAPI})") - else() - message(FATAL_ERROR "Asked for backend ${USE_GSSAPI} but it wasn't found") - endif() -else() - set(GIT_GSSAPI 0) - add_feature_info(GSSAPI NO "GSSAPI support for SPNEGO authentication") -endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 02895f98096..d6e6cf54230 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,7 +36,6 @@ add_feature_info(debugopen GIT_DEBUG_STRICT_OPEN "path validation in open") # Optional feature enablement # -include(SelectGSSAPI) include(SelectHTTPSBackend) include(SelectHashes) include(SelectHTTPParser) @@ -46,6 +45,7 @@ include(SelectSSH) include(SelectCompression) include(SelectI18n) include(SelectAuthNTLM) +include(SelectAuthNegotiate) # # Platform support diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index f51dce3e082..537a839a114 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -101,7 +101,7 @@ int git_libgit2_features(void) #if defined(GIT_AUTH_NTLM) | GIT_FEATURE_AUTH_NTLM #endif -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) +#if defined(GIT_AUTH_NEGOTIATE) | GIT_FEATURE_AUTH_NEGOTIATE #endif | GIT_FEATURE_COMPRESSION @@ -210,10 +210,14 @@ const char *git_libgit2_feature_backend(git_feature_t feature) break; case GIT_FEATURE_AUTH_NEGOTIATE: -#if defined(GIT_GSSAPI) +#if defined(GIT_AUTH_NEGOTIATE_GSSFRAMEWORK) + return "gssframework"; +#elif defined(GIT_AUTH_NEGOTIATE_GSSAPI) return "gssapi"; -#elif defined(GIT_WIN32) +#elif defined(GIT_AUTH_NEGOTIATE_SSPI) return "sspi"; +#elif defined(GIT_AUTH_NEGOTIATE) + GIT_ASSERT_WITH_RETVAL(!"Unknown Negotiate backend", NULL); #endif break; diff --git a/src/libgit2/transports/auth_gssapi.c b/src/libgit2/transports/auth_gssapi.c index 5005538411b..647f3ce3fa0 100644 --- a/src/libgit2/transports/auth_gssapi.c +++ b/src/libgit2/transports/auth_gssapi.c @@ -7,17 +7,18 @@ #include "auth_negotiate.h" -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) +#if defined(GIT_AUTH_NEGOTIATE_GSSAPI) || \ + defined(GIT_AUTH_NEGOTIATE_GSSFRAMEWORK) #include "git2.h" #include "auth.h" #include "git2/sys/credential.h" -#ifdef GIT_GSSFRAMEWORK -#import -#elif defined(GIT_GSSAPI) -#include -#include +#if defined(GIT_AUTH_NEGOTIATE_GSSFRAMEWORK) +# import +#elif defined(GIT_AUTH_NEGOTIATE_GSSAPI) +# include +# include #endif static gss_OID_desc gssapi_oid_spnego = @@ -310,5 +311,4 @@ int git_http_auth_negotiate( return 0; } -#endif /* GIT_GSSAPI */ - +#endif /* GIT_AUTH_NEGOTIATE_GSS... */ diff --git a/src/libgit2/transports/auth_negotiate.h b/src/libgit2/transports/auth_negotiate.h index 4360785c555..e528b402a9a 100644 --- a/src/libgit2/transports/auth_negotiate.h +++ b/src/libgit2/transports/auth_negotiate.h @@ -12,7 +12,7 @@ #include "git2.h" #include "auth.h" -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) +#ifdef GIT_AUTH_NEGOTIATE extern int git_http_auth_negotiate( git_http_auth_context **out, @@ -22,6 +22,6 @@ extern int git_http_auth_negotiate( #define git_http_auth_negotiate git_http_auth_dummy -#endif /* GIT_GSSAPI */ +#endif /* GIT_AUTH_NEGOTIATE */ #endif diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 27c2f688f83..a5cf6a9e0fb 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -40,8 +40,10 @@ #cmakedefine GIT_AUTH_NTLM_BUILTIN 1 #cmakedefine GIT_AUTH_NTLM_SSPI 1 -#cmakedefine GIT_GSSAPI 1 -#cmakedefine GIT_GSSFRAMEWORK 1 +#cmakedefine GIT_AUTH_NEGOTIATE 1 +#cmakedefine GIT_AUTH_NEGOTIATE_GSSFRAMEWORK 1 +#cmakedefine GIT_AUTH_NEGOTIATE_GSSAPI 1 +#cmakedefine GIT_AUTH_NEGOTIATE_SSPI 1 #cmakedefine GIT_WINHTTP 1 #cmakedefine GIT_HTTPS 1 diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 26e3e51b1d1..9eaa9f35055 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -36,7 +36,7 @@ void test_core_features__basic(void) #if defined(GIT_AUTH_NTLM) cl_assert((caps & GIT_FEATURE_AUTH_NTLM) != 0); #endif -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) +#if defined(GIT_AUTH_NEGOTIATE) cl_assert((caps & GIT_FEATURE_AUTH_NEGOTIATE) != 0); #endif @@ -174,10 +174,14 @@ void test_core_features__backends(void) cl_assert(ntlm == NULL); #endif -#if defined(GIT_GSSAPI) +#if defined(GIT_AUTH_NEGOTIATE_GSSFRAMEWORK) + cl_assert_equal_s("gssframework", negotiate); +#elif defined(GIT_AUTH_NEGOTIATE_GSSAPI) cl_assert_equal_s("gssapi", negotiate); -#elif defined(GIT_WIN32) +#elif defined(GIT_AUTH_NEGOTIATE_SSPI) cl_assert_equal_s("sspi", negotiate); +#elif defined(GIT_AUTH_NEGOTIATE) + cl_assert(0); #else cl_assert(negotiate == NULL); #endif From 8bbd2f406eeb904d976f4de1ee76d0435d577264 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 10:56:24 +0000 Subject: [PATCH 768/816] cmake: use DEBUG_LEAK_CHECKER as option The `USE_` prefix for inputs denotes a backend; the `DEBUG_` prefix denotes a debugging option. Make `DEBUG_LEAK_CHECKER` the name of the leak checking option. --- .github/workflows/experimental.yml | 4 ++-- .github/workflows/main.yml | 10 ++++---- .github/workflows/nightly.yml | 38 +++++++++++++++--------------- CMakeLists.txt | 2 +- cmake/AddClarTest.cmake | 6 +++-- src/CMakeLists.txt | 2 +- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml index 07442bddecb..8ffb4b63cbc 100644 --- a/.github/workflows/experimental.yml +++ b/.github/workflows/experimental.yml @@ -34,14 +34,14 @@ jobs: env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON - name: "macOS (SHA256)" id: macos-sha256 os: macos-13 setup-script: osx env: CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3616c743d7e..f6af730b10a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - name: "Linux (Noble, Clang, mbedTLS, OpenSSH)" id: noble-clang-mbedtls os: ubuntu-latest @@ -42,7 +42,7 @@ jobs: name: noble env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DUSE_HTTP_PARSER=http-parser + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DUSE_HTTP_PARSER=http-parser CMAKE_GENERATOR: Ninja - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" id: xenial-gcc-openssl @@ -52,7 +52,7 @@ jobs: env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" id: xenial-gcc-mbedtls os: ubuntu-latest @@ -61,14 +61,14 @@ jobs: env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - name: "macOS" id: macos os: macos-13 setup-script: osx env: CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b9392f84063..a12803d5b16 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -35,7 +35,7 @@ jobs: env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - name: "Linux (Noble, Clang, mbedTLS, OpenSSH)" id: noble-clang-mbedtls os: ubuntu-latest @@ -43,7 +43,7 @@ jobs: name: noble env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DUSE_HTTP_PARSER=http-parser + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DUSE_HTTP_PARSER=http-parser CMAKE_GENERATOR: Ninja - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" id: xenial-gcc-openssl @@ -53,7 +53,7 @@ jobs: env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" id: xenial-gcc-mbedtls os: ubuntu-latest @@ -62,14 +62,14 @@ jobs: env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - name: "macOS" id: macos os: macos-13 setup-script: osx env: CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true @@ -80,7 +80,7 @@ jobs: setup-script: ios env: CC: clang - CMAKE_OPTIONS: -DBUILD_TESTS=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 + CMAKE_OPTIONS: -DBUILD_TESTS=OFF -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DCMAKE_SYSTEM_NAME=iOS -DPLATFORM=OS64 CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_TESTS: true # Cannot exec iOS app on macOS @@ -188,7 +188,7 @@ jobs: container: name: centos7 env: - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_PUSHOPTIONS_TESTS: true @@ -198,7 +198,7 @@ jobs: container: name: centos7 env: - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_PUSHOPTIONS_TESTS: true @@ -208,7 +208,7 @@ jobs: container: name: centos8 env: - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true @@ -218,7 +218,7 @@ jobs: container: name: centos8 env: - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true @@ -231,7 +231,7 @@ jobs: env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=pcre2 -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DUSE_HTTP_PARSER=llhttp + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=pcre2 -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DUSE_HTTP_PARSER=llhttp - name: "Linux (Bionic, GCC, dynamically-loaded OpenSSL)" id: bionic-gcc-dynamicopenssl container: @@ -240,7 +240,7 @@ jobs: env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest @@ -253,7 +253,7 @@ jobs: env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest @@ -265,7 +265,7 @@ jobs: env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest @@ -307,7 +307,7 @@ jobs: name: xenial env: CC: gcc - CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_PUSHOPTIONS_TESTS: true - name: "Linux (no mmap)" @@ -341,7 +341,7 @@ jobs: name: xenial env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja # All builds: experimental SHA256 support @@ -352,7 +352,7 @@ jobs: env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON os: ubuntu-latest - name: "macOS (SHA256)" id: macos-sha256 @@ -360,7 +360,7 @@ jobs: setup-script: osx env: CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true @@ -382,7 +382,7 @@ jobs: env: CC: clang CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DUSE_SHA1=OpenSSL-FIPS -DUSE_SHA256=OpenSSL-FIPS + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DDEBUG_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DUSE_SHA1=OpenSSL-FIPS -DUSE_SHA256=OpenSSL-FIPS os: ubuntu-latest fail-fast: false env: ${{ matrix.platform.env }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 04dab76e7aa..060d8b7e317 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ if(APPLE) endif() # Debugging options -option(USE_LEAK_CHECKER "Run tests with leak checker" OFF) + set(DEBUG_LEAK_CHECKER "" CACHE STRING "Run tests with leak checker. Either valgrind or leaks.") option(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF) option(DEBUG_POOL "Enable debug pool allocator" OFF) option(DEBUG_STRICT_ALLOC "Enable strict allocator behavior" OFF) diff --git a/cmake/AddClarTest.cmake b/cmake/AddClarTest.cmake index 74394163825..26e9273306f 100644 --- a/cmake/AddClarTest.cmake +++ b/cmake/AddClarTest.cmake @@ -1,6 +1,8 @@ function(ADD_CLAR_TEST project name) - if(NOT USE_LEAK_CHECKER STREQUAL "OFF") - add_test(${name} "${PROJECT_SOURCE_DIR}/script/${USE_LEAK_CHECKER}.sh" "${PROJECT_BINARY_DIR}/${project}" ${ARGN}) + if(NOT DEBUG_LEAK_CHECKER STREQUAL "OFF" AND + NOT DEBUG_LEAK_CHECKER STREQUAL "" AND + NOT DEBUG_LEAK_CHECKER STREQUAL "win32") + add_test(${name} "${PROJECT_SOURCE_DIR}/script/${DEBUG_LEAK_CHECKER}.sh" "${PROJECT_BINARY_DIR}/${project}" ${ARGN}) else() add_test(${name} "${PROJECT_BINARY_DIR}/${project}" ${ARGN}) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6e6cf54230..3921489a58b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,7 @@ if(DEPRECATE_HARD) add_definitions(-DGIT_DEPRECATE_HARD) endif() -if(USE_LEAK_CHECKER STREQUAL "valgrind") +if(DEBUG_LEAK_CHECKER STREQUAL "valgrind") add_definitions(-DVALGRIND) endif() From 890d70856cbab8af641bffd3a878272aac70f438 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 11:29:41 +0000 Subject: [PATCH 769/816] cmake: update nanosecond selection For consistency, specify the nanosecond option in the same way as other options, and identify it as such. Split the detection of platform support (`FindStatNsec`) and its selection (`SelectNsec`). --- CMakeLists.txt | 4 +- cmake/FindStatNsec.cmake | 14 ------ cmake/SelectNsec.cmake | 58 +++++++++++++++++++++++ src/CMakeLists.txt | 17 +------ src/libgit2/index.c | 2 +- src/libgit2/index.h | 4 +- src/libgit2/iterator.c | 2 +- src/libgit2/libgit2.c | 14 +++--- src/util/futils.c | 6 +-- src/util/git2_features.h.in | 10 ++-- src/util/unix/posix.h | 8 ++-- src/util/win32/w32_util.h | 4 +- tests/libgit2/checkout/checkout_helpers.h | 1 + tests/libgit2/core/features.c | 14 +++--- tests/libgit2/merge/workdir/dirty.c | 2 +- 15 files changed, 97 insertions(+), 63 deletions(-) create mode 100644 cmake/SelectNsec.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 060d8b7e317..b90e7c1276a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,9 +27,8 @@ option(BUILD_FUZZERS "Build the fuzz targets" # Suggested functionality that may not be available on a per-platform basis option(USE_THREADS "Use threads for parallel processing when possible" ON) -option(USE_NSEC "Support nanosecond precision file mtimes and ctimes" ON) -# Backend selection +# Feature enablement and backend selection set(USE_SSH "" CACHE STRING "Enables SSH support and optionally selects provider. One of ON, OFF, or a specific provider: libssh2 or exec. (Defaults to OFF.)") set(USE_HTTPS "" CACHE STRING "Enable HTTPS support and optionally selects the provider. One of ON, OFF, or a specific provider: OpenSSL, OpenSSL-FIPS, OpenSSL-Dynamic, mbedTLS, SecureTransport, Schannel, or WinHTTP. (Defaults to ON.)") set(USE_SHA1 "" CACHE STRING "Selects SHA1 provider. One of builtin, HTTPS, or a specific provider. (Defaults to builtin.)") @@ -40,6 +39,7 @@ option(USE_NSEC "Support nanosecond precision file mtimes and cti # set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") set(USE_REGEX "" CACHE STRING "Selects regex provider. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") set(USE_COMPRESSION "" CACHE STRING "Selects compression backend. Either builtin or zlib.") + set(USE_NSEC "" CACHE STRING "Enable nanosecond precision timestamps. One of ON, OFF, or a specific provider: mtimespec, mtim, mtime, or win32. (Defaults to ON).") if(APPLE) # Currently only available on macOS for `precomposeUnicode` support diff --git a/cmake/FindStatNsec.cmake b/cmake/FindStatNsec.cmake index 9dfdf51c4e7..368cfedc1cc 100644 --- a/cmake/FindStatNsec.cmake +++ b/cmake/FindStatNsec.cmake @@ -1,20 +1,6 @@ -include(FeatureSummary) - check_struct_has_member("struct stat" st_mtim "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIM LANGUAGE C) check_struct_has_member("struct stat" st_mtimespec "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC LANGUAGE C) check_struct_has_member("struct stat" st_mtime_nsec sys/stat.h HAVE_STRUCT_STAT_MTIME_NSEC LANGUAGE C) - -if(HAVE_STRUCT_STAT_ST_MTIM) - check_struct_has_member("struct stat" st_mtim.tv_nsec sys/stat.h - HAVE_STRUCT_STAT_NSEC LANGUAGE C) -elseif(HAVE_STRUCT_STAT_ST_MTIMESPEC) - check_struct_has_member("struct stat" st_mtimespec.tv_nsec sys/stat.h - HAVE_STRUCT_STAT_NSEC LANGUAGE C) -else() - set(HAVE_STRUCT_STAT_NSEC ON ) -endif() - -add_feature_info(nanoseconds USE_NSEC "support nanosecond precision file mtimes and ctimes") diff --git a/cmake/SelectNsec.cmake b/cmake/SelectNsec.cmake new file mode 100644 index 00000000000..392b92bc45c --- /dev/null +++ b/cmake/SelectNsec.cmake @@ -0,0 +1,58 @@ +include(SanitizeBool) +include(FeatureSummary) + +sanitizebool(USE_NSEC) + +if((USE_NSEC STREQUAL ON OR USE_NSEC STREQUAL "") AND HAVE_STRUCT_STAT_ST_MTIM) + set(USE_NSEC "mtim") +elseif((USE_NSEC STREQUAL ON OR USE_NSEC STREQUAL "") AND HAVE_STRUCT_STAT_ST_MTIMESPEC) + set(USE_NSEC "mtimespec") +elseif((USE_NSEC STREQUAL ON OR USE_NSEC STREQUAL "") AND HAVE_STRUCT_STAT_MTIME_NSEC) + set(USE_NSEC "mtime_nsec") +elseif((USE_NSEC STREQUAL ON OR USE_NSEC STREQUAL "") AND WIN32) + set(USE_NSEC "win32") +elseif(USE_NSEC STREQUAL "") + message(WARNING "nanosecond timestamp precision was not detected") + set(USE_NSEC OFF) +elseif(USE_NSEC STREQUAL ON) + message(FATAL_ERROR "nanosecond support was requested but no platform support is available") +endif() + +if(USE_NSEC STREQUAL "mtim") + if(NOT HAVE_STRUCT_STAT_ST_MTIM) + message(FATAL_ERROR "stat mtim could not be found") + endif() + + set(GIT_NSEC 1) + set(GIT_NSEC_MTIM 1) + add_feature_info("Nanosecond support" ON "using mtim") +elseif(USE_NSEC STREQUAL "mtimespec") + if(NOT HAVE_STRUCT_STAT_ST_MTIMESPEC) + message(FATAL_ERROR "mtimespec could not be found") + endif() + + set(GIT_NSEC 1) + set(GIT_NSEC_MTIMESPEC 1) + add_feature_info("Nanosecond support" ON "using mtimespec") +elseif(USE_NSEC STREQUAL "mtime_nsec") + if(NOT HAVE_STRUCT_STAT_MTIME_NSEC) + message(FATAL_ERROR "mtime_nsec could not be found") + endif() + + set(GIT_NSEC 1) + set(GIT_NSEC_MTIME_NSEC 1) + add_feature_info("Nanosecond support" ON "using mtime_nsec") +elseif(USE_NSEC STREQUAL "win32") + if(NOT WIN32) + message(FATAL_ERROR "Win32 API support is not available on this platform") + endif() + + set(GIT_NSEC 1) + set(GIT_NSEC_WIN32 1) + add_feature_info("Nanosecond support" ON "using Win32 APIs") +elseif(USE_NSEC STREQUAL OFF) + set(GIT_NSEC 0) + add_feature_info("Nanosecond support" OFF "Nanosecond timestamp resolution is disabled") +else() + message(FATAL_ERROR "unknown nanosecond option: ${USE_NSEC}") +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3921489a58b..4aa062e7e20 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,7 @@ add_feature_info(debugopen GIT_DEBUG_STRICT_OPEN "path validation in open") # Optional feature enablement # +include(SelectNsec) include(SelectHTTPSBackend) include(SelectHashes) include(SelectHTTPParser) @@ -110,22 +111,6 @@ else() message(FATAL_ERROR "Unsupported architecture (CMAKE_SIZEOF_VOID_P is unset)") endif() -# nanosecond mtime/ctime support - -if(USE_NSEC) - set(GIT_USE_NSEC 1) -endif() - -# high-resolution stat support - -if(HAVE_STRUCT_STAT_ST_MTIM) - set(GIT_USE_STAT_MTIM 1) -elseif(HAVE_STRUCT_STAT_ST_MTIMESPEC) - set(GIT_USE_STAT_MTIMESPEC 1) -elseif(HAVE_STRUCT_STAT_ST_MTIME_NSEC) - set(GIT_USE_STAT_MTIME_NSEC 1) -endif() - # realtime support check_library_exists(rt clock_gettime "time.h" NEED_LIBRT) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index a3142c8bcd9..625315184f2 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -902,7 +902,7 @@ void git_index_entry__init_from_stat( { entry->ctime.seconds = (int32_t)st->st_ctime; entry->mtime.seconds = (int32_t)st->st_mtime; -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) entry->mtime.nanoseconds = st->st_mtime_nsec; entry->ctime.nanoseconds = st->st_ctime_nsec; #endif diff --git a/src/libgit2/index.h b/src/libgit2/index.h index 601e98f1ce2..57222a8c6f7 100644 --- a/src/libgit2/index.h +++ b/src/libgit2/index.h @@ -85,7 +85,7 @@ GIT_INLINE(bool) git_index_time_eq(const git_index_time *one, const git_index_ti if (one->seconds != two->seconds) return false; -#ifdef GIT_USE_NSEC +#ifdef GIT_NSEC if (one->nanoseconds != two->nanoseconds) return false; #endif @@ -106,7 +106,7 @@ GIT_INLINE(bool) git_index_entry_newer_than_index( return false; /* If the timestamp is the same or newer than the index, it's racy */ -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) if ((int32_t)index->stamp.mtime.tv_sec < entry->mtime.seconds) return true; else if ((int32_t)index->stamp.mtime.tv_sec > entry->mtime.seconds) diff --git a/src/libgit2/iterator.c b/src/libgit2/iterator.c index 5b3e0248539..4eca11f7cd1 100644 --- a/src/libgit2/iterator.c +++ b/src/libgit2/iterator.c @@ -1520,7 +1520,7 @@ static void filesystem_iterator_set_current( iter->entry.ctime.seconds = (int32_t)entry->st.st_ctime; iter->entry.mtime.seconds = (int32_t)entry->st.st_mtime; -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) iter->entry.ctime.nanoseconds = entry->st.st_ctime_nsec; iter->entry.mtime.nanoseconds = entry->st.st_mtime_nsec; #else diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 537a839a114..5e0aaf67825 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -90,7 +90,7 @@ int git_libgit2_features(void) #ifdef GIT_SSH | GIT_FEATURE_SSH #endif -#ifdef GIT_USE_NSEC +#ifdef GIT_NSEC | GIT_FEATURE_NSEC #endif | GIT_FEATURE_HTTP_PARSER @@ -152,15 +152,15 @@ const char *git_libgit2_feature_backend(git_feature_t feature) break; case GIT_FEATURE_NSEC: -#if defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIMESPEC) +#if defined(GIT_NSEC_MTIMESPEC) return "mtimespec"; -#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIM) +#elif defined(GIT_NSEC_MTIM) return "mtim"; -#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIME_NSEC) - return "mtime"; -#elif defined(GIT_USE_NSEC) && defined(GIT_WIN32) +#elif defined(GIT_NSEC_MTIME_NSEC) + return "mtime_nsec"; +#elif defined(GIT_NSEC_WIN32) return "win32"; -#elif defined(GIT_USE_NSEC) +#elif defined(GIT_NSEC) GIT_ASSERT_WITH_RETVAL(!"Unknown high-resolution time backend", NULL); #endif break; diff --git a/src/util/futils.c b/src/util/futils.c index eb32cbb1205..25c3a1be180 100644 --- a/src/util/futils.c +++ b/src/util/futils.c @@ -1158,7 +1158,7 @@ int git_futils_filestamp_check( return GIT_ENOTFOUND; if (stamp->mtime.tv_sec == st.st_mtime && -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) stamp->mtime.tv_nsec == st.st_mtime_nsec && #endif stamp->size == (uint64_t)st.st_size && @@ -1166,7 +1166,7 @@ int git_futils_filestamp_check( return 0; stamp->mtime.tv_sec = st.st_mtime; -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) stamp->mtime.tv_nsec = st.st_mtime_nsec; #endif stamp->size = (uint64_t)st.st_size; @@ -1190,7 +1190,7 @@ void git_futils_filestamp_set_from_stat( { if (st) { stamp->mtime.tv_sec = st->st_mtime; -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) stamp->mtime.tv_nsec = st->st_mtime_nsec; #else stamp->mtime.tv_nsec = 0; diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index a5cf6a9e0fb..f7c4e33f573 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -14,10 +14,12 @@ #cmakedefine GIT_I18N 1 #cmakedefine GIT_I18N_ICONV 1 -#cmakedefine GIT_USE_NSEC 1 -#cmakedefine GIT_USE_STAT_MTIM 1 -#cmakedefine GIT_USE_STAT_MTIMESPEC 1 -#cmakedefine GIT_USE_STAT_MTIME_NSEC 1 +#cmakedefine GIT_NSEC 1 +#cmakedefine GIT_NSEC_MTIM 1 +#cmakedefine GIT_NSEC_MTIMESPEC 1 +#cmakedefine GIT_NSEC_MTIME_NSEC 1 +#cmakedefine GIT_NSEC_WIN32 1 + #cmakedefine GIT_USE_FUTIMENS 1 #cmakedefine GIT_REGEX_REGCOMP_L 1 diff --git a/src/util/unix/posix.h b/src/util/unix/posix.h index 60f27d3d333..d1fc19e4566 100644 --- a/src/util/unix/posix.h +++ b/src/util/unix/posix.h @@ -23,16 +23,16 @@ typedef int GIT_SOCKET; #define p_lstat(p,b) lstat(p,b) #define p_stat(p,b) stat(p, b) -#if defined(GIT_USE_STAT_MTIMESPEC) +#if defined(GIT_NSEC_MTIMESPEC) # define st_atime_nsec st_atimespec.tv_nsec # define st_mtime_nsec st_mtimespec.tv_nsec # define st_ctime_nsec st_ctimespec.tv_nsec -#elif defined(GIT_USE_STAT_MTIM) +#elif defined(GIT_NSEC_MTIM) # define st_atime_nsec st_atim.tv_nsec # define st_mtime_nsec st_mtim.tv_nsec # define st_ctime_nsec st_ctim.tv_nsec -#elif !defined(GIT_USE_STAT_MTIME_NSEC) && defined(GIT_USE_NSEC) -# error GIT_USE_NSEC defined but unknown struct stat nanosecond type +#elif !defined(GIT_NSEC_MTIME_NSEC) && defined(GIT_NSEC) +# error GIT_NSEC defined but unknown struct stat nanosecond type #endif #define p_utimes(f, t) utimes(f, t) diff --git a/src/util/win32/w32_util.h b/src/util/win32/w32_util.h index 519663720d5..dfdf69cd0db 100644 --- a/src/util/win32/w32_util.h +++ b/src/util/win32/w32_util.h @@ -77,8 +77,10 @@ GIT_INLINE(void) git_win32__filetime_to_timespec( int64_t winTime = ((int64_t)ft->dwHighDateTime << 32) + ft->dwLowDateTime; winTime -= INT64_C(116444736000000000); /* Windows to Unix Epoch conversion */ ts->tv_sec = (time_t)(winTime / 10000000); -#ifdef GIT_USE_NSEC +#ifdef GIT_NSEC_WIN32 ts->tv_nsec = (winTime % 10000000) * 100; +#elif GIT_NSEC +# error GIT_NSEC defined but GIT_NSEC_WIN32 not defined #else ts->tv_nsec = 0; #endif diff --git a/tests/libgit2/checkout/checkout_helpers.h b/tests/libgit2/checkout/checkout_helpers.h index 879b48b06d7..6c723ffdf59 100644 --- a/tests/libgit2/checkout/checkout_helpers.h +++ b/tests/libgit2/checkout/checkout_helpers.h @@ -1,5 +1,6 @@ #include "git2/object.h" #include "git2/repository.h" +#include "git2_features.h" extern void assert_on_branch(git_repository *repo, const char *branch); extern void reset_index_to_treeish(git_object *treeish); diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 9eaa9f35055..4fcce91fd5c 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -20,7 +20,7 @@ void test_core_features__basic(void) cl_assert((caps & GIT_FEATURE_SSH) == 0); #endif -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) cl_assert((caps & GIT_FEATURE_NSEC) != 0); #else cl_assert((caps & GIT_FEATURE_NSEC) == 0); @@ -118,15 +118,15 @@ void test_core_features__backends(void) cl_assert(ssh == NULL); #endif -#if defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIMESPEC) +#if defined(GIT_NSEC_MTIMESPEC) cl_assert_equal_s("mtimespec", nsec); -#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIM) +#elif defined(GIT_NSEC_MTIM) cl_assert_equal_s("mtim", nsec); -#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIME_NSEC) - cl_assert_equal_s("mtime", nsec); -#elif defined(GIT_USE_NSEC) && defined(GIT_WIN32) +#elif defined(GIT_NSEC_MTIME_NSEC) + cl_assert_equal_s("mtime_nsec", nsec); +#elif defined(GIT_NSEC_WIN32) cl_assert_equal_s("win32", nsec); -#elif defined(GIT_USE_NSEC) +#elif defined(GIT_NSEC) cl_assert(0); #else cl_assert(nsec == NULL); diff --git a/tests/libgit2/merge/workdir/dirty.c b/tests/libgit2/merge/workdir/dirty.c index 570e7c759e5..723b259eaba 100644 --- a/tests/libgit2/merge/workdir/dirty.c +++ b/tests/libgit2/merge/workdir/dirty.c @@ -162,7 +162,7 @@ static void hack_index(char *files[]) entry->ctime.seconds = (int32_t)statbuf.st_ctime; entry->mtime.seconds = (int32_t)statbuf.st_mtime; -#if defined(GIT_USE_NSEC) +#if defined(GIT_NSEC) entry->ctime.nanoseconds = statbuf.st_ctime_nsec; entry->mtime.nanoseconds = statbuf.st_mtime_nsec; #else From 2b581ef517f2a7af01a2d9ee9874cc7dece34dc3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 11:40:44 +0000 Subject: [PATCH 770/816] cmake: update threads For consistency with other backend/provider selection, allow `USE_THREADS` to select the threads provider. --- CMakeLists.txt | 4 +--- cmake/SelectThreads.cmake | 41 +++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 14 +----------- src/libgit2/libgit2.c | 6 +++-- src/util/git2_features.h.in | 3 +++ tests/libgit2/core/features.c | 6 +++-- 6 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 cmake/SelectThreads.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index b90e7c1276a..864f813ff0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,10 +25,8 @@ option(BUILD_CLI "Build the command-line interface" option(BUILD_EXAMPLES "Build library usage example apps" OFF) option(BUILD_FUZZERS "Build the fuzz targets" OFF) -# Suggested functionality that may not be available on a per-platform basis -option(USE_THREADS "Use threads for parallel processing when possible" ON) - # Feature enablement and backend selection + set(USE_THREADS "" CACHE STRING "Use threads for parallel processing when possible. One of ON, OFF, or a specific provider: pthreads or win32. (Defaults to ON.)") set(USE_SSH "" CACHE STRING "Enables SSH support and optionally selects provider. One of ON, OFF, or a specific provider: libssh2 or exec. (Defaults to OFF.)") set(USE_HTTPS "" CACHE STRING "Enable HTTPS support and optionally selects the provider. One of ON, OFF, or a specific provider: OpenSSL, OpenSSL-FIPS, OpenSSL-Dynamic, mbedTLS, SecureTransport, Schannel, or WinHTTP. (Defaults to ON.)") set(USE_SHA1 "" CACHE STRING "Selects SHA1 provider. One of builtin, HTTPS, or a specific provider. (Defaults to builtin.)") diff --git a/cmake/SelectThreads.cmake b/cmake/SelectThreads.cmake new file mode 100644 index 00000000000..45c76fa0f5f --- /dev/null +++ b/cmake/SelectThreads.cmake @@ -0,0 +1,41 @@ +include(SanitizeBool) + +sanitizebool(USE_THREADS) + +if(NOT WIN32) + find_package(Threads) +endif() + +if((USE_THREADS STREQUAL ON OR USE_THREADS STREQUAL "") AND THREADS_FOUND) + set(USE_THREADS "pthreads") +elseif((USE_THREADS STREQUAL ON OR USE_THREADS STREQUAL "") AND WIN32) + set(USE_THREADS "win32") +elseif(USE_THREADS STREQUAL "") + set(USE_THREADS OFF) +endif() + +if(USE_THREADS STREQUAL "pthreads") + if(NOT THREADS_FOUND) + message(FATAL_ERROR "pthreads were requested but not found") + endif() + + list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT}) + + set(GIT_THREADS 1) + set(GIT_THREADS_PTHREADS 1) + add_feature_info("Threads" ON "using pthreads") +elseif(USE_THREADS STREQUAL "win32") + if(NOT WIN32) + message(FATAL_ERROR "Win32 API support is not available on this platform") + endif() + + set(GIT_THREADS 1) + set(GIT_THREADS_WIN32 1) + add_feature_info("Threads" ON "using Win32 APIs") +elseif(USE_THREADS STREQUAL OFF) + set(GIT_THREADS 0) + add_feature_info("Threads" OFF "threads support is disabled") +else() + message(FATAL_ERROR "unknown threads option: ${USE_THREADS}") +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4aa062e7e20..1e4f1286390 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,7 @@ add_feature_info(debugopen GIT_DEBUG_STRICT_OPEN "path validation in open") # Optional feature enablement # +include(SelectThreads) include(SelectNsec) include(SelectHTTPSBackend) include(SelectHashes) @@ -141,19 +142,6 @@ if(AMIGA) add_definitions(-DNO_ADDRINFO -DNO_READDIR_R -DNO_MMAP) endif() -# threads - -if(USE_THREADS) - if(NOT WIN32) - find_package(Threads REQUIRED) - list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT}) - list(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT}) - endif() - - set(GIT_THREADS 1) -endif() -add_feature_info(threadsafe USE_THREADS "threadsafe support") - # # Include child projects # diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 5e0aaf67825..4bdb6ba6e0f 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -116,10 +116,12 @@ const char *git_libgit2_feature_backend(git_feature_t feature) { switch (feature) { case GIT_FEATURE_THREADS: -#if defined(GIT_THREADS) && defined(GIT_WIN32) +#if defined(GIT_THREADS_PTHREADS) + return "pthread"; +#elif defined(GIT_THREADS_WIN32) return "win32"; #elif defined(GIT_THREADS) - return "pthread"; + GIT_ASSERT_WITH_RETVAL(!"Unknown threads backend", NULL); #endif break; diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index f7c4e33f573..b6eab6ed6cb 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -6,6 +6,9 @@ #cmakedefine GIT_DEBUG_STRICT_OPEN 1 #cmakedefine GIT_THREADS 1 +#cmakedefine GIT_THREADS_PTHREADS 1 +#cmakedefine GIT_THREADS_WIN32 1 + #cmakedefine GIT_WIN32_LEAKCHECK 1 #cmakedefine GIT_ARCH_64 1 diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 4fcce91fd5c..66211fb6469 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -82,10 +82,12 @@ void test_core_features__backends(void) const char *sha1 = git_libgit2_feature_backend(GIT_FEATURE_SHA1); const char *sha256 = git_libgit2_feature_backend(GIT_FEATURE_SHA256); -#if defined(GIT_THREADS) && defined(GIT_WIN32) +#if defined(GIT_THREADS_WIN32) cl_assert_equal_s("win32", threads); -#elif defined(GIT_THREADS) +#elif defined(GIT_THREADS_PTHREADS) cl_assert_equal_s("pthread", threads); +#elif defined(GIT_THREADS) + cl_assert(0); #else cl_assert(threads == NULL); #endif From bab249d82ea8c8c4f5b5fbe2d981b67df2778487 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jan 2025 11:18:56 +0000 Subject: [PATCH 771/816] cmake: standardize xdiff options --- cmake/SelectXdiff.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/SelectXdiff.cmake b/cmake/SelectXdiff.cmake index 9ab9f3f4f29..e4e4aa5d0d0 100644 --- a/cmake/SelectXdiff.cmake +++ b/cmake/SelectXdiff.cmake @@ -6,4 +6,6 @@ else() list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/xdiff") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") add_feature_info(xdiff ON "xdiff support (bundled)") +else() + message(FATAL_ERROR "asked for unknown Xdiff backend: ${USE_XDIFF}") endif() From 94d8883dcfebf2d16d0e517e8ceb436246d9d56a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 11:42:35 +0000 Subject: [PATCH 772/816] cmake: update verbiage on feature enablement --- cmake/SelectCompression.cmake | 4 ++-- cmake/SelectHTTPParser.cmake | 6 +++--- cmake/SelectI18n.cmake | 4 ++-- cmake/SelectRegex.cmake | 10 +++++----- cmake/SelectXdiff.cmake | 2 +- src/CMakeLists.txt | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cmake/SelectCompression.cmake b/cmake/SelectCompression.cmake index 50c4706f415..e2b5bf89e22 100644 --- a/cmake/SelectCompression.cmake +++ b/cmake/SelectCompression.cmake @@ -42,12 +42,12 @@ if(GIT_COMPRESSION_ZLIB) else() list(APPEND LIBGIT2_PC_REQUIRES "zlib") endif() - add_feature_info(compression ON "using system zlib") + add_feature_info("Compression" ON "using system zlib") elseif(GIT_COMPRESSION_BUILTIN) add_subdirectory("${PROJECT_SOURCE_DIR}/deps/zlib" "${PROJECT_BINARY_DIR}/deps/zlib") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/zlib") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $) - add_feature_info(compression ON "using bundled zlib") + add_feature_info("Compression" ON "using bundled zlib") else() message(FATAL_ERROR "unknown compression backend") endif() diff --git a/cmake/SelectHTTPParser.cmake b/cmake/SelectHTTPParser.cmake index e547e2d0166..9491c295b1c 100644 --- a/cmake/SelectHTTPParser.cmake +++ b/cmake/SelectHTTPParser.cmake @@ -7,7 +7,7 @@ if(USE_HTTP_PARSER STREQUAL "http-parser" OR USE_HTTP_PARSER STREQUAL "system") list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES}) list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") set(GIT_HTTPPARSER_HTTPPARSER 1) - add_feature_info(http-parser ON "using http-parser (system)") + add_feature_info("HTTP Parser" ON "using system http-parser") else() message(FATAL_ERROR "http-parser support was requested but not found") endif() @@ -19,7 +19,7 @@ elseif(USE_HTTP_PARSER STREQUAL "llhttp") list(APPEND LIBGIT2_SYSTEM_LIBS ${LLHTTP_LIBRARIES}) list(APPEND LIBGIT2_PC_LIBS "-lllhttp") set(GIT_HTTPPARSER_LLHTTP 1) - add_feature_info(http-parser ON "using llhttp (system)") + add_feature_info("HTTP Parser" ON "using system llhttp") else() message(FATAL_ERROR "llhttp support was requested but not found") endif() @@ -28,7 +28,7 @@ elseif(USE_HTTP_PARSER STREQUAL "" OR USE_HTTP_PARSER STREQUAL "builtin") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/llhttp") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") set(GIT_HTTPPARSER_BUILTIN 1) - add_feature_info(http-parser ON "using bundled parser") + add_feature_info("HTTP Parser" ON "using bundled parser") else() message(FATAL_ERROR "unknown http-parser: ${USE_HTTP_PARSER}") endif() diff --git a/cmake/SelectI18n.cmake b/cmake/SelectI18n.cmake index 1b4c6d7803b..aa70ee2f20e 100644 --- a/cmake/SelectI18n.cmake +++ b/cmake/SelectI18n.cmake @@ -33,8 +33,8 @@ if(USE_I18N) set(GIT_I18N 1) set(GIT_I18N_ICONV 1) - add_feature_info(i18n ON "using ${USE_I18N}") + add_feature_info("Internationalization" ON "using ${USE_I18N}") else() set(GIT_I18N 0) - add_feature_info(i18n NO "internationalization support is disabled") + add_feature_info("Internationalization" OFF "internationalization support is disabled") endif() diff --git a/cmake/SelectRegex.cmake b/cmake/SelectRegex.cmake index 64cc2f14815..d1c09ae44c2 100644 --- a/cmake/SelectRegex.cmake +++ b/cmake/SelectRegex.cmake @@ -27,7 +27,7 @@ if(NOT USE_REGEX) endif() if(USE_REGEX STREQUAL "regcomp_l") - add_feature_info(regex ON "using system regcomp_l") + add_feature_info("Regular expressions" ON "using system regcomp_l") set(GIT_REGEX_REGCOMP_L 1) elseif(USE_REGEX STREQUAL "pcre2") find_package(PCRE2) @@ -36,24 +36,24 @@ elseif(USE_REGEX STREQUAL "pcre2") MESSAGE(FATAL_ERROR "PCRE2 support was requested but not found") endif() - add_feature_info(regex ON "using system PCRE2") + add_feature_info("Regular expressions" ON "using system PCRE2") set(GIT_REGEX_PCRE2 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE2_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${PCRE2_LIBRARIES}) list(APPEND LIBGIT2_PC_REQUIRES "libpcre2-8") elseif(USE_REGEX STREQUAL "pcre") - add_feature_info(regex ON "using system PCRE") + add_feature_info("Regular expressions" ON "using system PCRE") set(GIT_REGEX_PCRE 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${PCRE_LIBRARIES}) list(APPEND LIBGIT2_PC_REQUIRES "libpcre") elseif(USE_REGEX STREQUAL "regcomp") - add_feature_info(regex ON "using system regcomp") + add_feature_info("Regular expressions" ON "using system regcomp") set(GIT_REGEX_REGCOMP 1) elseif(USE_REGEX STREQUAL "builtin") - add_feature_info(regex ON "using builtin") + add_feature_info("Regular expressions" ON "using bundled implementation") set(GIT_REGEX_BUILTIN 1) add_subdirectory("${PROJECT_SOURCE_DIR}/deps/pcre" "${PROJECT_BINARY_DIR}/deps/pcre") diff --git a/cmake/SelectXdiff.cmake b/cmake/SelectXdiff.cmake index e4e4aa5d0d0..718a6fc4fe3 100644 --- a/cmake/SelectXdiff.cmake +++ b/cmake/SelectXdiff.cmake @@ -5,7 +5,7 @@ else() add_subdirectory("${PROJECT_SOURCE_DIR}/deps/xdiff" "${PROJECT_BINARY_DIR}/deps/xdiff") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/xdiff") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") - add_feature_info(xdiff ON "xdiff support (bundled)") + add_feature_info("Xdiff" ON "using bundled provider") else() message(FATAL_ERROR "asked for unknown Xdiff backend: ${USE_XDIFF}") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1e4f1286390..3ded3af898c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,17 +20,17 @@ endif() if(DEBUG_POOL) set(GIT_DEBUG_POOL 1) endif() -add_feature_info(debugpool GIT_DEBUG_POOL "debug pool allocator") +add_feature_info("Debug pool" GIT_DEBUG_POOL "debug-mode struct pool allocators") if(DEBUG_STRICT_ALLOC) set(GIT_DEBUG_STRICT_ALLOC 1) endif() -add_feature_info(debugalloc GIT_DEBUG_STRICT_ALLOC "debug strict allocators") +add_feature_info("Debug alloc" GIT_DEBUG_STRICT_ALLOC "debug-mode strict allocators") if(DEBUG_STRICT_OPEN) set(GIT_DEBUG_STRICT_OPEN 1) endif() -add_feature_info(debugopen GIT_DEBUG_STRICT_OPEN "path validation in open") +add_feature_info("Debug open" GIT_DEBUG_STRICT_OPEN "strict path validation in open") # # Optional feature enablement From 9efdbe3834ed66a57b43543b6eb2db3fd17e1fbf Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 12:02:50 +0000 Subject: [PATCH 773/816] cmake: standardize leak check option The `GIT_WIN32_LEAKCHECK` option is a debugging option, so it should be `GIT_DEBUG_LEAKCHECK_WIN32` --- .github/workflows/experimental.yml | 2 +- .github/workflows/main.yml | 4 ++-- .github/workflows/nightly.yml | 6 +++--- CMakeLists.txt | 5 +---- cmake/DefaultCFlags.cmake | 4 ++-- src/util/alloc.c | 2 +- src/util/allocators/win32_leakcheck.c | 2 +- src/util/git2_features.h.in | 3 +-- src/util/win32/w32_leakcheck.c | 2 +- src/util/win32/w32_leakcheck.h | 2 +- tests/clar/clar_libgit2_trace.c | 4 ++-- tests/clar/main.c | 4 ++-- tests/libgit2/trace/windows/stacktrace.c | 10 +++++----- 13 files changed, 23 insertions(+), 27 deletions(-) diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml index 8ffb4b63cbc..bb945d5980f 100644 --- a/.github/workflows/experimental.yml +++ b/.github/workflows/experimental.yml @@ -52,7 +52,7 @@ jobs: env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 17 2022 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_OPTIONS: -A x64 -DDEBUG_LEAK_CHECKER=win32 -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true # TODO: this is a temporary removal diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f6af730b10a..90c02977ea6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,7 +80,7 @@ jobs: env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 17 2022 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + CMAKE_OPTIONS: -A x64 -DDEBUG_LEAK_CHECKER=win32 -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true @@ -92,7 +92,7 @@ jobs: env: ARCH: x86 CMAKE_GENERATOR: Visual Studio 17 2022 - CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + CMAKE_OPTIONS: -A Win32 -DDEBUG_LEAK_CHECKER=win32 -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a12803d5b16..852a3fb8339 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -91,7 +91,7 @@ jobs: env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 17 2022 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + CMAKE_OPTIONS: -A x64 -DDEBUG_LEAK_CHECKER=win32 -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true @@ -103,7 +103,7 @@ jobs: env: ARCH: x86 CMAKE_GENERATOR: Visual Studio 17 2022 - CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + CMAKE_OPTIONS: -A Win32 -DDEBUG_LEAK_CHECKER=win32 -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true @@ -370,7 +370,7 @@ jobs: env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 17 2022 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_OPTIONS: -A x64 -DDEBUG_LEAK_CHECKER=win32 -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true # TODO: this is a temporary removal diff --git a/CMakeLists.txt b/CMakeLists.txt index 864f813ff0c..4e884db5034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ if(APPLE) endif() # Debugging options - set(DEBUG_LEAK_CHECKER "" CACHE STRING "Run tests with leak checker. Either valgrind or leaks.") + set(DEBUG_LEAK_CHECKER "" CACHE STRING "Configure for leak checking test runs. One of valgrind, leaks, or win32. Either valgrind or leaks.") option(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF) option(DEBUG_POOL "Enable debug pool allocator" OFF) option(DEBUG_STRICT_ALLOC "Enable strict allocator behavior" OFF) @@ -78,9 +78,6 @@ if(MSVC) # If you want to embed a copy of libssh2 into libgit2, pass a # path to libssh2 option(EMBED_SSH_PATH "Path to libssh2 to embed (Windows)" OFF) - - # Enable leak checking using the debugging C runtime. - option(WIN32_LEAKCHECK "Enable leak reporting via crtdbg" OFF) endif() if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) diff --git a/cmake/DefaultCFlags.cmake b/cmake/DefaultCFlags.cmake index a9c9ab9729c..14899f89d48 100644 --- a/cmake/DefaultCFlags.cmake +++ b/cmake/DefaultCFlags.cmake @@ -26,8 +26,8 @@ if(MSVC) set(CRT_FLAG_RELEASE "/MD") endif() - if(WIN32_LEAKCHECK) - set(GIT_WIN32_LEAKCHECK 1) + if(DEBUG_LEAK_CHECKER STREQUAL "win32") + set(GIT_DEBUG_LEAKCHECK_WIN32 1) set(CRT_FLAG_DEBUG "${CRT_FLAG_DEBUG}") set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} Dbghelp.lib") endif() diff --git a/src/util/alloc.c b/src/util/alloc.c index 998b0aea1d9..1059cb65744 100644 --- a/src/util/alloc.c +++ b/src/util/alloc.c @@ -87,7 +87,7 @@ char *git__substrdup(const char *str, size_t n) static int setup_default_allocator(void) { -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) return git_win32_leakcheck_init_allocator(&git__allocator); #elif defined(GIT_DEBUG_STRICT_ALLOC) return git_debugalloc_init_allocator(&git__allocator); diff --git a/src/util/allocators/win32_leakcheck.c b/src/util/allocators/win32_leakcheck.c index cdf16d34880..f17f432718f 100644 --- a/src/util/allocators/win32_leakcheck.c +++ b/src/util/allocators/win32_leakcheck.c @@ -7,7 +7,7 @@ #include "win32_leakcheck.h" -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) #include "win32/w32_leakcheck.h" diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index b6eab6ed6cb..c2fa17eedcb 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -4,13 +4,12 @@ #cmakedefine GIT_DEBUG_POOL 1 #cmakedefine GIT_DEBUG_STRICT_ALLOC 1 #cmakedefine GIT_DEBUG_STRICT_OPEN 1 +#cmakedefine GIT_DEBUG_LEAKCHECK_WIN32 1 #cmakedefine GIT_THREADS 1 #cmakedefine GIT_THREADS_PTHREADS 1 #cmakedefine GIT_THREADS_WIN32 1 -#cmakedefine GIT_WIN32_LEAKCHECK 1 - #cmakedefine GIT_ARCH_64 1 #cmakedefine GIT_ARCH_32 1 diff --git a/src/util/win32/w32_leakcheck.c b/src/util/win32/w32_leakcheck.c index 0f095de12d2..26c20918ce3 100644 --- a/src/util/win32/w32_leakcheck.c +++ b/src/util/win32/w32_leakcheck.c @@ -7,7 +7,7 @@ #include "w32_leakcheck.h" -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) #include "Windows.h" #include "Dbghelp.h" diff --git a/src/util/win32/w32_leakcheck.h b/src/util/win32/w32_leakcheck.h index 82d863851ee..52ff10a777a 100644 --- a/src/util/win32/w32_leakcheck.h +++ b/src/util/win32/w32_leakcheck.h @@ -13,7 +13,7 @@ /* Initialize the win32 leak checking system. */ int git_win32_leakcheck_global_init(void); -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) #include #include diff --git a/tests/clar/clar_libgit2_trace.c b/tests/clar/clar_libgit2_trace.c index 814a5fa9ee7..f33b019e1e0 100644 --- a/tests/clar/clar_libgit2_trace.c +++ b/tests/clar/clar_libgit2_trace.c @@ -164,7 +164,7 @@ static void _cl_trace_cb__event_handler( switch (ev) { case CL_TRACE__SUITE_BEGIN: git_trace(GIT_TRACE_TRACE, "\n\n%s\n%s: Begin Suite", HR, suite_name); -#if 0 && defined(GIT_WIN32_LEAKCHECK) +#if 0 && defined(GIT_DEBUG_LEAKCHECK_WIN32) git_win32__crtdbg_stacktrace__dump( GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK, suite_name); @@ -172,7 +172,7 @@ static void _cl_trace_cb__event_handler( break; case CL_TRACE__SUITE_END: -#if 0 && defined(GIT_WIN32_LEAKCHECK) +#if 0 && defined(GIT_DEBUG_LEAKCHECK_WIN32) /* As an example of checkpointing, dump leaks within this suite. * This may generate false positives for things like the global * TLS error state and maybe the odb cache since they aren't diff --git a/tests/clar/main.c b/tests/clar/main.c index e3f4fe740bd..cdd4630790d 100644 --- a/tests/clar/main.c +++ b/tests/clar/main.c @@ -1,7 +1,7 @@ #include "clar_libgit2.h" #include "clar_libgit2_trace.h" -#ifdef GIT_WIN32_LEAKCHECK +#ifdef GIT_DEBUG_LEAKCHECK_WIN32 # include "win32/w32_leakcheck.h" #endif @@ -37,7 +37,7 @@ int main(int argc, char *argv[]) cl_global_trace_disable(); git_libgit2_shutdown(); -#ifdef GIT_WIN32_LEAKCHECK +#ifdef GIT_DEBUG_LEAKCHECK_WIN32 if (git_win32_leakcheck_has_leaks()) res = res || 1; #endif diff --git a/tests/libgit2/trace/windows/stacktrace.c b/tests/libgit2/trace/windows/stacktrace.c index 0a77ef99d21..21dd13a48f4 100644 --- a/tests/libgit2/trace/windows/stacktrace.c +++ b/tests/libgit2/trace/windows/stacktrace.c @@ -1,7 +1,7 @@ #include "clar_libgit2.h" #include "win32/w32_leakcheck.h" -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) static void a(void) { char buf[10000]; @@ -26,7 +26,7 @@ static void c(void) void test_trace_windows_stacktrace__basic(void) { -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) c(); #endif } @@ -34,7 +34,7 @@ void test_trace_windows_stacktrace__basic(void) void test_trace_windows_stacktrace__leaks(void) { -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) void * p1; void * p2; void * p3; @@ -124,7 +124,7 @@ void test_trace_windows_stacktrace__leaks(void) #endif } -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) static void aux_cb_alloc__1(unsigned int *aux_id) { static unsigned int aux_counter = 0; @@ -141,7 +141,7 @@ static void aux_cb_lookup__1(unsigned int aux_id, char *aux_msg, size_t aux_msg_ void test_trace_windows_stacktrace__aux1(void) { -#if defined(GIT_WIN32_LEAKCHECK) +#if defined(GIT_DEBUG_LEAKCHECK_WIN32) git_win32_leakcheck_stack_set_aux_cb(aux_cb_alloc__1, aux_cb_lookup__1); c(); c(); From c42ccfaa349fc5b119f229d1d39665d3fa0d76e2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 12:05:31 +0000 Subject: [PATCH 774/816] cmake: don't report futimes enablement futimes is not an option; don't report enablement as such. --- src/CMakeLists.txt | 5 ++--- src/util/git2_features.h.in | 2 +- src/util/unix/posix.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ded3af898c..76eb9485584 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,9 +56,8 @@ include(SelectAuthNegotiate) # futimes/futimens if(HAVE_FUTIMENS) - set(GIT_USE_FUTIMENS 1) -endif () -add_feature_info(futimens GIT_USE_FUTIMENS "futimens support") + set(GIT_FUTIMENS 1) +endif() # qsort diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index c2fa17eedcb..cd6bfc54c96 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -22,7 +22,7 @@ #cmakedefine GIT_NSEC_MTIME_NSEC 1 #cmakedefine GIT_NSEC_WIN32 1 -#cmakedefine GIT_USE_FUTIMENS 1 +#cmakedefine GIT_FUTIMENS 1 #cmakedefine GIT_REGEX_REGCOMP_L 1 #cmakedefine GIT_REGEX_REGCOMP 1 diff --git a/src/util/unix/posix.h b/src/util/unix/posix.h index d1fc19e4566..0c5c1065549 100644 --- a/src/util/unix/posix.h +++ b/src/util/unix/posix.h @@ -82,7 +82,7 @@ GIT_INLINE(int) p_fsync(int fd) #define p_timeval timeval -#ifdef GIT_USE_FUTIMENS +#ifdef GIT_FUTIMENS GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2]) { struct timespec s[2]; From c4c284e46fa17e811bed74839108e836f98473a7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 13:02:39 +0000 Subject: [PATCH 775/816] cmake: standardize HTTPS backend definitions There were a few oddities around HTTPS provider selection: namely, `GIT_OPENSSL_DYNAMIC` implied `GIT_OPENSSL`, which made a bit of sense, until we added FIPS support. In addition, dynamic OpenSSL for _hashes_ and dynamic OpenSSL for HTTPS was conflated in a few places. Untangle these, and make `GIT_HTTPS_*` the define, for consistency with other feature provider selection. --- cmake/SelectHTTPSBackend.cmake | 25 ++++++++++--------- cmake/SelectHashes.cmake | 2 -- src/libgit2/libgit2.c | 12 ++++----- src/libgit2/settings.c | 10 +++++--- src/libgit2/streams/mbedtls.c | 2 +- src/libgit2/streams/mbedtls.h | 2 +- src/libgit2/streams/openssl.c | 16 ++++++------ src/libgit2/streams/openssl.h | 4 +-- src/libgit2/streams/openssl_dynamic.c | 7 +++--- src/libgit2/streams/openssl_dynamic.h | 4 +-- src/libgit2/streams/openssl_legacy.c | 8 +++--- src/libgit2/streams/openssl_legacy.h | 8 +++--- src/libgit2/streams/schannel.c | 2 +- src/libgit2/streams/schannel.h | 2 +- src/libgit2/streams/stransport.c | 2 +- src/libgit2/streams/stransport.h | 2 +- src/libgit2/streams/tls.c | 18 ++++++++------ src/libgit2/transports/auth_ntlm.h | 8 ------ src/libgit2/transports/http.c | 4 +-- src/libgit2/transports/winhttp.c | 4 +-- src/util/git2_features.h.in | 12 ++++----- src/util/hash/openssl.c | 35 ++++++++++++++++----------- src/util/hash/openssl.h | 22 +++++++++-------- src/util/hash/sha.h | 2 ++ src/util/win32/error.c | 4 +-- tests/libgit2/core/features.c | 12 ++++----- tests/libgit2/online/clone.c | 8 +++--- tests/libgit2/online/customcert.c | 16 ++++++------ tests/libgit2/stream/registration.c | 2 +- 29 files changed, 132 insertions(+), 123 deletions(-) diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index 0316b3a1c1a..f7d46c0daff 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -48,7 +48,7 @@ if(USE_HTTPS) message(FATAL_ERROR "Cannot use SecureTransport backend, SSLCreateContext not supported") endif() - set(GIT_SECURE_TRANSPORT 1) + set(GIT_HTTPS_SECURETRANSPORT 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${SECURITY_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) list(APPEND LIBGIT2_PC_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) @@ -57,7 +57,7 @@ if(USE_HTTPS) message(FATAL_ERROR "Asked for OpenSSL TLS backend, but it wasn't found") endif() - set(GIT_OPENSSL 1) + set(GIT_HTTPS_OPENSSL 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES}) # Static OpenSSL (lib crypto.a) requires libdl, include it explicitly @@ -102,13 +102,12 @@ if(USE_HTTPS) if(CERT_LOCATION) if(NOT EXISTS ${CERT_LOCATION}) - message(FATAL_ERROR "Cannot use CERT_LOCATION=${CERT_LOCATION} as it doesn't exist") + message(FATAL_ERROR "cannot use CERT_LOCATION=${CERT_LOCATION} as it doesn't exist") endif() - add_feature_info(CERT_LOCATION ON "using certificates from ${CERT_LOCATION}") add_definitions(-DGIT_DEFAULT_CERT_LOCATION="${CERT_LOCATION}") endif() - set(GIT_MBEDTLS 1) + set(GIT_HTTPS_MBEDTLS 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${MBEDTLS_LIBRARIES}) # mbedTLS has no pkgconfig file, hence we can't require it @@ -116,12 +115,12 @@ if(USE_HTTPS) # For now, pass its link flags as our own list(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) elseif(USE_HTTPS STREQUAL "Schannel") - set(GIT_SCHANNEL 1) + set(GIT_HTTPS_SCHANNEL 1) list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") elseif(USE_HTTPS STREQUAL "WinHTTP") - set(GIT_WINHTTP 1) + set(GIT_HTTPS_WINHTTP 1) # Since MinGW does not come with headers or an import library for winhttp, # we have to include a private header and generate our own import library @@ -137,16 +136,20 @@ if(USE_HTTPS) list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") - set(GIT_OPENSSL 1) - set(GIT_OPENSSL_DYNAMIC 1) + set(GIT_HTTPS_OPENSSL_DYNAMIC 1) list(APPEND LIBGIT2_SYSTEM_LIBS dl) else() message(FATAL_ERROR "unknown HTTPS backend: ${USE_HTTPS}") endif() set(GIT_HTTPS 1) - add_feature_info(HTTPS GIT_HTTPS "using ${USE_HTTPS}") + + if(USE_HTTPS STREQUAL "mbedTLS" AND CERT_LOCATION) + add_feature_info("HTTPS" GIT_HTTPS "using ${USE_HTTPS} (certificate location: ${CERT_LOCATION})") + else() + add_feature_info("HTTPS" GIT_HTTPS "using ${USE_HTTPS}") + endif() else() set(GIT_HTTPS 0) - add_feature_info(HTTPS NO "HTTPS support is disabled") + add_feature_info("HTTPS" NO "HTTPS support is disabled") endif() diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 6f6e0f056dd..b5180d2fdd2 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -34,7 +34,6 @@ elseif(USE_SHA1 STREQUAL "OpenSSL") elseif(USE_SHA1 STREQUAL "OpenSSL-FIPS") set(GIT_SHA1_OPENSSL_FIPS 1) elseif(USE_SHA1 STREQUAL "OpenSSL-Dynamic") - set(GIT_SHA1_OPENSSL 1) set(GIT_SHA1_OPENSSL_DYNAMIC 1) list(APPEND LIBGIT2_SYSTEM_LIBS dl) elseif(USE_SHA1 STREQUAL "CommonCrypto") @@ -80,7 +79,6 @@ elseif(USE_SHA256 STREQUAL "OpenSSL") elseif(USE_SHA256 STREQUAL "OpenSSL-FIPS") set(GIT_SHA256_OPENSSL_FIPS 1) elseif(USE_SHA256 STREQUAL "OpenSSL-Dynamic") - set(GIT_SHA256_OPENSSL 1) set(GIT_SHA256_OPENSSL_DYNAMIC 1) list(APPEND LIBGIT2_SYSTEM_LIBS dl) elseif(USE_SHA256 STREQUAL "CommonCrypto") diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 4bdb6ba6e0f..37e0bd012fe 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -126,17 +126,17 @@ const char *git_libgit2_feature_backend(git_feature_t feature) break; case GIT_FEATURE_HTTPS: -#if defined(GIT_HTTPS) && defined(GIT_OPENSSL) +#if defined(GIT_HTTPS_OPENSSL) return "openssl"; -#elif defined(GIT_HTTPS) && defined(GIT_OPENSSL_DYNAMIC) +#elif defined(GIT_HTTPS_OPENSSL_DYNAMIC) return "openssl-dynamic"; -#elif defined(GIT_HTTPS) && defined(GIT_MBEDTLS) +#elif defined(GIT_HTTPS_MBEDTLS) return "mbedtls"; -#elif defined(GIT_HTTPS) && defined(GIT_SECURE_TRANSPORT) +#elif defined(GIT_HTTPS_SECURETRANSPORT) return "securetransport"; -#elif defined(GIT_HTTPS) && defined(GIT_SCHANNEL) +#elif defined(GIT_HTTPS_SCHANNEL) return "schannel"; -#elif defined(GIT_HTTPS) && defined(GIT_WINHTTP) +#elif defined(GIT_HTTPS_WINHTTP) return "winhttp"; #elif defined(GIT_HTTPS) GIT_ASSERT_WITH_RETVAL(!"Unknown HTTPS backend", NULL); diff --git a/src/libgit2/settings.c b/src/libgit2/settings.c index f4c2453a433..5c7c9cb15c6 100644 --- a/src/libgit2/settings.c +++ b/src/libgit2/settings.c @@ -204,13 +204,13 @@ int git_libgit2_opts(int key, ...) break; case GIT_OPT_SET_SSL_CERT_LOCATIONS: -#ifdef GIT_OPENSSL +#if defined(GIT_HTTPS_OPENSSL) || defined(GIT_HTTPS_OPENSSL_DYNAMIC) { const char *file = va_arg(ap, const char *); const char *path = va_arg(ap, const char *); error = git_openssl__set_cert_location(file, path); } -#elif defined(GIT_MBEDTLS) +#elif defined(GIT_HTTPS_MBEDTLS) { const char *file = va_arg(ap, const char *); const char *path = va_arg(ap, const char *); @@ -223,7 +223,7 @@ int git_libgit2_opts(int key, ...) break; case GIT_OPT_ADD_SSL_X509_CERT: -#ifdef GIT_OPENSSL +#if defined(GIT_HTTPS_OPENSSL) || defined(GIT_HTTPS_OPENSSL_DYNAMIC) { X509 *cert = va_arg(ap, X509 *); error = git_openssl__add_x509_cert(cert); @@ -303,7 +303,9 @@ int git_libgit2_opts(int key, ...) break; case GIT_OPT_SET_SSL_CIPHERS: -#if (GIT_OPENSSL || GIT_MBEDTLS) +#if defined(GIT_HTTPS_OPENSSL) || \ + defined(GIT_HTTPS_OPENSSL_DYNAMIC) || \ + defined(GIT_HTTPS_MBEDTLS) { git__free(git__ssl_ciphers); git__ssl_ciphers = git__strdup(va_arg(ap, const char *)); diff --git a/src/libgit2/streams/mbedtls.c b/src/libgit2/streams/mbedtls.c index a3839c2ce15..ccf0f110303 100644 --- a/src/libgit2/streams/mbedtls.c +++ b/src/libgit2/streams/mbedtls.c @@ -7,7 +7,7 @@ #include "streams/mbedtls.h" -#ifdef GIT_MBEDTLS +#ifdef GIT_HTTPS_MBEDTLS #include diff --git a/src/libgit2/streams/mbedtls.h b/src/libgit2/streams/mbedtls.h index bcca6dd401a..76c0627a2ca 100644 --- a/src/libgit2/streams/mbedtls.h +++ b/src/libgit2/streams/mbedtls.h @@ -13,7 +13,7 @@ extern int git_mbedtls_stream_global_init(void); -#ifdef GIT_MBEDTLS +#ifdef GIT_HTTPS_MBEDTLS extern int git_mbedtls__set_cert_location(const char *file, const char *path); extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port); diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c index ca64e460b75..f12b699f9b0 100644 --- a/src/libgit2/streams/openssl.c +++ b/src/libgit2/streams/openssl.c @@ -9,7 +9,7 @@ #include "streams/openssl_legacy.h" #include "streams/openssl_dynamic.h" -#ifdef GIT_OPENSSL +#if defined(GIT_HTTPS_OPENSSL) || defined(GIT_HTTPS_OPENSSL_DYNAMIC) #include @@ -29,7 +29,7 @@ # include #endif -#ifndef GIT_OPENSSL_DYNAMIC +#ifndef GIT_HTTPS_OPENSSL_DYNAMIC # include # include # include @@ -64,7 +64,7 @@ static void shutdown_ssl(void) } #ifdef VALGRIND -# if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) +# if !defined(GIT_HTTPS_OPENSSL_LEGACY) && !defined(GIT_HTTPS_OPENSSL_DYNAMIC) static void *git_openssl_malloc(size_t bytes, const char *file, int line) { @@ -86,7 +86,7 @@ static void git_openssl_free(void *mem, const char *file, int line) GIT_UNUSED(line); git__free(mem); } -# else /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ +# else /* !GIT_HTTPS_OPENSSL_LEGACY && !GIT_HTTPS_OPENSSL_DYNAMIC */ static void *git_openssl_malloc(size_t bytes) { return git__calloc(1, bytes); @@ -101,7 +101,7 @@ static void git_openssl_free(void *mem) { git__free(mem); } -# endif /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ +# endif /* !GIT_HTTPS_OPENSSL_LEGACY && !GIT_HTTPS_OPENSSL_DYNAMIC */ #endif /* VALGRIND */ static int openssl_init(void) @@ -181,7 +181,7 @@ bool openssl_initialized; int git_openssl_stream_global_init(void) { -#ifndef GIT_OPENSSL_DYNAMIC +#ifndef GIT_HTTPS_OPENSSL_DYNAMIC return openssl_init(); #else if (git_mutex_init(&openssl_mutex) != 0) @@ -193,7 +193,7 @@ int git_openssl_stream_global_init(void) static int openssl_ensure_initialized(void) { -#ifdef GIT_OPENSSL_DYNAMIC +#ifdef GIT_HTTPS_OPENSSL_DYNAMIC int error = 0; if (git_mutex_lock(&openssl_mutex) != 0) @@ -214,7 +214,7 @@ static int openssl_ensure_initialized(void) #endif } -#if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) +#if !defined(GIT_HTTPS_OPENSSL_LEGACY) && !defined(GIT_HTTPS_OPENSSL_DYNAMIC) int git_openssl_set_locking(void) { # ifdef GIT_THREADS diff --git a/src/libgit2/streams/openssl.h b/src/libgit2/streams/openssl.h index a3ef1a93343..2a5f04099bc 100644 --- a/src/libgit2/streams/openssl.h +++ b/src/libgit2/streams/openssl.h @@ -15,14 +15,14 @@ extern int git_openssl_stream_global_init(void); -#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC) +#if defined(GIT_HTTPS_OPENSSL) # include # include # include # include # endif -#ifdef GIT_OPENSSL +#if defined(GIT_HTTPS_OPENSSL) || defined(GIT_HTTPS_OPENSSL_DYNAMIC) extern int git_openssl__set_cert_location(const char *file, const char *path); extern int git_openssl__add_x509_cert(X509 *cert); extern int git_openssl__reset_context(void); diff --git a/src/libgit2/streams/openssl_dynamic.c b/src/libgit2/streams/openssl_dynamic.c index fe679526f9d..3ab292073d9 100644 --- a/src/libgit2/streams/openssl_dynamic.c +++ b/src/libgit2/streams/openssl_dynamic.c @@ -8,7 +8,7 @@ #include "streams/openssl.h" #include "streams/openssl_dynamic.h" -#if defined(GIT_OPENSSL) && defined(GIT_OPENSSL_DYNAMIC) +#ifdef GIT_HTTPS_OPENSSL_DYNAMIC #include "runtime.h" @@ -128,7 +128,8 @@ int git_openssl_stream_dynamic_init(void) (openssl_handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL && (openssl_handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL && (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL && - (openssl_handle = dlopen("libssl.so.3", RTLD_NOW)) == NULL) { + (openssl_handle = dlopen("libssl.so.3", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.3.dylib", RTLD_NOW)) == NULL) { git_error_set(GIT_ERROR_SSL, "could not load ssl libraries"); return -1; } @@ -314,4 +315,4 @@ void GENERAL_NAMES_free(GENERAL_NAME *sk) sk_free(sk); } -#endif /* GIT_OPENSSL && GIT_OPENSSL_DYNAMIC */ +#endif /* GIT_HTTPS_OPENSSL_DYNAMIC */ diff --git a/src/libgit2/streams/openssl_dynamic.h b/src/libgit2/streams/openssl_dynamic.h index 0d7ef0f2a89..07a650b91af 100644 --- a/src/libgit2/streams/openssl_dynamic.h +++ b/src/libgit2/streams/openssl_dynamic.h @@ -149,7 +149,7 @@ #ifndef INCLUDE_streams_openssl_dynamic_h__ #define INCLUDE_streams_openssl_dynamic_h__ -#ifdef GIT_OPENSSL_DYNAMIC +#ifdef GIT_HTTPS_OPENSSL_DYNAMIC # define BIO_CTRL_FLUSH 11 @@ -348,6 +348,6 @@ extern void GENERAL_NAMES_free(GENERAL_NAME *sk); extern int git_openssl_stream_dynamic_init(void); -#endif /* GIT_OPENSSL_DYNAMIC */ +#endif /* GIT_HTTPS_OPENSSL_DYNAMIC */ #endif diff --git a/src/libgit2/streams/openssl_legacy.c b/src/libgit2/streams/openssl_legacy.c index e61e6efbb5e..7d361263f49 100644 --- a/src/libgit2/streams/openssl_legacy.c +++ b/src/libgit2/streams/openssl_legacy.c @@ -11,14 +11,14 @@ #include "runtime.h" #include "git2/sys/openssl.h" -#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC) +#if defined(GIT_HTTPS_OPENSSL) && !defined(GIT_HTTPS_OPENSSL_DYNAMIC) # include # include # include # include #endif -#if defined(GIT_OPENSSL_LEGACY) || defined(GIT_OPENSSL_DYNAMIC) +#if defined(GIT_HTTPS_OPENSSL_LEGACY) || defined(GIT_HTTPS_OPENSSL_DYNAMIC) /* * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it @@ -173,7 +173,7 @@ int git_openssl_set_locking(void) return -1; #endif -#ifdef GIT_OPENSSL_DYNAMIC +#ifdef GIT_HTTPS_OPENSSL_DYNAMIC /* * This function is required on legacy versions of OpenSSL; when building * with dynamically-loaded OpenSSL, we detect whether we loaded it or not. @@ -200,4 +200,4 @@ int git_openssl_set_locking(void) } #endif /* GIT_THREADS */ -#endif /* GIT_OPENSSL_LEGACY || GIT_OPENSSL_DYNAMIC */ +#endif /* GIT_HTTPS_OPENSSL_LEGACY || GIT_HTTPS_OPENSSL_DYNAMIC */ diff --git a/src/libgit2/streams/openssl_legacy.h b/src/libgit2/streams/openssl_legacy.h index e6dae957207..205c984adcc 100644 --- a/src/libgit2/streams/openssl_legacy.h +++ b/src/libgit2/streams/openssl_legacy.h @@ -9,7 +9,7 @@ #include "streams/openssl_dynamic.h" -#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC) +#if defined(GIT_HTTPS_OPENSSL) && !defined(GIT_HTTPS_OPENSSL_DYNAMIC) # include # include # include @@ -17,11 +17,11 @@ # if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) -# define GIT_OPENSSL_LEGACY +# define GIT_HTTPS_OPENSSL_LEGACY # endif #endif -#if defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) +#if defined(GIT_HTTPS_OPENSSL_LEGACY) && !defined(GIT_HTTPS_OPENSSL_DYNAMIC) # define OPENSSL_init_ssl OPENSSL_init_ssl__legacy # define BIO_meth_new BIO_meth_new__legacy # define BIO_meth_free BIO_meth_free__legacy @@ -39,7 +39,7 @@ # define ASN1_STRING_get0_data ASN1_STRING_get0_data__legacy #endif -#if defined(GIT_OPENSSL_LEGACY) || defined(GIT_OPENSSL_DYNAMIC) +#if defined(GIT_HTTPS_OPENSSL_LEGACY) || defined(GIT_HTTPS_OPENSSL_DYNAMIC) extern int OPENSSL_init_ssl__legacy(uint64_t opts, const void *settings); extern BIO_METHOD *BIO_meth_new__legacy(int type, const char *name); diff --git a/src/libgit2/streams/schannel.c b/src/libgit2/streams/schannel.c index f096158193c..062758a2587 100644 --- a/src/libgit2/streams/schannel.c +++ b/src/libgit2/streams/schannel.c @@ -7,7 +7,7 @@ #include "streams/schannel.h" -#ifdef GIT_SCHANNEL +#ifdef GIT_HTTPS_SCHANNEL #define SECURITY_WIN32 diff --git a/src/libgit2/streams/schannel.h b/src/libgit2/streams/schannel.h index 3584970d1f8..153bdbf96e7 100644 --- a/src/libgit2/streams/schannel.h +++ b/src/libgit2/streams/schannel.h @@ -11,7 +11,7 @@ #include "git2/sys/stream.h" -#ifdef GIT_SCHANNEL +#ifdef GIT_HTTPS_SCHANNEL extern int git_schannel_stream_new( git_stream **out, diff --git a/src/libgit2/streams/stransport.c b/src/libgit2/streams/stransport.c index 2d4cc55b549..3dbc403b7f4 100644 --- a/src/libgit2/streams/stransport.c +++ b/src/libgit2/streams/stransport.c @@ -7,7 +7,7 @@ #include "streams/stransport.h" -#ifdef GIT_SECURE_TRANSPORT +#ifdef GIT_HTTPS_SECURETRANSPORT #include #include diff --git a/src/libgit2/streams/stransport.h b/src/libgit2/streams/stransport.h index 1026e204b16..e1b936b53ba 100644 --- a/src/libgit2/streams/stransport.h +++ b/src/libgit2/streams/stransport.h @@ -11,7 +11,7 @@ #include "git2/sys/stream.h" -#ifdef GIT_SECURE_TRANSPORT +#ifdef GIT_HTTPS_SECURETRANSPORT extern int git_stransport_stream_new(git_stream **out, const char *host, const char *port); extern int git_stransport_stream_wrap(git_stream **out, git_stream *in, const char *host); diff --git a/src/libgit2/streams/tls.c b/src/libgit2/streams/tls.c index 246ac9ca793..47ef2689f3f 100644 --- a/src/libgit2/streams/tls.c +++ b/src/libgit2/streams/tls.c @@ -28,13 +28,14 @@ int git_tls_stream_new(git_stream **out, const char *host, const char *port) if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_TLS)) == 0) { init = custom.init; } else if (error == GIT_ENOTFOUND) { -#ifdef GIT_SECURE_TRANSPORT +#if defined(GIT_HTTPS_SECURETRANSPORT) init = git_stransport_stream_new; -#elif defined(GIT_OPENSSL) +#elif defined(GIT_HTTPS_OPENSSL) || \ + defined(GIT_HTTPS_OPENSSL_DYNAMIC) init = git_openssl_stream_new; -#elif defined(GIT_MBEDTLS) +#elif defined(GIT_HTTPS_MBEDTLS) init = git_mbedtls_stream_new; -#elif defined(GIT_SCHANNEL) +#elif defined(GIT_HTTPS_SCHANNEL) init = git_schannel_stream_new; #endif } else { @@ -60,13 +61,14 @@ int git_tls_stream_wrap(git_stream **out, git_stream *in, const char *host) if (git_stream_registry_lookup(&custom, GIT_STREAM_TLS) == 0) { wrap = custom.wrap; } else { -#ifdef GIT_SECURE_TRANSPORT +#if defined(GIT_HTTPS_SECURETRANSPORT) wrap = git_stransport_stream_wrap; -#elif defined(GIT_OPENSSL) +#elif defined(GIT_HTTPS_OPENSSL) || \ + defined(GIT_HTTPS_OPENSSL_DYNAMIC) wrap = git_openssl_stream_wrap; -#elif defined(GIT_MBEDTLS) +#elif defined(GIT_HTTPS_MBEDTLS) wrap = git_mbedtls_stream_wrap; -#elif defined(GIT_SCHANNEL) +#elif defined(GIT_HTTPS_SCHANNEL) wrap = git_schannel_stream_wrap; #endif } diff --git a/src/libgit2/transports/auth_ntlm.h b/src/libgit2/transports/auth_ntlm.h index b6610d94018..d83d1c4cd4d 100644 --- a/src/libgit2/transports/auth_ntlm.h +++ b/src/libgit2/transports/auth_ntlm.h @@ -15,14 +15,6 @@ #if defined(GIT_AUTH_NTLM) -#if defined(GIT_OPENSSL) -# define CRYPT_OPENSSL -#elif defined(GIT_MBEDTLS) -# define CRYPT_MBEDTLS -#elif defined(GIT_SECURE_TRANSPORT) -# define CRYPT_COMMONCRYPTO -#endif - extern int git_http_auth_ntlm( git_http_auth_context **out, const git_net_url *url); diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index ea819952018..923a825fa30 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -7,7 +7,7 @@ #include "common.h" -#ifndef GIT_WINHTTP +#ifndef GIT_HTTPS_WINHTTP #include "net.h" #include "remote.h" @@ -762,4 +762,4 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own return 0; } -#endif /* !GIT_WINHTTP */ +#endif /* !GIT_HTTPS_WINHTTP */ diff --git a/src/libgit2/transports/winhttp.c b/src/libgit2/transports/winhttp.c index b83ef990de6..7141c284634 100644 --- a/src/libgit2/transports/winhttp.c +++ b/src/libgit2/transports/winhttp.c @@ -7,7 +7,7 @@ #include "common.h" -#ifdef GIT_WINHTTP +#ifdef GIT_HTTPS_WINHTTP #include "git2.h" #include "git2/transport.h" @@ -1715,4 +1715,4 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own return 0; } -#endif /* GIT_WINHTTP */ +#endif /* GIT_HTTPS_WINHTTP */ diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index cd6bfc54c96..02a5c811375 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -49,13 +49,13 @@ #cmakedefine GIT_AUTH_NEGOTIATE_GSSAPI 1 #cmakedefine GIT_AUTH_NEGOTIATE_SSPI 1 -#cmakedefine GIT_WINHTTP 1 #cmakedefine GIT_HTTPS 1 -#cmakedefine GIT_OPENSSL 1 -#cmakedefine GIT_OPENSSL_DYNAMIC 1 -#cmakedefine GIT_SECURE_TRANSPORT 1 -#cmakedefine GIT_MBEDTLS 1 -#cmakedefine GIT_SCHANNEL 1 +#cmakedefine GIT_HTTPS_OPENSSL 1 +#cmakedefine GIT_HTTPS_OPENSSL_DYNAMIC 1 +#cmakedefine GIT_HTTPS_SECURETRANSPORT 1 +#cmakedefine GIT_HTTPS_MBEDTLS 1 +#cmakedefine GIT_HTTPS_SCHANNEL 1 +#cmakedefine GIT_HTTPS_WINHTTP 1 #cmakedefine GIT_HTTPPARSER_HTTPPARSER 1 #cmakedefine GIT_HTTPPARSER_LLHTTP 1 diff --git a/src/util/hash/openssl.c b/src/util/hash/openssl.c index 1ed1b4409f9..8d58cfbc15b 100644 --- a/src/util/hash/openssl.c +++ b/src/util/hash/openssl.c @@ -7,7 +7,7 @@ #include "openssl.h" -#ifdef GIT_OPENSSL_DYNAMIC +#if defined(GIT_SHA1_OPENSSL_DYNAMIC) || defined(GIT_SHA256_OPENSSL_DYNAMIC) # include static int handle_count; @@ -31,7 +31,8 @@ static int git_hash_openssl_global_init(void) (openssl_handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL && (openssl_handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL && (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL && - (openssl_handle = dlopen("libssl.so.3", RTLD_NOW)) == NULL) { + (openssl_handle = dlopen("libssl.so.3", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.3.dylib", RTLD_NOW)) == NULL) { git_error_set(GIT_ERROR_SSL, "could not load ssl libraries"); return -1; } @@ -46,17 +47,13 @@ static int git_hash_openssl_global_init(void) #endif -#ifdef GIT_SHA1_OPENSSL - -# ifdef GIT_OPENSSL_DYNAMIC +#ifdef GIT_SHA1_OPENSSL_DYNAMIC static int (*SHA1_Init)(SHA_CTX *c); static int (*SHA1_Update)(SHA_CTX *c, const void *data, size_t len); static int (*SHA1_Final)(unsigned char *md, SHA_CTX *c); -# endif int git_hash_sha1_global_init(void) { -#ifdef GIT_OPENSSL_DYNAMIC if (git_hash_openssl_global_init() < 0) return -1; @@ -67,10 +64,17 @@ int git_hash_sha1_global_init(void) git_error_set(GIT_ERROR_SSL, "could not load hash function: %s", msg ? msg : "unknown error"); return -1; } -#endif return 0; } +#elif GIT_SHA1_OPENSSL +int git_hash_sha1_global_init(void) +{ + return 0; +} +#endif + +#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA1_OPENSSL_DYNAMIC) int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) { @@ -196,17 +200,13 @@ int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) #endif -#ifdef GIT_SHA256_OPENSSL - -# ifdef GIT_OPENSSL_DYNAMIC +#ifdef GIT_SHA256_OPENSSL_DYNAMIC static int (*SHA256_Init)(SHA256_CTX *c); static int (*SHA256_Update)(SHA256_CTX *c, const void *data, size_t len); static int (*SHA256_Final)(unsigned char *md, SHA256_CTX *c); -#endif int git_hash_sha256_global_init(void) { -#ifdef GIT_OPENSSL_DYNAMIC if (git_hash_openssl_global_init() < 0) return -1; @@ -217,10 +217,17 @@ int git_hash_sha256_global_init(void) git_error_set(GIT_ERROR_SSL, "could not load hash function: %s", msg ? msg : "unknown error"); return -1; } -#endif return 0; } +#elif GIT_SHA256_OPENSSL +int git_hash_sha256_global_init(void) +{ + return 0; +} +#endif + +#if defined(GIT_SHA256_OPENSSL) || defined(GIT_SHA256_OPENSSL_DYNAMIC) int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) { diff --git a/src/util/hash/openssl.h b/src/util/hash/openssl.h index 8be37fd44e8..2ab73c9893c 100644 --- a/src/util/hash/openssl.h +++ b/src/util/hash/openssl.h @@ -10,31 +10,33 @@ #include "hash/sha.h" -#ifndef GIT_OPENSSL_DYNAMIC -# if defined(GIT_SHA1_OPENSSL_FIPS) || defined(GIT_SHA256_OPENSSL_FIPS) -# include -# else -# include -# endif -#else +#if defined(GIT_SHA1_OPENSSL_FIPS) || defined(GIT_SHA256_OPENSSL_FIPS) +# include +#endif + +#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) +# include +#endif +#if defined(GIT_SHA1_OPENSSL_DYNAMIC) typedef struct { unsigned int h0, h1, h2, h3, h4; unsigned int Nl, Nh; unsigned int data[16]; unsigned int num; } SHA_CTX; +#endif +#if defined(GIT_SHA256_OPENSSL_DYNAMIC) typedef struct { unsigned int h[8]; unsigned int Nl, Nh; unsigned int data[16]; unsigned int num, md_len; } SHA256_CTX; - #endif -#ifdef GIT_SHA1_OPENSSL +#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA1_OPENSSL_DYNAMIC) struct git_hash_sha1_ctx { SHA_CTX c; }; @@ -46,7 +48,7 @@ struct git_hash_sha1_ctx { }; #endif -#ifdef GIT_SHA256_OPENSSL +#if defined(GIT_SHA256_OPENSSL) || defined(GIT_SHA256_OPENSSL_DYNAMIC) struct git_hash_sha256_ctx { SHA256_CTX c; }; diff --git a/src/util/hash/sha.h b/src/util/hash/sha.h index eb418c0d631..f9d04814237 100644 --- a/src/util/hash/sha.h +++ b/src/util/hash/sha.h @@ -22,8 +22,10 @@ typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; #endif #if defined(GIT_SHA1_OPENSSL) || \ + defined(GIT_SHA1_OPENSSL_DYNAMIC) || \ defined(GIT_SHA1_OPENSSL_FIPS) || \ defined(GIT_SHA256_OPENSSL) || \ + defined(GIT_SHA256_OPENSSL_DYNAMIC) || \ defined(GIT_SHA256_OPENSSL_FIPS) # include "openssl.h" #endif diff --git a/src/util/win32/error.c b/src/util/win32/error.c index dfd6fa1e8a1..141b1ad4cef 100644 --- a/src/util/win32/error.c +++ b/src/util/win32/error.c @@ -9,7 +9,7 @@ #include "utf-conv.h" -#ifdef GIT_WINHTTP +#ifdef GIT_HTTPS_WINHTTP # include #endif @@ -24,7 +24,7 @@ char *git_win32_get_error_message(DWORD error_code) if (!error_code) return NULL; -#ifdef GIT_WINHTTP +#ifdef GIT_HTTPS_WINHTTP /* Errors raised by WinHTTP are not in the system resource table */ if (error_code >= WINHTTP_ERROR_BASE && error_code <= WINHTTP_ERROR_LAST) diff --git a/tests/libgit2/core/features.c b/tests/libgit2/core/features.c index 66211fb6469..f8c6679c2fb 100644 --- a/tests/libgit2/core/features.c +++ b/tests/libgit2/core/features.c @@ -92,17 +92,17 @@ void test_core_features__backends(void) cl_assert(threads == NULL); #endif -#if defined(GIT_HTTPS) && defined(GIT_OPENSSL) +#if defined(GIT_HTTPS_OPENSSL) cl_assert_equal_s("openssl", https); -#elif defined(GIT_HTTPS) && defined(GIT_OPENSSL_DYNAMIC) +#elif defined(GIT_HTTPS_OPENSSL_DYNAMIC) cl_assert_equal_s("openssl-dynamic", https); -#elif defined(GIT_HTTPS) && defined(GIT_MBEDTLS) +#elif defined(GIT_HTTPS_MBEDTLS) cl_assert_equal_s("mbedtls", https); -#elif defined(GIT_HTTPS) && defined(GIT_SECURE_TRANSPORT) +#elif defined(GIT_HTTPS_SECURETRANSPORT) cl_assert_equal_s("securetransport", https); -#elif defined(GIT_HTTPS) && defined(GIT_SCHANNEL) +#elif defined(GIT_HTTPS_SCHANNEL) cl_assert_equal_s("schannel", https); -#elif defined(GIT_HTTPS) && defined(GIT_WINHTTP) +#elif defined(GIT_HTTPS_WINHTTP) cl_assert_equal_s("winhttp", https); #elif defined(GIT_HTTPS) cl_assert(0); diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 6e9c8ea5051..be0990d86de 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -1373,7 +1373,7 @@ void test_online_clone__sha256(void) void test_online_clone__connect_timeout_configurable(void) { -#ifdef GIT_WINHTTP +#ifdef GIT_HTTPS_WINHTTP cl_skip(); #else uint64_t start, finish; @@ -1392,7 +1392,7 @@ void test_online_clone__connect_timeout_configurable(void) void test_online_clone__connect_timeout_default(void) { -#ifdef GIT_WINHTTP +#ifdef GIT_HTTPS_WINHTTP cl_skip(); #else /* This test takes ~ 75 seconds on Unix. */ @@ -1410,7 +1410,7 @@ void test_online_clone__connect_timeout_default(void) void test_online_clone__timeout_configurable_times_out(void) { -#ifdef GIT_WINHTTP +#ifdef GIT_HTTPS_WINHTTP cl_skip(); #else git_repository *failed_repo; @@ -1427,7 +1427,7 @@ void test_online_clone__timeout_configurable_times_out(void) void test_online_clone__timeout_configurable_succeeds_slowly(void) { -#ifdef GIT_WINHTTP +#ifdef GIT_HTTPS_WINHTTP cl_skip(); #else if (!_remote_speed_slow) diff --git a/tests/libgit2/online/customcert.c b/tests/libgit2/online/customcert.c index 89694b5f4cf..ef05bb4ea15 100644 --- a/tests/libgit2/online/customcert.c +++ b/tests/libgit2/online/customcert.c @@ -10,7 +10,7 @@ #include "str.h" #include "streams/openssl.h" -#if (GIT_OPENSSL && !GIT_OPENSSL_DYNAMIC) +#ifdef GIT_HTTPS_OPENSSL # include # include # include @@ -30,13 +30,13 @@ #define CUSTOM_CERT_THREE_URL "https://test.libgit2.org:3443/anonymous/test.git" #define CUSTOM_CERT_THREE_FILE "three.pem.raw" -#if (GIT_OPENSSL || GIT_MBEDTLS) +#if (GIT_HTTPS_OPENSSL || GIT_HTTPS_OPENSSL_DYNAMIC || GIT_HTTPS_MBEDTLS) static git_repository *g_repo; #endif void test_online_customcert__initialize(void) { -#if (GIT_OPENSSL || GIT_MBEDTLS) +#if (GIT_HTTPS_OPENSSL || GIT_HTTPS_OPENSSL_DYNAMIC || GIT_HTTPS_MBEDTLS) git_str path = GIT_STR_INIT, file = GIT_STR_INIT; char cwd[GIT_PATH_MAX]; @@ -58,7 +58,7 @@ void test_online_customcert__initialize(void) void test_online_customcert__cleanup(void) { -#if (GIT_OPENSSL || GIT_MBEDTLS) +#if (GIT_HTTPS_OPENSSL || GIT_HTTPS_OPENSSL_DYNAMIC || GIT_HTTPS_MBEDTLS) if (g_repo) { git_repository_free(g_repo); g_repo = NULL; @@ -68,14 +68,14 @@ void test_online_customcert__cleanup(void) cl_fixture_cleanup(CUSTOM_CERT_DIR); #endif -#ifdef GIT_OPENSSL +#if (GIT_HTTPS_OPENSSL || GIT_HTTPS_OPENSSL_DYNAMIC) git_openssl__reset_context(); #endif } void test_online_customcert__file(void) { -#if (GIT_OPENSSL || GIT_MBEDTLS) +#if (GIT_HTTPS_OPENSSL || GIT_HTTPS_OPENSSL_DYNAMIC || GIT_HTTPS_MBEDTLS) cl_git_pass(git_clone(&g_repo, CUSTOM_CERT_ONE_URL, "./cloned", NULL)); cl_assert(git_fs_path_exists("./cloned/master.txt")); #endif @@ -83,7 +83,7 @@ void test_online_customcert__file(void) void test_online_customcert__path(void) { -#if (GIT_OPENSSL || GIT_MBEDTLS) +#if (GIT_HTTPS_OPENSSL || GIT_HTTPS_OPENSSL_DYNAMIC || GIT_HTTPS_MBEDTLS) cl_git_pass(git_clone(&g_repo, CUSTOM_CERT_TWO_URL, "./cloned", NULL)); cl_assert(git_fs_path_exists("./cloned/master.txt")); #endif @@ -91,7 +91,7 @@ void test_online_customcert__path(void) void test_online_customcert__raw_x509(void) { -#if (GIT_OPENSSL && !GIT_OPENSSL_DYNAMIC) +#if GIT_HTTPS_OPENSSL X509* x509_cert = NULL; char cwd[GIT_PATH_MAX]; git_str raw_file = GIT_STR_INIT, diff --git a/tests/libgit2/stream/registration.c b/tests/libgit2/stream/registration.c index ccaecee8c1e..e1ce54a5dc2 100644 --- a/tests/libgit2/stream/registration.c +++ b/tests/libgit2/stream/registration.c @@ -84,7 +84,7 @@ void test_stream_registration__tls(void) /* We don't have TLS support enabled, or we're on Windows * with WinHTTP, which is not actually TLS stream support. */ -#if defined(GIT_WINHTTP) || !defined(GIT_HTTPS) +#if defined(GIT_HTTPS_WINHTTP) || !defined(GIT_HTTPS) cl_git_fail_with(-1, error); #else cl_git_pass(error); From 5a654f11bbbbf509bf01b603339eb8917d24656f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 31 Dec 2024 13:06:26 +0000 Subject: [PATCH 776/816] cmake: update git2_features.h Reorganize the libgit2 feature selection file. --- src/util/git2_features.h.in | 76 ++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 02a5c811375..7e94835e83a 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -1,20 +1,37 @@ #ifndef INCLUDE_features_h__ #define INCLUDE_features_h__ +/* Debugging options */ + #cmakedefine GIT_DEBUG_POOL 1 #cmakedefine GIT_DEBUG_STRICT_ALLOC 1 #cmakedefine GIT_DEBUG_STRICT_OPEN 1 #cmakedefine GIT_DEBUG_LEAKCHECK_WIN32 1 +/* Feature enablement and provider / backend selection */ + #cmakedefine GIT_THREADS 1 #cmakedefine GIT_THREADS_PTHREADS 1 #cmakedefine GIT_THREADS_WIN32 1 -#cmakedefine GIT_ARCH_64 1 -#cmakedefine GIT_ARCH_32 1 +#cmakedefine GIT_SHA1_BUILTIN 1 +#cmakedefine GIT_SHA1_OPENSSL 1 +#cmakedefine GIT_SHA1_OPENSSL_FIPS 1 +#cmakedefine GIT_SHA1_OPENSSL_DYNAMIC 1 +#cmakedefine GIT_SHA1_MBEDTLS 1 +#cmakedefine GIT_SHA1_COMMON_CRYPTO 1 +#cmakedefine GIT_SHA1_WIN32 1 -#cmakedefine GIT_I18N 1 -#cmakedefine GIT_I18N_ICONV 1 +#cmakedefine GIT_SHA256_BUILTIN 1 +#cmakedefine GIT_SHA256_WIN32 1 +#cmakedefine GIT_SHA256_COMMON_CRYPTO 1 +#cmakedefine GIT_SHA256_OPENSSL 1 +#cmakedefine GIT_SHA256_OPENSSL_FIPS 1 +#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 +#cmakedefine GIT_SHA256_MBEDTLS 1 + +#cmakedefine GIT_COMPRESSION_BUILTIN 1 +#cmakedefine GIT_COMPRESSION_ZLIB 1 #cmakedefine GIT_NSEC 1 #cmakedefine GIT_NSEC_MTIM 1 @@ -22,7 +39,8 @@ #cmakedefine GIT_NSEC_MTIME_NSEC 1 #cmakedefine GIT_NSEC_WIN32 1 -#cmakedefine GIT_FUTIMENS 1 +#cmakedefine GIT_I18N 1 +#cmakedefine GIT_I18N_ICONV 1 #cmakedefine GIT_REGEX_REGCOMP_L 1 #cmakedefine GIT_REGEX_REGCOMP 1 @@ -30,25 +48,11 @@ #cmakedefine GIT_REGEX_PCRE2 1 #cmakedefine GIT_REGEX_BUILTIN 1 -#cmakedefine GIT_QSORT_BSD 1 -#cmakedefine GIT_QSORT_GNU 1 -#cmakedefine GIT_QSORT_C11 1 -#cmakedefine GIT_QSORT_MSC 1 - #cmakedefine GIT_SSH 1 #cmakedefine GIT_SSH_EXEC 1 #cmakedefine GIT_SSH_LIBSSH2 1 #cmakedefine GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1 -#cmakedefine GIT_AUTH_NTLM 1 -#cmakedefine GIT_AUTH_NTLM_BUILTIN 1 -#cmakedefine GIT_AUTH_NTLM_SSPI 1 - -#cmakedefine GIT_AUTH_NEGOTIATE 1 -#cmakedefine GIT_AUTH_NEGOTIATE_GSSFRAMEWORK 1 -#cmakedefine GIT_AUTH_NEGOTIATE_GSSAPI 1 -#cmakedefine GIT_AUTH_NEGOTIATE_SSPI 1 - #cmakedefine GIT_HTTPS 1 #cmakedefine GIT_HTTPS_OPENSSL 1 #cmakedefine GIT_HTTPS_OPENSSL_DYNAMIC 1 @@ -61,24 +65,26 @@ #cmakedefine GIT_HTTPPARSER_LLHTTP 1 #cmakedefine GIT_HTTPPARSER_BUILTIN 1 -#cmakedefine GIT_SHA1_BUILTIN 1 -#cmakedefine GIT_SHA1_WIN32 1 -#cmakedefine GIT_SHA1_COMMON_CRYPTO 1 -#cmakedefine GIT_SHA1_OPENSSL 1 -#cmakedefine GIT_SHA1_OPENSSL_FIPS 1 -#cmakedefine GIT_SHA1_OPENSSL_DYNAMIC 1 -#cmakedefine GIT_SHA1_MBEDTLS 1 +#cmakedefine GIT_AUTH_NTLM 1 +#cmakedefine GIT_AUTH_NTLM_BUILTIN 1 +#cmakedefine GIT_AUTH_NTLM_SSPI 1 -#cmakedefine GIT_SHA256_BUILTIN 1 -#cmakedefine GIT_SHA256_WIN32 1 -#cmakedefine GIT_SHA256_COMMON_CRYPTO 1 -#cmakedefine GIT_SHA256_OPENSSL 1 -#cmakedefine GIT_SHA256_OPENSSL_FIPS 1 -#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 -#cmakedefine GIT_SHA256_MBEDTLS 1 +#cmakedefine GIT_AUTH_NEGOTIATE 1 +#cmakedefine GIT_AUTH_NEGOTIATE_GSSFRAMEWORK 1 +#cmakedefine GIT_AUTH_NEGOTIATE_GSSAPI 1 +#cmakedefine GIT_AUTH_NEGOTIATE_SSPI 1 -#cmakedefine GIT_COMPRESSION_BUILTIN 1 -#cmakedefine GIT_COMPRESSION_ZLIB 1 +/* Platform details */ + +#cmakedefine GIT_ARCH_64 1 +#cmakedefine GIT_ARCH_32 1 + +#cmakedefine GIT_QSORT_BSD 1 +#cmakedefine GIT_QSORT_GNU 1 +#cmakedefine GIT_QSORT_C11 1 +#cmakedefine GIT_QSORT_MSC 1 + +#cmakedefine GIT_FUTIMENS 1 #cmakedefine GIT_RAND_GETENTROPY 1 #cmakedefine GIT_RAND_GETLOADAVG 1 From 4546929e003ef8182c4c76c751af26928fc9a95d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jan 2025 11:31:52 +0000 Subject: [PATCH 777/816] cmake: case insensitive options It's hard to remember whether it's `-DUSE_HTTPS=mbedTLS` or `-DUSE_HTTPS=mbedtls`. Even worse for things like `builtin` which we may have been inconsistent about. Allow for case insensitive options. --- ...SanitizeBool.cmake => SanitizeInput.cmake} | 4 +- cmake/SelectAuthNTLM.cmake | 6 +- cmake/SelectAuthNegotiate.cmake | 10 +- cmake/SelectCompression.cmake | 6 +- cmake/SelectHTTPParser.cmake | 8 +- cmake/SelectHTTPSBackend.cmake | 60 ++++++---- cmake/SelectHashes.cmake | 103 +++++++++--------- cmake/SelectI18n.cmake | 6 +- cmake/SelectNsec.cmake | 4 +- cmake/SelectThreads.cmake | 4 +- cmake/SelectXdiff.cmake | 7 +- deps/ntlmclient/CMakeLists.txt | 8 +- src/util/CMakeLists.txt | 22 ++-- 13 files changed, 140 insertions(+), 108 deletions(-) rename cmake/{SanitizeBool.cmake => SanitizeInput.cmake} (88%) diff --git a/cmake/SanitizeBool.cmake b/cmake/SanitizeInput.cmake similarity index 88% rename from cmake/SanitizeBool.cmake rename to cmake/SanitizeInput.cmake index 586c17d0528..8398d888986 100644 --- a/cmake/SanitizeBool.cmake +++ b/cmake/SanitizeInput.cmake @@ -1,4 +1,4 @@ -function(SanitizeBool VAR) +function(SanitizeInput VAR) string(TOLOWER "${${VAR}}" VALUE) if(VALUE STREQUAL "on") set(${VAR} "ON" PARENT_SCOPE) @@ -16,5 +16,7 @@ function(SanitizeBool VAR) set(${VAR} "OFF" PARENT_SCOPE) elseif(VALUE STREQUAL "0") set(${VAR} "OFF" PARENT_SCOPE) + else() + set(${VAR} "${VALUE}" PARENT_SCOPE) endif() endfunction() diff --git a/cmake/SelectAuthNTLM.cmake b/cmake/SelectAuthNTLM.cmake index 105c4bbc38e..ed48c047867 100644 --- a/cmake/SelectAuthNTLM.cmake +++ b/cmake/SelectAuthNTLM.cmake @@ -1,11 +1,11 @@ -include(SanitizeBool) +include(SanitizeInput) if(USE_AUTH_NTLM STREQUAL "" AND NOT USE_NTLMCLIENT STREQUAL "") - sanitizebool(USE_NTLMCLIENT) + sanitizeinput(USE_NTLMCLIENT) set(USE_AUTH_NTLM "${USE_NTLMCLIENT}") endif() -sanitizebool(USE_AUTH_NTLM) +sanitizeinput(USE_AUTH_NTLM) if(USE_AUTH_NTLM STREQUAL "") set(USE_AUTH_NTLM ON) diff --git a/cmake/SelectAuthNegotiate.cmake b/cmake/SelectAuthNegotiate.cmake index 3615571bc27..98e925af26f 100644 --- a/cmake/SelectAuthNegotiate.cmake +++ b/cmake/SelectAuthNegotiate.cmake @@ -1,4 +1,4 @@ -include(SanitizeBool) +include(SanitizeInput) find_package(GSSAPI) @@ -7,14 +7,14 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "iOS") endif() if(USE_AUTH_NEGOTIATE STREQUAL "" AND NOT USE_GSSAPI STREQUAL "") - sanitizebool(USE_GSSAPI) + sanitizeinput(USE_GSSAPI) set(USE_AUTH_NEGOTIATE "${USE_GSSAPI}") endif() -sanitizebool(USE_AUTH_NEGOTIATE) +sanitizeinput(USE_AUTH_NEGOTIATE) if((USE_AUTH_NEGOTIATE STREQUAL ON OR USE_AUTH_NEGOTIATE STREQUAL "") AND GSSFRAMEWORK_FOUND) - set(USE_AUTH_NEGOTIATE "GSS.framework") + set(USE_AUTH_NEGOTIATE "gssframework") elseif((USE_AUTH_NEGOTIATE STREQUAL ON OR USE_AUTH_NEGOTIATE STREQUAL "") AND GSSAPI_FOUND) set(USE_AUTH_NEGOTIATE "gssapi") elseif((USE_AUTH_NEGOTIATE STREQUAL ON OR USE_AUTH_NEGOTIATE STREQUAL "") AND WIN32) @@ -25,7 +25,7 @@ elseif(USE_AUTH_NEGOTIATE STREQUAL ON) message(FATAL_ERROR "negotiate support was requested but no backend is available") endif() -if(USE_AUTH_NEGOTIATE STREQUAL "GSS.framework") +if(USE_AUTH_NEGOTIATE STREQUAL "gssframework") if(NOT GSSFRAMEWORK_FOUND) message(FATAL_ERROR "GSS.framework could not be found") endif() diff --git a/cmake/SelectCompression.cmake b/cmake/SelectCompression.cmake index e2b5bf89e22..d0a4b566476 100644 --- a/cmake/SelectCompression.cmake +++ b/cmake/SelectCompression.cmake @@ -1,8 +1,8 @@ -include(SanitizeBool) +include(SanitizeInput) # Fall back to the previous cmake configuration, "USE_BUNDLED_ZLIB" if(NOT USE_COMPRESSION AND USE_BUNDLED_ZLIB) - SanitizeBool(USE_BUNDLED_ZLIB) + SanitizeInput(USE_BUNDLED_ZLIB) if(USE_BUNDLED_ZLIB STREQUAL ON) set(USE_COMPRESSION "builtin") @@ -13,6 +13,8 @@ if(NOT USE_COMPRESSION AND USE_BUNDLED_ZLIB) endif() endif() +SanitizeInput(USE_COMPRESSION) + if(NOT USE_COMPRESSION) find_package(ZLIB) diff --git a/cmake/SelectHTTPParser.cmake b/cmake/SelectHTTPParser.cmake index 9491c295b1c..00138c20da1 100644 --- a/cmake/SelectHTTPParser.cmake +++ b/cmake/SelectHTTPParser.cmake @@ -1,5 +1,11 @@ +include(SanitizeInput) + +sanitizeinput(USE_HTTP_PARSER) + # Optional external dependency: http-parser -if(USE_HTTP_PARSER STREQUAL "http-parser" OR USE_HTTP_PARSER STREQUAL "system") +if(USE_HTTP_PARSER STREQUAL "http-parser" OR + USE_HTTP_PARSER STREQUAL "httpparser" OR + USE_HTTP_PARSER STREQUAL "system") find_package(HTTP_Parser) if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index f7d46c0daff..a264945be45 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -1,8 +1,9 @@ -include(SanitizeBool) +include(SanitizeInput) # We try to find any packages our backends might use find_package(OpenSSL) find_package(mbedTLS) + if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "iOS") find_package(Security) find_package(CoreFoundation) @@ -12,24 +13,24 @@ if(USE_HTTPS STREQUAL "") set(USE_HTTPS ON) endif() -sanitizebool(USE_HTTPS) +sanitizeinput(USE_HTTPS) if(USE_HTTPS) # Auto-select TLS backend if(USE_HTTPS STREQUAL ON) if(SECURITY_FOUND) if(SECURITY_HAS_SSLCREATECONTEXT) - set(USE_HTTPS "SecureTransport") + set(USE_HTTPS "securetransport") else() message(STATUS "Security framework is too old, falling back to OpenSSL") set(USE_HTTPS "OpenSSL") endif() elseif(WIN32) - set(USE_HTTPS "WinHTTP") + set(USE_HTTPS "winhttp") elseif(OPENSSL_FOUND) - set(USE_HTTPS "OpenSSL") + set(USE_HTTPS "openssl") elseif(MBEDTLS_FOUND) - set(USE_HTTPS "mbedTLS") + set(USE_HTTPS "mbedtls") else() message(FATAL_ERROR "Unable to autodetect a usable HTTPS backend." "Please pass the backend name explicitly (-DUSE_HTTPS=backend)") @@ -37,7 +38,7 @@ if(USE_HTTPS) endif() # Check that we can find what's required for the selected backend - if(USE_HTTPS STREQUAL "SecureTransport") + if(USE_HTTPS STREQUAL "securetransport") if(NOT COREFOUNDATION_FOUND) message(FATAL_ERROR "Cannot use SecureTransport backend, CoreFoundation.framework not found") endif() @@ -48,25 +49,31 @@ if(USE_HTTPS) message(FATAL_ERROR "Cannot use SecureTransport backend, SSLCreateContext not supported") endif() - set(GIT_HTTPS_SECURETRANSPORT 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${SECURITY_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) list(APPEND LIBGIT2_PC_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) - elseif(USE_HTTPS STREQUAL "OpenSSL") + + set(GIT_HTTPS_SECURETRANSPORT 1) + add_feature_info("HTTPS" ON "using SecureTransport") + elseif(USE_HTTPS STREQUAL "openssl") if(NOT OPENSSL_FOUND) message(FATAL_ERROR "Asked for OpenSSL TLS backend, but it wasn't found") endif() - set(GIT_HTTPS_OPENSSL 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES}) + # Static OpenSSL (lib crypto.a) requires libdl, include it explicitly if(LINK_WITH_STATIC_LIBRARIES STREQUAL ON) list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_DL_LIBS}) endif() + list(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS}) list(APPEND LIBGIT2_PC_REQUIRES "openssl") - elseif(USE_HTTPS STREQUAL "mbedTLS") + + set(GIT_HTTPS_OPENSSL 1) + add_feature_info("HTTPS" ON "using OpenSSL") + elseif(USE_HTTPS STREQUAL "mbedtls") if(NOT MBEDTLS_FOUND) message(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found") endif() @@ -107,21 +114,27 @@ if(USE_HTTPS) add_definitions(-DGIT_DEFAULT_CERT_LOCATION="${CERT_LOCATION}") endif() - set(GIT_HTTPS_MBEDTLS 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${MBEDTLS_LIBRARIES}) # mbedTLS has no pkgconfig file, hence we can't require it # https://github.com/ARMmbed/mbedtls/issues/228 # For now, pass its link flags as our own list(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) - elseif(USE_HTTPS STREQUAL "Schannel") - set(GIT_HTTPS_SCHANNEL 1) + set(GIT_HTTPS_MBEDTLS 1) + + if(CERT_LOCATION) + add_feature_info("HTTPS" ON "using mbedTLS (certificate location: ${CERT_LOCATION})") + else() + add_feature_info("HTTPS" ON "using mbedTLS") + endif() + elseif(USE_HTTPS STREQUAL "schannel") list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") - elseif(USE_HTTPS STREQUAL "WinHTTP") - set(GIT_HTTPS_WINHTTP 1) + set(GIT_HTTPS_SCHANNEL 1) + add_feature_info("HTTPS" ON "using Schannel") + elseif(USE_HTTPS STREQUAL "winhttp") # Since MinGW does not come with headers or an import library for winhttp, # we have to include a private header and generate our own import library if(MINGW) @@ -135,20 +148,19 @@ if(USE_HTTPS) list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") - elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") - set(GIT_HTTPS_OPENSSL_DYNAMIC 1) + + set(GIT_HTTPS_WINHTTP 1) + add_feature_info("HTTPS" ON "using WinHTTP") + elseif(USE_HTTPS STREQUAL "openssl-dynamic") list(APPEND LIBGIT2_SYSTEM_LIBS dl) + + set(GIT_HTTPS_OPENSSL_DYNAMIC 1) + add_feature_info("HTTPS" ON "using OpenSSL-Dynamic") else() message(FATAL_ERROR "unknown HTTPS backend: ${USE_HTTPS}") endif() set(GIT_HTTPS 1) - - if(USE_HTTPS STREQUAL "mbedTLS" AND CERT_LOCATION) - add_feature_info("HTTPS" GIT_HTTPS "using ${USE_HTTPS} (certificate location: ${CERT_LOCATION})") - else() - add_feature_info("HTTPS" GIT_HTTPS "using ${USE_HTTPS}") - endif() else() set(GIT_HTTPS 0) add_feature_info("HTTPS" NO "HTTPS support is disabled") diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index b5180d2fdd2..cf229666a4a 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -1,21 +1,24 @@ # Select a hash backend -include(SanitizeBool) +include(SanitizeInput) -sanitizebool(USE_SHA1) -sanitizebool(USE_SHA256) +sanitizeinput(USE_HTTPS) +sanitizeinput(USE_SHA1) +sanitizeinput(USE_SHA256) # sha1 -if(USE_SHA1 STREQUAL "" OR USE_SHA1 STREQUAL ON) +if(USE_SHA1 STREQUAL "" OR + USE_SHA1 STREQUAL ON OR + USE_SHA1 STREQUAL "collisiondetection") SET(USE_SHA1 "builtin") -elseif(USE_SHA1 STREQUAL "HTTPS") - if(USE_HTTPS STREQUAL "SecureTransport") - set(USE_SHA1 "CommonCrypto") - elseif(USE_HTTPS STREQUAL "Schannel") - set(USE_SHA1 "Win32") - elseif(USE_HTTPS STREQUAL "WinHTTP") - set(USE_SHA1 "Win32") +elseif(USE_SHA1 STREQUAL "https") + if(USE_HTTPS STREQUAL "securetransport") + set(USE_SHA1 "commoncrypto") + elseif(USE_HTTPS STREQUAL "schannel") + set(USE_SHA1 "win32") + elseif(USE_HTTPS STREQUAL "winhttp") + set(USE_SHA1 "win32") elseif(USE_HTTPS) set(USE_SHA1 ${USE_HTTPS}) else() @@ -23,25 +26,28 @@ elseif(USE_SHA1 STREQUAL "HTTPS") endif() endif() -if(USE_SHA1 STREQUAL "Builtin" OR USE_SHA1 STREQUAL "CollisionDetection") - set(USE_SHA1 "builtin") -endif() - if(USE_SHA1 STREQUAL "builtin") set(GIT_SHA1_BUILTIN 1) -elseif(USE_SHA1 STREQUAL "OpenSSL") + add_feature_info(SHA1 ON "using bundled collision detection implementation") +elseif(USE_SHA1 STREQUAL "openssl") set(GIT_SHA1_OPENSSL 1) -elseif(USE_SHA1 STREQUAL "OpenSSL-FIPS") + add_feature_info(SHA1 ON "using OpenSSL") +elseif(USE_SHA1 STREQUAL "openssl-fips") set(GIT_SHA1_OPENSSL_FIPS 1) -elseif(USE_SHA1 STREQUAL "OpenSSL-Dynamic") - set(GIT_SHA1_OPENSSL_DYNAMIC 1) + add_feature_info(SHA1 ON "using OpenSSL-FIPS") +elseif(USE_SHA1 STREQUAL "openssl-dynamic") list(APPEND LIBGIT2_SYSTEM_LIBS dl) -elseif(USE_SHA1 STREQUAL "CommonCrypto") + set(GIT_SHA1_OPENSSL_DYNAMIC 1) + add_feature_info(SHA1 ON "using OpenSSL-Dynamic") +elseif(USE_SHA1 STREQUAL "commoncrypto") set(GIT_SHA1_COMMON_CRYPTO 1) -elseif(USE_SHA1 STREQUAL "mbedTLS") + add_feature_info(SHA1 ON "using CommonCrypto") +elseif(USE_SHA1 STREQUAL "mbedtls") set(GIT_SHA1_MBEDTLS 1) -elseif(USE_SHA1 STREQUAL "Win32") + add_feature_info(SHA1 ON "using mbedTLS") +elseif(USE_SHA1 STREQUAL "win32") set(GIT_SHA1_WIN32 1) + add_feature_info(SHA1 ON "using Win32 APIs") else() message(FATAL_ERROR "asked for unknown SHA1 backend: ${USE_SHA1}") endif() @@ -50,23 +56,19 @@ endif() if(USE_SHA256 STREQUAL "" OR USE_SHA256 STREQUAL ON) if(USE_HTTPS) - SET(USE_SHA256 "HTTPS") + SET(USE_SHA256 "https") else() SET(USE_SHA256 "builtin") endif() endif() -if(USE_SHA256 STREQUAL "Builtin") - set(USE_SHA256 "builtin") -endif() - -if(USE_SHA256 STREQUAL "HTTPS") - if(USE_HTTPS STREQUAL "SecureTransport") - set(USE_SHA256 "CommonCrypto") - elseif(USE_HTTPS STREQUAL "Schannel") - set(USE_SHA256 "Win32") - elseif(USE_HTTPS STREQUAL "WinHTTP") - set(USE_SHA256 "Win32") +if(USE_SHA256 STREQUAL "https") + if(USE_HTTPS STREQUAL "securetransport") + set(USE_SHA256 "commoncrypto") + elseif(USE_HTTPS STREQUAL "schannel") + set(USE_SHA256 "win32") + elseif(USE_HTTPS STREQUAL "winhttp") + set(USE_SHA256 "win32") elseif(USE_HTTPS) set(USE_SHA256 ${USE_HTTPS}) endif() @@ -74,27 +76,33 @@ endif() if(USE_SHA256 STREQUAL "builtin") set(GIT_SHA256_BUILTIN 1) -elseif(USE_SHA256 STREQUAL "OpenSSL") + add_feature_info(SHA256 ON "using bundled implementation") +elseif(USE_SHA256 STREQUAL "openssl") set(GIT_SHA256_OPENSSL 1) -elseif(USE_SHA256 STREQUAL "OpenSSL-FIPS") + add_feature_info(SHA256 ON "using OpenSSL") +elseif(USE_SHA256 STREQUAL "openssl-fips") set(GIT_SHA256_OPENSSL_FIPS 1) -elseif(USE_SHA256 STREQUAL "OpenSSL-Dynamic") - set(GIT_SHA256_OPENSSL_DYNAMIC 1) + add_feature_info(SHA256 ON "using OpenSSL-FIPS") +elseif(USE_SHA256 STREQUAL "openssl-dynamic") list(APPEND LIBGIT2_SYSTEM_LIBS dl) -elseif(USE_SHA256 STREQUAL "CommonCrypto") + set(GIT_SHA256_OPENSSL_DYNAMIC 1) + add_feature_info(SHA256 ON "using OpenSSL-Dynamic") +elseif(USE_SHA256 STREQUAL "commoncrypto") set(GIT_SHA256_COMMON_CRYPTO 1) -elseif(USE_SHA256 STREQUAL "mbedTLS") + add_feature_info(SHA256 ON "using CommonCrypto") +elseif(USE_SHA256 STREQUAL "mbedtls") set(GIT_SHA256_MBEDTLS 1) -elseif(USE_SHA256 STREQUAL "Win32") + add_feature_info(SHA256 ON "using mbedTLS") +elseif(USE_SHA256 STREQUAL "win32") set(GIT_SHA256_WIN32 1) + add_feature_info(SHA256 ON "using Win32 APIs") else() message(FATAL_ERROR "asked for unknown SHA256 backend: ${USE_SHA256}") endif() # add library requirements - -if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL" OR - USE_SHA1 STREQUAL "OpenSSL-FIPS" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") +if(USE_SHA1 STREQUAL "openssl" OR USE_SHA256 STREQUAL "openssl" OR + USE_SHA1 STREQUAL "openssl-fips" OR USE_SHA256 STREQUAL "openssl-fips") if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LIBGIT2_PC_LIBS "-lssl") else() @@ -102,7 +110,7 @@ if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL" OR endif() endif() -if(USE_SHA1 STREQUAL "mbedTLS" OR USE_SHA256 STREQUAL "mbedTLS") +if(USE_SHA1 STREQUAL "mbedtls" OR USE_SHA256 STREQUAL "mbedtls") list(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${MBEDTLS_LIBRARIES}) # mbedTLS has no pkgconfig file, hence we can't require it @@ -111,11 +119,6 @@ if(USE_SHA1 STREQUAL "mbedTLS" OR USE_SHA256 STREQUAL "mbedTLS") list(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) endif() -# notify feature enablement - -add_feature_info(SHA1 ON "using ${USE_SHA1}") -add_feature_info(SHA256 ON "using ${USE_SHA256}") - # warn for users who do not use sha1dc if(NOT "${USE_SHA1}" STREQUAL "builtin") diff --git a/cmake/SelectI18n.cmake b/cmake/SelectI18n.cmake index aa70ee2f20e..f95e1244135 100644 --- a/cmake/SelectI18n.cmake +++ b/cmake/SelectI18n.cmake @@ -1,9 +1,9 @@ -include(SanitizeBool) +include(SanitizeInput) find_package(IntlIconv) if(USE_I18N STREQUAL "" AND NOT USE_ICONV STREQUAL "") - sanitizebool(USE_ICONV) + sanitizeinput(USE_ICONV) set(USE_I18N "${USE_ICONV}") endif() @@ -11,7 +11,7 @@ if(USE_I18N STREQUAL "") set(USE_I18N ON) endif() -sanitizebool(USE_I18N) +sanitizeinput(USE_I18N) if(USE_I18N) if(USE_I18N STREQUAL ON) diff --git a/cmake/SelectNsec.cmake b/cmake/SelectNsec.cmake index 392b92bc45c..59606a47f81 100644 --- a/cmake/SelectNsec.cmake +++ b/cmake/SelectNsec.cmake @@ -1,7 +1,7 @@ -include(SanitizeBool) +include(SanitizeInput) include(FeatureSummary) -sanitizebool(USE_NSEC) +sanitizeinput(USE_NSEC) if((USE_NSEC STREQUAL ON OR USE_NSEC STREQUAL "") AND HAVE_STRUCT_STAT_ST_MTIM) set(USE_NSEC "mtim") diff --git a/cmake/SelectThreads.cmake b/cmake/SelectThreads.cmake index 45c76fa0f5f..1a6ddfa9670 100644 --- a/cmake/SelectThreads.cmake +++ b/cmake/SelectThreads.cmake @@ -1,6 +1,6 @@ -include(SanitizeBool) +include(SanitizeInput) -sanitizebool(USE_THREADS) +sanitizeinput(USE_THREADS) if(NOT WIN32) find_package(Threads) diff --git a/cmake/SelectXdiff.cmake b/cmake/SelectXdiff.cmake index 718a6fc4fe3..91d72ad34b6 100644 --- a/cmake/SelectXdiff.cmake +++ b/cmake/SelectXdiff.cmake @@ -1,7 +1,12 @@ # Optional external dependency: xdiff + +include(SanitizeInput) + +sanitizeinput(USE_XDIFF) + if(USE_XDIFF STREQUAL "system") message(FATAL_ERROR "external/system xdiff is not yet supported") -else() +elseif(USE_XDIFF STREQUAL "builtin" OR USE_XDIFF STREQUAL "") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/xdiff" "${PROJECT_BINARY_DIR}/deps/xdiff") list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/xdiff") list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") diff --git a/deps/ntlmclient/CMakeLists.txt b/deps/ntlmclient/CMakeLists.txt index f1f5de162a0..a3e8c2aff03 100644 --- a/deps/ntlmclient/CMakeLists.txt +++ b/deps/ntlmclient/CMakeLists.txt @@ -13,22 +13,22 @@ else() file(GLOB SRC_NTLMCLIENT_UNICODE "unicode_builtin.c" "unicode_builtin.h") endif() -if(USE_HTTPS STREQUAL "SecureTransport") +if(USE_HTTPS STREQUAL "securetransport") add_definitions(-DCRYPT_COMMONCRYPTO) set(SRC_NTLMCLIENT_CRYPTO "crypt_commoncrypto.c" "crypt_commoncrypto.h") # CC_MD4 has been deprecated in macOS 10.15. set_source_files_properties("crypt_commoncrypto.c" COMPILE_FLAGS "-Wno-deprecated") -elseif(USE_HTTPS STREQUAL "OpenSSL") +elseif(USE_HTTPS STREQUAL "openssl") add_definitions(-DCRYPT_OPENSSL) add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) include_directories(${OPENSSL_INCLUDE_DIR}) set(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h") -elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") +elseif(USE_HTTPS STREQUAL "openssl-dynamic") add_definitions(-DCRYPT_OPENSSL) add_definitions(-DCRYPT_OPENSSL_DYNAMIC) add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) set(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h") -elseif(USE_HTTPS STREQUAL "mbedTLS") +elseif(USE_HTTPS STREQUAL "mbedtls") add_definitions(-DCRYPT_MBEDTLS) include_directories(${MBEDTLS_INCLUDE_DIR}) set(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c" "crypt_mbedtls.h" "crypt_builtin_md4.c") diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 5831c213b7b..0811057f3a3 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -34,16 +34,16 @@ if(USE_SHA1 STREQUAL "builtin") target_compile_definitions(util PRIVATE SHA1DC_NO_STANDARD_INCLUDES=1) target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_SHA1_C=\"git2_util.h\") target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"git2_util.h\") -elseif(USE_SHA1 STREQUAL "SHA1CollisionDetection") - file(GLOB UTIL_SRC_SHA1 hash/collisiondetect.*) -elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic" OR USE_SHA1 STREQUAL "OpenSSL-FIPS") +elseif(USE_SHA1 STREQUAL "openssl" OR + USE_SHA1 STREQUAL "openssl-dynamic" OR + USE_SHA1 STREQUAL "openssl-fips") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) file(GLOB UTIL_SRC_SHA1 hash/openssl.*) -elseif(USE_SHA1 STREQUAL "CommonCrypto") +elseif(USE_SHA1 STREQUAL "commoncrypto") file(GLOB UTIL_SRC_SHA1 hash/common_crypto.*) -elseif(USE_SHA1 STREQUAL "mbedTLS") +elseif(USE_SHA1 STREQUAL "mbedtls") file(GLOB UTIL_SRC_SHA1 hash/mbedtls.*) -elseif(USE_SHA1 STREQUAL "Win32") +elseif(USE_SHA1 STREQUAL "win32") file(GLOB UTIL_SRC_SHA1 hash/win32.*) else() message(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}") @@ -53,14 +53,16 @@ list(SORT UTIL_SRC_SHA1) if(USE_SHA256 STREQUAL "builtin") file(GLOB UTIL_SRC_SHA256 hash/builtin.* hash/rfc6234/*) -elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") +elseif(USE_SHA256 STREQUAL "openssl" OR + USE_SHA256 STREQUAL "openssl-dynamic" OR + USE_SHA256 STREQUAL "openssl-fips") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) file(GLOB UTIL_SRC_SHA256 hash/openssl.*) -elseif(USE_SHA256 STREQUAL "CommonCrypto") +elseif(USE_SHA256 STREQUAL "commoncrypto") file(GLOB UTIL_SRC_SHA256 hash/common_crypto.*) -elseif(USE_SHA256 STREQUAL "mbedTLS") +elseif(USE_SHA256 STREQUAL "mbedtls") file(GLOB UTIL_SRC_SHA256 hash/mbedtls.*) -elseif(USE_SHA256 STREQUAL "Win32") +elseif(USE_SHA256 STREQUAL "win32") file(GLOB UTIL_SRC_SHA256 hash/win32.*) else() message(FATAL_ERROR "asked for unknown SHA256 backend: ${USE_SHA256}") From 24d50ad87b70a6120a4d645874ec2eca6e85beed Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jan 2025 10:36:39 +0000 Subject: [PATCH 778/816] cli: add version command Move the `--version` information into its own command, so that we can support `--build-options`. --- src/cli/cmd.h | 1 + src/cli/cmd_version.c | 91 +++++++++++++++++++++++++++++++++++++++++++ src/cli/main.c | 10 ++++- 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/cli/cmd_version.c diff --git a/src/cli/cmd.h b/src/cli/cmd.h index 194a0b5058d..bce4709fb7a 100644 --- a/src/cli/cmd.h +++ b/src/cli/cmd.h @@ -33,5 +33,6 @@ extern int cmd_hash_object(int argc, char **argv); extern int cmd_help(int argc, char **argv); extern int cmd_index_pack(int argc, char **argv); extern int cmd_init(int argc, char **argv); +extern int cmd_version(int argc, char **argv); #endif /* CLI_cmd_h__ */ diff --git a/src/cli/cmd_version.c b/src/cli/cmd_version.c new file mode 100644 index 00000000000..3d415b49229 --- /dev/null +++ b/src/cli/cmd_version.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include "common.h" +#include "cmd.h" + +#define COMMAND_NAME "version" + +static int build_options; + +struct feature_names { + int feature; + const char *name; +}; + +static const struct feature_names feature_names[] = { + { GIT_FEATURE_SHA1, "sha1" }, + { GIT_FEATURE_SHA256, "sha256" }, + { GIT_FEATURE_THREADS, "threads" }, + { GIT_FEATURE_NSEC, "nsec" }, + { GIT_FEATURE_COMPRESSION, "compression" }, + { GIT_FEATURE_I18N, "i18n" }, + { GIT_FEATURE_REGEX, "regex" }, + { GIT_FEATURE_SSH, "ssh" }, + { GIT_FEATURE_HTTPS, "https" }, + { GIT_FEATURE_HTTP_PARSER, "http_parser" }, + { GIT_FEATURE_AUTH_NTLM, "auth_ntlm" }, + { GIT_FEATURE_AUTH_NEGOTIATE, "auth_negotiate" }, + { 0, NULL } +}; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, + + { CLI_OPT_TYPE_SWITCH, "build-options", 0, &build_options, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "show compile-time options" }, + { 0 }, +}; + +static int print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts, 0); + printf("\n"); + + printf("Display version information for %s.\n", PROGRAM_NAME); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); + + return 0; +} + +int cmd_version(int argc, char **argv) +{ + cli_opt invalid_opt; + const struct feature_names *f; + const char *backend; + int supported_features; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (cli_opt__show_help) { + print_help(); + return 0; + } + + printf("%s version %s\n", PROGRAM_NAME, LIBGIT2_VERSION); + + if (build_options) { + supported_features = git_libgit2_features(); + + for (f = feature_names; f->feature; f++) { + if (!(supported_features & f->feature)) + continue; + + backend = git_libgit2_feature_backend(f->feature); + printf("backend-%s: %s\n", f->name, backend); + } + } + + return 0; +} diff --git a/src/cli/main.c b/src/cli/main.c index be913ba64ec..4716d6ddee9 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -38,6 +38,7 @@ const cli_cmd_spec cli_cmds[] = { { "help", cmd_help, "Display help information" }, { "index-pack", cmd_index_pack, "Create an index for a packfile" }, { "init", cmd_init, "Create a new git repository" }, + { "version", cmd_version, "Show application version information" }, { NULL } }; @@ -76,6 +77,12 @@ static void help_args(int *argc, char **argv) *argc = 1; } +static void version_args(int *argc, char **argv) +{ + argv[0] = "version"; + *argc = 1; +} + int main(int argc, char **argv) { const cli_cmd_spec *cmd; @@ -110,7 +117,8 @@ int main(int argc, char **argv) } if (show_version) { - printf("%s version %s\n", PROGRAM_NAME, LIBGIT2_VERSION); + version_args(&argc, argv); + ret = cmd_version(argc, argv); goto done; } From fb7fef0d729da561a4f9892c051dea5c462cd74d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jan 2025 12:03:58 +0000 Subject: [PATCH 779/816] hash: allow `unsigned int` != `size_t` in sha256 Our bundled SHA256 implementation passes a `size_t` as an `unsigned int`. Stop doing that. --- src/util/hash/builtin.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/util/hash/builtin.c b/src/util/hash/builtin.c index cc4aa58fe8d..b4736efbc66 100644 --- a/src/util/hash/builtin.c +++ b/src/util/hash/builtin.c @@ -32,13 +32,23 @@ int git_hash_sha256_init(git_hash_sha256_ctx *ctx) return 0; } -int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) +int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *_data, size_t len) { + const unsigned char *data = _data; GIT_ASSERT_ARG(ctx); - if (SHA256Input(&ctx->c, data, len)) { - git_error_set(GIT_ERROR_SHA, "SHA256 error"); - return -1; + + while (len > 0) { + unsigned int chunk = (len > UINT_MAX) ? UINT_MAX : (unsigned int)len; + + if (SHA256Input(&ctx->c, data, chunk)) { + git_error_set(GIT_ERROR_SHA, "SHA256 error"); + return -1; + } + + data += chunk; + len -= chunk; } + return 0; } From 56e2a85643fab018c154767e5a1f5fbf794fc774 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 23 Dec 2024 11:53:23 +0000 Subject: [PATCH 780/816] sha256: simplify API changes for sha256 support There are several places where users may want to specify the type of object IDs (sha1 or sha256) that should be used, for example, when dealing with repositories, indexes, etc. However, given that sha256 support remains disappointingly uncommon in the wild, we should avoid hard API breaks when possible. Instead, update these APIs to have an "extended" format (eg, `git_odb_open_ext`) that provides an options structure with oid type information. This allows callers who do care about sha256 to use it, and callers who do not to avoid gratuitous API breakage. --- examples/diff.c | 6 --- examples/show-index.c | 4 -- fuzzers/packfile_fuzzer.c | 7 --- include/git2/diff.h | 40 ++++++++++++++-- include/git2/index.h | 66 ++++++++++++++++----------- include/git2/odb.h | 59 ++++++++++++++---------- include/git2/sys/repository.h | 28 +++++++----- src/libgit2/apply.c | 8 ++-- src/libgit2/diff.h | 10 ++++ src/libgit2/diff_parse.c | 19 ++++---- src/libgit2/index.c | 41 ++++++----------- src/libgit2/index.h | 30 +++++++----- src/libgit2/merge.c | 8 +++- src/libgit2/odb.c | 39 +++++----------- src/libgit2/odb.h | 22 +++++---- src/libgit2/repository.c | 34 ++++++++------ src/libgit2/repository.h | 12 ++++- src/libgit2/stash.c | 12 +++-- tests/libgit2/attr/repo.c | 4 -- tests/libgit2/checkout/index.c | 5 +- tests/libgit2/clone/nonetwork.c | 6 ++- tests/libgit2/diff/diff_helpers.c | 10 ---- tests/libgit2/diff/index.c | 5 +- tests/libgit2/index/cache.c | 13 ++++-- tests/libgit2/index/inmemory.c | 4 +- tests/libgit2/index/racy.c | 5 +- tests/libgit2/index/read_index.c | 18 +++++--- tests/libgit2/index/tests.c | 33 ++++++++------ tests/libgit2/index/tests256.c | 65 ++++++++++++++++++++------ tests/libgit2/network/remote/local.c | 10 +--- tests/libgit2/object/raw/write.c | 2 +- tests/libgit2/object/tree/update.c | 12 ++--- tests/libgit2/odb/backend/loose.c | 2 +- tests/libgit2/odb/backend/mempack.c | 2 +- tests/libgit2/odb/backend/nobackend.c | 10 ++-- tests/libgit2/odb/foreach.c | 5 +- tests/libgit2/odb/loose.c | 25 +++++----- tests/libgit2/odb/mixed.c | 2 +- tests/libgit2/odb/open.c | 8 ++-- tests/libgit2/odb/packed.c | 2 +- tests/libgit2/odb/packed256.c | 2 +- tests/libgit2/odb/packedone.c | 3 +- tests/libgit2/odb/packedone256.c | 2 +- tests/libgit2/odb/sorting.c | 4 +- tests/libgit2/refs/iterator.c | 2 +- tests/libgit2/repo/new.c | 23 ++-------- tests/libgit2/repo/setters.c | 7 ++- tests/libgit2/reset/hard.c | 3 +- tests/libgit2/status/worktree_init.c | 4 +- tests/libgit2/submodule/lookup.c | 2 +- 50 files changed, 419 insertions(+), 326 deletions(-) diff --git a/examples/diff.c b/examples/diff.c index 80c5200e908..ed8fbd60d42 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -189,15 +189,9 @@ static void compute_diff_no_index(git_diff **diff, struct diff_options *o) { git_patch_to_buf(&buf, patch), "patch to buf", NULL); -#ifdef GIT_EXPERIMENTAL_SHA256 - check_lg2( - git_diff_from_buffer(diff, buf.ptr, buf.size, NULL), - "diff from patch", NULL); -#else check_lg2( git_diff_from_buffer(diff, buf.ptr, buf.size), "diff from patch", NULL); -#endif git_patch_free(patch); git_buf_dispose(&buf); diff --git a/examples/show-index.c b/examples/show-index.c index ac0040874ec..fb797e04beb 100644 --- a/examples/show-index.c +++ b/examples/show-index.c @@ -30,11 +30,7 @@ int lg2_show_index(git_repository *repo, int argc, char **argv) dirlen = strlen(dir); if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) { -#ifdef GIT_EXPERIMENTAL_SHA256 - check_lg2(git_index_open(&index, dir, NULL), "could not open index", dir); -#else check_lg2(git_index_open(&index, dir), "could not open index", dir); -#endif } else { check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir); check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL); diff --git a/fuzzers/packfile_fuzzer.c b/fuzzers/packfile_fuzzer.c index bcbdd8bc40b..cc4c33ad536 100644 --- a/fuzzers/packfile_fuzzer.c +++ b/fuzzers/packfile_fuzzer.c @@ -37,17 +37,10 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) abort(); } -#ifdef GIT_EXPERIMENTAL_SHA256 - if (git_odb_new(&odb, NULL) < 0) { - fprintf(stderr, "Failed to create the odb\n"); - abort(); - } -#else if (git_odb_new(&odb) < 0) { fprintf(stderr, "Failed to create the odb\n"); abort(); } -#endif if (git_mempack_new(&mempack) < 0) { fprintf(stderr, "Failed to create the mempack\n"); diff --git a/include/git2/diff.h b/include/git2/diff.h index b12e8ab2754..856a28f7943 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -1321,6 +1321,8 @@ GIT_EXTERN(int) git_diff_buffers( */ typedef struct { unsigned int version; + + /** Object ID type used in the patch file. */ git_oid_t oid_type; } git_diff_parse_options; @@ -1330,8 +1332,7 @@ typedef struct { /** Stack initializer for diff parse options. Alternatively use * `git_diff_parse_options_init` programmatic initialization. */ -#define GIT_DIFF_PARSE_OPTIONS_INIT \ - { GIT_DIFF_PARSE_OPTIONS_VERSION, GIT_OID_DEFAULT } +#define GIT_DIFF_PARSE_OPTIONS_INIT { GIT_DIFF_PARSE_OPTIONS_VERSION } /** * Read the contents of a git patch file into a `git_diff` object. @@ -1347,6 +1348,9 @@ typedef struct { * implementation, it will not read unified diffs produced by * the `diff` program, nor any other types of patch files. * + * @note This API only supports SHA1 patch files + * @see git_diff_from_buffer_ext + * * @param out A pointer to a git_diff pointer that will be allocated. * @param content The contents of a patch file * @param content_len The length of the patch file contents @@ -1355,11 +1359,37 @@ typedef struct { GIT_EXTERN(int) git_diff_from_buffer( git_diff **out, const char *content, - size_t content_len + size_t content_len); + #ifdef GIT_EXPERIMENTAL_SHA256 - , git_diff_parse_options *opts + +/** + * Read the contents of a git patch file into a `git_diff` object. + * + * The diff object produced is similar to the one that would be + * produced if you actually produced it computationally by comparing + * two trees, however there may be subtle differences. For example, + * a patch file likely contains abbreviated object IDs, so the + * object IDs in a `git_diff_delta` produced by this function will + * also be abbreviated. + * + * This function will only read patch files created by a git + * implementation, it will not read unified diffs produced by + * the `diff` program, nor any other types of patch files. + * + * @param out A pointer to a git_diff pointer that will be allocated. + * @param content The contents of a patch file + * @param content_len The length of the patch file contents + * @param opts Options controlling diff parsing + * @return 0 or an error code + */ +GIT_EXTERN(int) git_diff_from_buffer_ext( + git_diff **out, + const char *content, + size_t content_len, + git_diff_parse_options *opts); + #endif - ); /** * This is an opaque structure which is allocated by `git_diff_get_stats`. diff --git a/include/git2/index.h b/include/git2/index.h index 0adff1abd95..6aadbef6b73 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -189,8 +189,6 @@ typedef enum { GIT_INDEX_STAGE_THEIRS = 3 } git_index_stage_t; -#ifdef GIT_EXPERIMENTAL_SHA256 - /** * The options for opening or creating an index. * @@ -233,62 +231,76 @@ GIT_EXTERN(int) git_index_options_init( unsigned int version); /** - * Creates a new bare Git index object, without a repository to back - * it. This index object is capable of storing SHA256 objects. + * Create a new bare Git index object as a memory representation + * of the Git index file in 'index_path', without a repository + * to back it. + * + * Since there is no ODB or working directory behind this index, + * any Index methods which rely on these (e.g. index_add_bypath) + * will fail with the GIT_ERROR error code. + * + * If you need to access the index of an actual repository, + * use the `git_repository_index` wrapper. + * + * The index must be freed once it's no longer in use. + * + * @note This API only supports SHA1 indexes + * @see git_index_open_ext * * @param index_out the pointer for the new index * @param index_path the path to the index file in disk - * @param opts the options for opening the index, or NULL * @return 0 or an error code */ GIT_EXTERN(int) git_index_open( git_index **index_out, - const char *index_path, - const git_index_options *opts); + const char *index_path); + +#ifdef GIT_EXPERIMENTAL_SHA256 /** - * Create an in-memory index object. + * Creates a new bare Git index object, without a repository to back + * it. This index object is capable of storing SHA256 objects. * * @param index_out the pointer for the new index + * @param index_path the path to the index file in disk * @param opts the options for opening the index, or NULL * @return 0 or an error code */ -GIT_EXTERN(int) git_index_new(git_index **index_out, const git_index_options *opts); +GIT_EXTERN(int) git_index_open_ext( + git_index **index_out, + const char *index_path, + const git_index_options *opts); -#else +#endif /** - * Create a new bare Git index object as a memory representation - * of the Git index file in 'index_path', without a repository - * to back it. - * - * Since there is no ODB or working directory behind this index, - * any Index methods which rely on these (e.g. index_add_bypath) - * will fail with the GIT_ERROR error code. + * Create an in-memory index object. * - * If you need to access the index of an actual repository, - * use the `git_repository_index` wrapper. + * This index object cannot be read/written to the filesystem, + * but may be used to perform in-memory index operations. * * The index must be freed once it's no longer in use. * + * @note This API only supports SHA1 indexes + * @see git_index_new_ext + * * @param index_out the pointer for the new index - * @param index_path the path to the index file in disk * @return 0 or an error code */ -GIT_EXTERN(int) git_index_open(git_index **index_out, const char *index_path); +GIT_EXTERN(int) git_index_new(git_index **index_out); + +#ifdef GIT_EXPERIMENTAL_SHA256 /** * Create an in-memory index object. * - * This index object cannot be read/written to the filesystem, - * but may be used to perform in-memory index operations. - * - * The index must be freed once it's no longer in use. - * * @param index_out the pointer for the new index + * @param opts the options for opening the index, or NULL * @return 0 or an error code */ -GIT_EXTERN(int) git_index_new(git_index **index_out); +GIT_EXTERN(int) git_index_new_ext( + git_index **index_out, + const git_index_options *opts); #endif diff --git a/include/git2/odb.h b/include/git2/odb.h index e809c36d70e..e81e41c910a 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -62,44 +62,34 @@ typedef struct { */ #define GIT_ODB_OPTIONS_INIT { GIT_ODB_OPTIONS_VERSION } -#ifdef GIT_EXPERIMENTAL_SHA256 - /** * Create a new object database with no backends. * - * @param[out] odb location to store the database pointer, if opened. - * @param opts the options for this object database or NULL for defaults - * @return 0 or an error code - */ -GIT_EXTERN(int) git_odb_new(git_odb **odb, const git_odb_options *opts); - -/** - * Create a new object database and automatically add loose and packed - * backends. + * Before the ODB can be used for read/writing, a custom database + * backend must be manually added using `git_odb_add_backend()` * - * @param[out] odb_out location to store the database pointer, if opened. - * Set to NULL if the open failed. - * @param objects_dir path of the backends' "objects" directory. - * @param opts the options for this object database or NULL for defaults + * @note This API only supports SHA1 object databases + * @see git_odb_new_ext + * + * @param[out] odb location to store the database pointer, if opened. * @return 0 or an error code */ -GIT_EXTERN(int) git_odb_open( - git_odb **odb_out, - const char *objects_dir, - const git_odb_options *opts); +GIT_EXTERN(int) git_odb_new(git_odb **odb); -#else +#ifdef GIT_EXPERIMENTAL_SHA256 /** * Create a new object database with no backends. * - * Before the ODB can be used for read/writing, a custom database - * backend must be manually added using `git_odb_add_backend()` - * * @param[out] odb location to store the database pointer, if opened. + * @param opts the options for this object database or NULL for defaults * @return 0 or an error code */ -GIT_EXTERN(int) git_odb_new(git_odb **odb); +GIT_EXTERN(int) git_odb_new_ext( + git_odb **odb, + const git_odb_options *opts); + +#endif /** * Create a new object database and automatically add @@ -112,12 +102,33 @@ GIT_EXTERN(int) git_odb_new(git_odb **odb); * assuming `objects_dir` as the Objects folder which * contains a 'pack/' folder with the corresponding data * + * @note This API only supports SHA1 object databases + * @see git_odb_open_ext + * * @param[out] odb_out location to store the database pointer, if opened. * Set to NULL if the open failed. * @param objects_dir path of the backends' "objects" directory. * @return 0 or an error code */ GIT_EXTERN(int) git_odb_open(git_odb **odb_out, const char *objects_dir); + +#ifdef GIT_EXPERIMENTAL_SHA256 + +/** + * Create a new object database and automatically add loose and packed + * backends. + * + * @param[out] odb_out location to store the database pointer, if opened. + * Set to NULL if the open failed. + * @param objects_dir path of the backends' "objects" directory. + * @param opts the options for this object database or NULL for defaults + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_open_ext( + git_odb **odb_out, + const char *objects_dir, + const git_odb_options *opts); + #endif /** diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h index 026ac8a1d1a..cdd1a4bd2d6 100644 --- a/include/git2/sys/repository.h +++ b/include/git2/sys/repository.h @@ -20,8 +20,6 @@ */ GIT_BEGIN_DECL -#ifdef GIT_EXPERIMENTAL_SHA256 - /** * The options for creating an repository from scratch. * @@ -64,16 +62,6 @@ GIT_EXTERN(int) git_repository_new_options_init( git_repository_new_options *opts, unsigned int version); -/** - * Create a new repository with no backends. - * - * @param[out] out The blank repository - * @param opts the options for repository creation, or NULL for defaults - * @return 0 on success, or an error code - */ -GIT_EXTERN(int) git_repository_new(git_repository **out, git_repository_new_options *opts); -#else - /** * Create a new repository with neither backends nor config object * @@ -84,11 +72,27 @@ GIT_EXTERN(int) git_repository_new(git_repository **out, git_repository_new_opti * can fail to function properly: locations under $GIT_DIR, $GIT_COMMON_DIR, * or $GIT_INFO_DIR are impacted. * + * @note This API only creates SHA1 repositories + * @see git_repository_new_ext + * * @param[out] out The blank repository * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_new(git_repository **out); +#ifdef GIT_EXPERIMENTAL_SHA256 + +/** + * Create a new repository with no backends. + * + * @param[out] out The blank repository + * @param opts the options for repository creation, or NULL for defaults + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_repository_new_ext( + git_repository **out, + git_repository_new_options *opts); + #endif /** diff --git a/src/libgit2/apply.c b/src/libgit2/apply.c index 07e502db259..24922cfa550 100644 --- a/src/libgit2/apply.c +++ b/src/libgit2/apply.c @@ -621,6 +621,7 @@ int git_apply_to_tree( { git_index *postimage = NULL; git_reader *pre_reader = NULL, *post_reader = NULL; + git_index_options index_opts = GIT_INDEX_OPTIONS_FOR_REPO(repo); git_apply_options opts = GIT_APPLY_OPTIONS_INIT; const git_diff_delta *delta; size_t i; @@ -643,7 +644,7 @@ int git_apply_to_tree( * put the current tree into the postimage as-is - the diff will * replace any entries contained therein */ - if ((error = git_index__new(&postimage, repo->oid_type)) < 0 || + if ((error = git_index_new_ext(&postimage, &index_opts)) < 0 || (error = git_index_read_tree(postimage, preimage)) < 0 || (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) goto done; @@ -809,6 +810,7 @@ int git_apply( git_index *index = NULL, *preimage = NULL, *postimage = NULL; git_reader *pre_reader = NULL, *post_reader = NULL; git_apply_options opts = GIT_APPLY_OPTIONS_INIT; + git_index_options index_opts = GIT_INDEX_OPTIONS_FOR_REPO(repo); int error = GIT_EINVALID; GIT_ASSERT_ARG(repo); @@ -849,8 +851,8 @@ int git_apply( * having the full repo index, so we will limit our checkout * to only write these files that were affected by the diff. */ - if ((error = git_index__new(&preimage, repo->oid_type)) < 0 || - (error = git_index__new(&postimage, repo->oid_type)) < 0 || + if ((error = git_index_new_ext(&preimage, &index_opts)) < 0 || + (error = git_index_new_ext(&postimage, &index_opts)) < 0 || (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) goto done; diff --git a/src/libgit2/diff.h b/src/libgit2/diff.h index f21b2764505..c79a279e379 100644 --- a/src/libgit2/diff.h +++ b/src/libgit2/diff.h @@ -64,4 +64,14 @@ extern int git_diff_delta__casecmp(const void *a, const void *b); extern int git_diff__entry_cmp(const void *a, const void *b); extern int git_diff__entry_icmp(const void *a, const void *b); +#ifndef GIT_EXPERIMENTAL_SHA256 + +int git_diff_from_buffer_ext( + git_diff **out, + const char *content, + size_t content_len, + git_diff_parse_options *opts); + +#endif + #endif diff --git a/src/libgit2/diff_parse.c b/src/libgit2/diff_parse.c index 02eb21ef82c..25dcd8e1100 100644 --- a/src/libgit2/diff_parse.c +++ b/src/libgit2/diff_parse.c @@ -68,11 +68,16 @@ static git_diff_parsed *diff_parsed_alloc(git_oid_t oid_type) int git_diff_from_buffer( git_diff **out, const char *content, - size_t content_len -#ifdef GIT_EXPERIMENTAL_SHA256 - , git_diff_parse_options *opts -#endif - ) + size_t content_len) +{ + return git_diff_from_buffer_ext(out, content, content_len, NULL); +} + +int git_diff_from_buffer_ext( + git_diff **out, + const char *content, + size_t content_len, + git_diff_parse_options *opts) { git_diff_parsed *diff; git_patch *patch; @@ -83,12 +88,8 @@ int git_diff_from_buffer( *out = NULL; -#ifdef GIT_EXPERIMENTAL_SHA256 oid_type = (opts && opts->oid_type) ? opts->oid_type : GIT_OID_DEFAULT; -#else - oid_type = GIT_OID_DEFAULT; -#endif patch_opts.oid_type = oid_type; diff --git a/src/libgit2/index.c b/src/libgit2/index.c index a3142c8bcd9..7610781fc16 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -386,21 +386,25 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case) git_vector_sort(&index->reuc); } -int git_index__open( +int git_index_open_ext( git_index **index_out, const char *index_path, - git_oid_t oid_type) + const git_index_options *opts) { git_index *index; int error = -1; GIT_ASSERT_ARG(index_out); + GIT_ERROR_CHECK_VERSION(opts, GIT_INDEX_OPTIONS_VERSION, "git_index_options"); + + if (opts && opts->oid_type) + GIT_ASSERT_ARG(git_oid_type_is_valid(opts->oid_type)); index = git__calloc(1, sizeof(git_index)); GIT_ERROR_CHECK_ALLOC(index); - GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); - index->oid_type = oid_type; + index->oid_type = opts && opts->oid_type ? opts->oid_type : + GIT_OID_DEFAULT; if (git_pool_init(&index->tree_pool, 1) < 0) goto fail; @@ -441,39 +445,20 @@ int git_index__open( return error; } -#ifdef GIT_EXPERIMENTAL_SHA256 -int git_index_open( - git_index **index_out, - const char *index_path, - const git_index_options *opts) -{ - return git_index__open(index_out, index_path, - opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT); -} -#else int git_index_open(git_index **index_out, const char *index_path) { - return git_index__open(index_out, index_path, GIT_OID_SHA1); + return git_index_open_ext(index_out, index_path, NULL); } -#endif -int git_index__new(git_index **out, git_oid_t oid_type) +int git_index_new(git_index **out) { - return git_index__open(out, NULL, oid_type); + return git_index_open_ext(out, NULL, NULL); } -#ifdef GIT_EXPERIMENTAL_SHA256 -int git_index_new(git_index **out, const git_index_options *opts) +int git_index_new_ext(git_index **out, const git_index_options *opts) { - return git_index__new(out, - opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT); + return git_index_open_ext(out, NULL, opts); } -#else -int git_index_new(git_index **out) -{ - return git_index__new(out, GIT_OID_SHA1); -} -#endif static void index_free(git_index *index) { diff --git a/src/libgit2/index.h b/src/libgit2/index.h index 601e98f1ce2..aa2667de3e5 100644 --- a/src/libgit2/index.h +++ b/src/libgit2/index.h @@ -20,6 +20,10 @@ #define GIT_INDEX_FILE "index" #define GIT_INDEX_FILE_MODE 0666 +/* Helper to create index options based on repository options */ +#define GIT_INDEX_OPTIONS_FOR_REPO(r) \ + { GIT_INDEX_OPTIONS_VERSION, r ? r->oid_type : 0 } + extern bool git_index__enforce_unsaved_safety; struct git_index { @@ -143,17 +147,6 @@ GIT_INLINE(unsigned char *) git_index__checksum(git_index *index) return index->checksum; } -/* SHA256-aware internal functions */ - -extern int git_index__new( - git_index **index_out, - git_oid_t oid_type); - -extern int git_index__open( - git_index **index_out, - const char *index_path, - git_oid_t oid_type); - /* Copy the current entries vector *and* increment the index refcount. * Call `git_index__release_snapshot` when done. */ @@ -204,4 +197,19 @@ extern int git_indexwriter_commit(git_indexwriter *writer); */ extern void git_indexwriter_cleanup(git_indexwriter *writer); +/* SHA256 support */ + +#ifndef GIT_EXPERIMENTAL_SHA256 + +int git_index_open_ext( + git_index **index_out, + const char *index_path, + const git_index_options *opts); + +GIT_EXTERN(int) git_index_new_ext( + git_index **index_out, + const git_index_options *opts); + +#endif + #endif diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 25834c69fed..0c5bc0f82d0 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -2014,11 +2014,14 @@ static int index_from_diff_list( git_index *index; size_t i; git_merge_diff *conflict; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; int error = 0; *out = NULL; - if ((error = git_index__new(&index, oid_type)) < 0) + index_opts.oid_type = oid_type; + + if ((error = git_index_new_ext(&index, &index_opts)) < 0) return error; if ((error = git_index__fill(index, &diff_list->staged)) < 0) @@ -2195,6 +2198,7 @@ int git_merge_trees( { git_iterator *ancestor_iter = NULL, *our_iter = NULL, *their_iter = NULL; git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; + git_index_options index_opts = GIT_INDEX_OPTIONS_FOR_REPO(repo); int error; GIT_ASSERT_ARG(out); @@ -2211,7 +2215,7 @@ int git_merge_trees( result = our_tree; if (result) { - if ((error = git_index__new(out, repo->oid_type)) == 0) + if ((error = git_index_new_ext(out, &index_opts)) == 0) error = git_index_read_tree(*out, result); return error; diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 2c308c97772..5678524c4d0 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -536,9 +536,14 @@ static void normalize_options( opts->oid_type = GIT_OID_DEFAULT; } -int git_odb__new(git_odb **out, const git_odb_options *opts) +int git_odb_new_ext(git_odb **out, const git_odb_options *opts) { - git_odb *db = git__calloc(1, sizeof(*db)); + git_odb *db; + + GIT_ASSERT_ARG(out); + GIT_ERROR_CHECK_VERSION(opts, GIT_ODB_OPTIONS_VERSION, "git_odb_options"); + + db = git__calloc(1, sizeof(*db)); GIT_ERROR_CHECK_ALLOC(db); normalize_options(&db->options, opts); @@ -564,17 +569,10 @@ int git_odb__new(git_odb **out, const git_odb_options *opts) return 0; } -#ifdef GIT_EXPERIMENTAL_SHA256 -int git_odb_new(git_odb **out, const git_odb_options *opts) -{ - return git_odb__new(out, opts); -} -#else int git_odb_new(git_odb **out) { - return git_odb__new(out, NULL); + return git_odb_new_ext(out, NULL); } -#endif static int add_backend_internal( git_odb *odb, git_odb_backend *backend, @@ -833,7 +831,7 @@ int git_odb_set_commit_graph(git_odb *odb, git_commit_graph *cgraph) return error; } -int git_odb__open( +int git_odb_open_ext( git_odb **out, const char *objects_dir, const git_odb_options *opts) @@ -842,10 +840,11 @@ int git_odb__open( GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(objects_dir); + GIT_ERROR_CHECK_VERSION(opts, GIT_ODB_OPTIONS_VERSION, "git_odb_options"); *out = NULL; - if (git_odb__new(&db, opts) < 0) + if (git_odb_new_ext(&db, opts) < 0) return -1; if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) { @@ -857,25 +856,11 @@ int git_odb__open( return 0; } -#ifdef GIT_EXPERIMENTAL_SHA256 - -int git_odb_open( - git_odb **out, - const char *objects_dir, - const git_odb_options *opts) -{ - return git_odb__open(out, objects_dir, opts); -} - -#else - int git_odb_open(git_odb **out, const char *objects_dir) { - return git_odb__open(out, objects_dir, NULL); + return git_odb_open_ext(out, objects_dir, NULL); } -#endif - int git_odb__set_caps(git_odb *odb, int caps) { if (caps == GIT_ODB_CAP_FROM_OWNER) { diff --git a/src/libgit2/odb.h b/src/libgit2/odb.h index 7a712e20262..fa50b984971 100644 --- a/src/libgit2/odb.h +++ b/src/libgit2/odb.h @@ -160,13 +160,6 @@ void git_odb_object__free(void *object); /* SHA256 support */ -int git_odb__new(git_odb **out, const git_odb_options *opts); - -int git_odb__open( - git_odb **out, - const char *objects_dir, - const git_odb_options *opts); - int git_odb__hash( git_oid *out, const void *data, @@ -180,9 +173,22 @@ int git_odb__hashfile( git_object_t object_type, git_oid_t oid_type); -GIT_EXTERN(int) git_odb__backend_loose( +int git_odb__backend_loose( git_odb_backend **out, const char *objects_dir, git_odb_backend_loose_options *opts); +#ifndef GIT_EXPERIMENTAL_SHA256 + +int git_odb_open_ext( + git_odb **odb_out, + const char *objects_dir, + const git_odb_options *opts); + +int git_odb_new_ext( + git_odb **odb, + const git_odb_options *opts); + +#endif + #endif diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 2c36458b367..3be967c9406 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -328,33 +328,35 @@ static git_repository *repository_alloc(void) return NULL; } -int git_repository__new(git_repository **out, git_oid_t oid_type) +int git_repository_new_ext( + git_repository **out, + git_repository_new_options *opts) { git_repository *repo; + GIT_ASSERT_ARG(out); + GIT_ERROR_CHECK_VERSION(opts, + GIT_REPOSITORY_NEW_OPTIONS_VERSION, + "git_repository_new_options"); + + if (opts && opts->oid_type) + GIT_ASSERT_ARG(git_oid_type_is_valid(opts->oid_type)); + *out = repo = repository_alloc(); GIT_ERROR_CHECK_ALLOC(repo); - GIT_ASSERT_ARG(git_oid_type_is_valid(oid_type)); - repo->is_bare = 1; repo->is_worktree = 0; - repo->oid_type = oid_type; + repo->oid_type = opts && opts->oid_type ? opts->oid_type : + GIT_OID_DEFAULT; return 0; } -#ifdef GIT_EXPERIMENTAL_SHA256 -int git_repository_new(git_repository **out, git_repository_new_options *opts) +int git_repository_new(git_repository **out) { - return git_repository__new(out, opts && opts->oid_type ? opts->oid_type : GIT_OID_DEFAULT); + return git_repository_new_ext(out, NULL); } -#else -int git_repository_new(git_repository** out) -{ - return git_repository__new(out, GIT_OID_SHA1); -} -#endif static int load_config_data(git_repository *repo, const git_config *config) { @@ -1548,7 +1550,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) odb_opts.oid_type = repo->oid_type; if ((error = repository_odb_path(&odb_path, repo)) < 0 || - (error = git_odb__new(&odb, &odb_opts)) < 0 || + (error = git_odb_new_ext(&odb, &odb_opts)) < 0 || (error = repository_odb_alternates(odb, repo)) < 0) return error; @@ -1657,11 +1659,13 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) if (repo->_index == NULL) { git_str index_path = GIT_STR_INIT; git_index *index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; if ((error = repository_index_path(&index_path, repo)) < 0) return error; - error = git_index__open(&index, index_path.ptr, repo->oid_type); + index_opts.oid_type = repo->oid_type; + error = git_index_open_ext(&index, index_path.ptr, &index_opts); if (!error) { GIT_REFCOUNT_OWN(index, repo); diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index fbf143894e6..7da2d165577 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -15,6 +15,7 @@ #include "git2/repository.h" #include "git2/object.h" #include "git2/config.h" +#include "git2/sys/repository.h" #include "array.h" #include "cache.h" @@ -281,7 +282,14 @@ int git_repository__set_objectformat( git_repository *repo, git_oid_t oid_type); -/* SHA256-aware internal functions */ -int git_repository__new(git_repository **out, git_oid_t oid_type); +/* SHA256 support */ + +#ifndef GIT_EXPERIMENTAL_SHA256 + +GIT_EXTERN(int) git_repository_new_ext( + git_repository **out, + git_repository_new_options *opts); + +#endif #endif diff --git a/src/libgit2/stash.c b/src/libgit2/stash.c index b49e95cdb21..23c82b408fd 100644 --- a/src/libgit2/stash.c +++ b/src/libgit2/stash.c @@ -281,10 +281,11 @@ static int build_untracked_tree( git_tree *i_tree = NULL; git_diff *diff = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_index_options index_opts = GIT_INDEX_OPTIONS_FOR_REPO(repo); struct stash_update_rules data = {0}; int error; - if ((error = git_index__new(&i_index, repo->oid_type)) < 0) + if ((error = git_index_new_ext(&i_index, &index_opts)) < 0) goto cleanup; if (flags & GIT_STASH_INCLUDE_UNTRACKED) { @@ -484,10 +485,11 @@ static int commit_worktree( { git_index *i_index = NULL, *r_index = NULL; git_tree *w_tree = NULL; + git_index_options index_opts = GIT_INDEX_OPTIONS_FOR_REPO(repo); int error = 0, ignorecase; if ((error = git_repository_index(&r_index, repo) < 0) || - (error = git_index__new(&i_index, repo->oid_type)) < 0 || + (error = git_index_new_ext(&i_index, &index_opts)) < 0 || (error = git_index__fill(i_index, &r_index->entries) < 0) || (error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0) goto cleanup; @@ -688,6 +690,7 @@ int git_stash_save_with_opts( git_str msg = GIT_STR_INIT; git_tree *tree = NULL; git_reference *head = NULL; + git_index_options index_opts = GIT_INDEX_OPTIONS_FOR_REPO(repo); bool has_paths = false; int error; @@ -732,7 +735,7 @@ int git_stash_save_with_opts( i_commit, b_commit, u_commit)) < 0) goto cleanup; } else { - if ((error = git_index__new(&paths_index, repo->oid_type)) < 0 || + if ((error = git_index_new_ext(&paths_index, &index_opts)) < 0 || (error = retrieve_head(&head, repo)) < 0 || (error = git_reference_peel((git_object**)&tree, head, GIT_OBJECT_TREE)) < 0 || (error = git_index_read_tree(paths_index, tree)) < 0 || @@ -1010,9 +1013,10 @@ static int stage_new_files( git_iterator *iterators[2] = { NULL, NULL }; git_iterator_options iterator_options = GIT_ITERATOR_OPTIONS_INIT; git_index *index = NULL; + git_index_options index_opts = GIT_INDEX_OPTIONS_FOR_REPO(repo); int error; - if ((error = git_index__new(&index, repo->oid_type)) < 0 || + if ((error = git_index_new_ext(&index, &index_opts)) < 0 || (error = git_iterator_for_tree( &iterators[0], parent_tree, &iterator_options)) < 0 || (error = git_iterator_for_tree( diff --git a/tests/libgit2/attr/repo.c b/tests/libgit2/attr/repo.c index 793c1a7d041..4c71bddb75c 100644 --- a/tests/libgit2/attr/repo.c +++ b/tests/libgit2/attr/repo.c @@ -317,11 +317,7 @@ void test_attr_repo__inmemory_repo_without_index(void) git_index *index = NULL; /* setup bare in-memory repo without index */ -#ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&inmemory, NULL)); -#else cl_git_pass(git_repository_new(&inmemory)); -#endif cl_assert(git_repository_is_bare(inmemory)); /* verify repo isn't given an index upfront in future */ diff --git a/tests/libgit2/checkout/index.c b/tests/libgit2/checkout/index.c index 03d5d392b54..aa85e24a616 100644 --- a/tests/libgit2/checkout/index.c +++ b/tests/libgit2/checkout/index.c @@ -830,8 +830,11 @@ void test_checkout_index__adding_conflict_removes_stage_0(void) { git_index *new_index, *index; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__new(&new_index, GIT_OID_SHA1)); + index_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_index_new_ext(&new_index, &index_opts)); add_conflict(new_index, "new.txt"); cl_git_pass(git_checkout_index(g_repo, new_index, &opts)); diff --git a/tests/libgit2/clone/nonetwork.c b/tests/libgit2/clone/nonetwork.c index e784ec20f4e..dfde7f291eb 100644 --- a/tests/libgit2/clone/nonetwork.c +++ b/tests/libgit2/clone/nonetwork.c @@ -265,13 +265,17 @@ void test_clone_nonetwork__clone_tag_to_tree(void) git_tree *tree; git_reference *tag; git_tree_entry *tentry; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + const char *file_path = "some/deep/path.txt"; const char *file_content = "some content\n"; const char *tag_name = "refs/tags/tree-tag"; + index_opts.oid_type = GIT_OID_SHA1; + stage = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_repository_odb(&odb, stage)); - cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&index, &index_opts)); memset(&entry, 0, sizeof(git_index_entry)); entry.path = file_path; diff --git a/tests/libgit2/diff/diff_helpers.c b/tests/libgit2/diff/diff_helpers.c index 5daebffeb3c..6a76a92e7e8 100644 --- a/tests/libgit2/diff/diff_helpers.c +++ b/tests/libgit2/diff/diff_helpers.c @@ -314,15 +314,6 @@ void diff_assert_equal(git_diff *a, git_diff *b) } } -#ifdef GIT_EXPERIMENTAL_SHA256 -int diff_from_buffer( - git_diff **out, - const char *content, - size_t content_len) -{ - return git_diff_from_buffer(out, content, content_len, NULL); -} -#else int diff_from_buffer( git_diff **out, const char *content, @@ -330,4 +321,3 @@ int diff_from_buffer( { return git_diff_from_buffer(out, content, content_len); } -#endif diff --git a/tests/libgit2/diff/index.c b/tests/libgit2/diff/index.c index b7866750bb3..c6b7037e4c0 100644 --- a/tests/libgit2/diff/index.c +++ b/tests/libgit2/diff/index.c @@ -276,10 +276,13 @@ void test_diff_index__to_index(void) git_tree *old_tree; git_index *old_index; git_index *new_index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; git_diff *diff; diff_expects exp; - cl_git_pass(git_index__new(&old_index, GIT_OID_SHA1)); + index_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_index_new_ext(&old_index, &index_opts)); old_tree = resolve_commit_oid_to_tree(g_repo, a_commit); cl_git_pass(git_index_read_tree(old_index, old_tree)); diff --git a/tests/libgit2/index/cache.c b/tests/libgit2/index/cache.c index 77f19a50b29..1d0f8a3ebf2 100644 --- a/tests/libgit2/index/cache.c +++ b/tests/libgit2/index/cache.c @@ -24,7 +24,7 @@ void test_index_cache__write_extension_at_root(void) const char *tree_id_str = "45dd856fdd4d89b884c340ba0e047752d9b085d6"; const char *index_file = "index-tree"; - cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); + cl_git_pass(git_index_open_ext(&index, index_file, NULL)); cl_assert(index->tree == NULL); cl_git_pass(git_oid__fromstr(&id, tree_id_str, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); @@ -35,7 +35,7 @@ void test_index_cache__write_extension_at_root(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); + cl_git_pass(git_index_open_ext(&index, index_file, NULL)); cl_assert(index->tree); cl_assert_equal_i(git_index_entrycount(index), index->tree->entry_count); @@ -52,11 +52,12 @@ void test_index_cache__write_extension_invalidated_root(void) git_index *index; git_tree *tree; git_oid id; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; const char *tree_id_str = "45dd856fdd4d89b884c340ba0e047752d9b085d6"; const char *index_file = "index-tree-invalidated"; git_index_entry entry; - cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); + cl_git_pass(git_index_open_ext(&index, index_file, &index_opts)); cl_assert(index->tree == NULL); cl_git_pass(git_oid__fromstr(&id, tree_id_str, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); @@ -77,7 +78,9 @@ void test_index_cache__write_extension_invalidated_root(void) cl_git_pass(git_index_write(index)); git_index_free(index); - cl_git_pass(git_index__open(&index, index_file, GIT_OID_SHA1)); + index_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_index_open_ext(&index, index_file, &index_opts)); cl_assert(index->tree); cl_assert_equal_i(-1, index->tree->entry_count); @@ -96,7 +99,7 @@ void test_index_cache__read_tree_no_children(void) git_tree *tree; git_oid id; - cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&index)); cl_assert(index->tree == NULL); cl_git_pass(git_oid__fromstr(&id, "45dd856fdd4d89b884c340ba0e047752d9b085d6", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); diff --git a/tests/libgit2/index/inmemory.c b/tests/libgit2/index/inmemory.c index 39374af67bc..2b4ea994877 100644 --- a/tests/libgit2/index/inmemory.c +++ b/tests/libgit2/index/inmemory.c @@ -5,7 +5,7 @@ void test_index_inmemory__can_create_an_inmemory_index(void) { git_index *index; - cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&index)); cl_assert_equal_i(0, (int)git_index_entrycount(index)); git_index_free(index); @@ -15,7 +15,7 @@ void test_index_inmemory__cannot_add_bypath_to_an_inmemory_index(void) { git_index *index; - cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&index, NULL)); cl_assert_equal_i(GIT_ERROR, git_index_add_bypath(index, "test.txt")); diff --git a/tests/libgit2/index/racy.c b/tests/libgit2/index/racy.c index a1d6f9c6ec0..bbac7a6df3b 100644 --- a/tests/libgit2/index/racy.c +++ b/tests/libgit2/index/racy.c @@ -279,6 +279,7 @@ void test_index_racy__read_index_smudges(void) { git_index *index, *newindex; const git_index_entry *entry; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; /* if we are reading an index into our new index, ensure that any * racy entries in the index that we're reading are smudged so that @@ -287,7 +288,7 @@ void test_index_racy__read_index_smudges(void) setup_race(); cl_git_pass(git_repository_index(&index, g_repo)); - cl_git_pass(git_index__new(&newindex, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&newindex, &index_opts)); cl_git_pass(git_index_read_index(newindex, index)); cl_assert(entry = git_index_get_bypath(newindex, "A", 0)); @@ -305,7 +306,7 @@ void test_index_racy__read_index_clears_uptodate_bit(void) setup_uptodate_files(); cl_git_pass(git_repository_index(&index, g_repo)); - cl_git_pass(git_index__new(&newindex, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&newindex)); cl_git_pass(git_index_read_index(newindex, index)); /* ensure that files brought in from the other index are not uptodate */ diff --git a/tests/libgit2/index/read_index.c b/tests/libgit2/index/read_index.c index 9c80be299f1..caaf40f7967 100644 --- a/tests/libgit2/index/read_index.c +++ b/tests/libgit2/index/read_index.c @@ -33,8 +33,11 @@ void test_index_read_index__maintains_stat_cache(void) git_index_entry new_entry; const git_index_entry *e; git_tree *tree; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; size_t i; + index_opts.oid_type = GIT_OID_SHA1; + cl_assert_equal_i(4, git_index_entrycount(_index)); /* write-tree */ @@ -42,7 +45,7 @@ void test_index_read_index__maintains_stat_cache(void) /* read-tree, then read index */ git_tree_lookup(&tree, _repo, &index_id); - cl_git_pass(git_index__new(&new_index, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&new_index, &index_opts)); cl_git_pass(git_index_read_tree(new_index, tree)); git_tree_free(tree); @@ -81,7 +84,7 @@ static bool roundtrip_with_read_index(const char *tree_idstr) cl_git_pass(git_oid__fromstr(&tree_id, tree_idstr, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); - cl_git_pass(git_index__new(&tree_index, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&tree_index)); cl_git_pass(git_index_read_tree(tree_index, tree)); cl_git_pass(git_index_read_index(_index, tree_index)); cl_git_pass(git_index_write_tree(&new_tree_id, _index)); @@ -110,15 +113,18 @@ void test_index_read_index__read_and_writes(void) git_oid tree_id, new_tree_id; git_tree *tree; git_index *tree_index, *new_index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA1; cl_git_pass(git_oid__fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); - cl_git_pass(git_index__new(&tree_index, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&tree_index, &index_opts)); cl_git_pass(git_index_read_tree(tree_index, tree)); cl_git_pass(git_index_read_index(_index, tree_index)); cl_git_pass(git_index_write(_index)); - cl_git_pass(git_index__open(&new_index, git_index_path(_index), GIT_OID_SHA1)); + cl_git_pass(git_index_open_ext(&new_index, git_index_path(_index), &index_opts)); cl_git_pass(git_index_write_tree_to(&new_tree_id, new_index, _repo)); cl_assert_equal_oid(&tree_id, &new_tree_id); @@ -174,8 +180,8 @@ void test_index_read_index__handles_conflicts(void) cl_git_pass(git_oid__fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); - cl_git_pass(git_index__new(&index, GIT_OID_SHA1)); - cl_git_pass(git_index__new(&new_index, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&index, NULL)); + cl_git_pass(git_index_new_ext(&new_index, NULL)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_read_tree(new_index, tree)); diff --git a/tests/libgit2/index/tests.c b/tests/libgit2/index/tests.c index b48eb0fc170..fb064ea2172 100644 --- a/tests/libgit2/index/tests.c +++ b/tests/libgit2/index/tests.c @@ -81,7 +81,7 @@ void test_index_tests__empty_index(void) { git_index *index; - cl_git_pass(git_index__open(&index, "in-memory-index", GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, "in-memory-index")); cl_assert(index->on_disk == 0); cl_assert(git_index_entrycount(index) == 0); @@ -96,7 +96,7 @@ void test_index_tests__default_test_index(void) unsigned int i; git_index_entry **entries; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count); @@ -119,7 +119,7 @@ void test_index_tests__gitgit_index(void) { git_index *index; - cl_git_pass(git_index__open(&index, TEST_INDEX2_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX2_PATH)); cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count_2); @@ -134,7 +134,7 @@ void test_index_tests__find_in_existing(void) git_index *index; unsigned int i; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { size_t idx; @@ -151,7 +151,7 @@ void test_index_tests__find_in_empty(void) git_index *index; unsigned int i; - cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, "fake-index")); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path)); @@ -166,7 +166,7 @@ void test_index_tests__find_prefix(void) const git_index_entry *entry; size_t pos; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_git_pass(git_index_find_prefix(&pos, index, "src")); entry = git_index_get_byindex(index, pos); @@ -187,7 +187,7 @@ void test_index_tests__write(void) copy_file(TEST_INDEXBIG_PATH, "index_rewrite"); - cl_git_pass(git_index__open(&index, "index_rewrite", GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, "index_rewrite")); cl_assert(index->on_disk); cl_git_pass(git_index_write(index)); @@ -218,7 +218,7 @@ void test_index_tests__sort1(void) /* sort the entries in an empty index */ git_index *index; - cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, "fake-index")); /* FIXME: this test is slightly dumb */ cl_assert(git_vector_is_sorted(&index->entries)); @@ -702,8 +702,11 @@ void test_index_tests__write_tree_invalid_unowned_index(void) git_repository *repo; git_index_entry entry = {{0}}; git_oid tree_id; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + index_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_index_new_ext(&idx, &index_opts)); cl_git_pass(git_oid__fromstr(&entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318", GIT_OID_SHA1)); entry.path = "foo"; @@ -966,7 +969,7 @@ void test_index_tests__reload_from_disk(void) cl_git_pass(git_repository_index(&write_index, repo)); cl_assert_equal_i(false, write_index->on_disk); - cl_git_pass(git_index__open(&read_index, write_index->index_file_path, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&read_index, write_index->index_file_path)); cl_assert_equal_i(false, read_index->on_disk); /* Stage two new files against the write_index */ @@ -1004,7 +1007,7 @@ void test_index_tests__corrupted_extension(void) { git_index *index; - cl_git_fail_with(git_index__open(&index, TEST_INDEXBAD_PATH, GIT_OID_SHA1), GIT_ERROR); + cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR); } void test_index_tests__reload_while_ignoring_case(void) @@ -1012,7 +1015,7 @@ void test_index_tests__reload_while_ignoring_case(void) git_index *index; unsigned int caps; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_git_pass(git_vector_verify_sorted(&index->entries)); caps = git_index_caps(index); @@ -1037,7 +1040,7 @@ void test_index_tests__change_icase_on_instance(void) unsigned int caps; const git_index_entry *e; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_git_pass(git_vector_verify_sorted(&index->entries)); caps = git_index_caps(index); @@ -1093,7 +1096,7 @@ void test_index_tests__can_iterate(void) size_t i, iterator_idx = 0, found = 0; int ret; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_git_pass(git_index_iterator_new(&iterator, index)); cl_assert(git_vector_is_sorted(&iterator->snap)); @@ -1136,7 +1139,7 @@ void test_index_tests__can_modify_while_iterating(void) size_t expected = 0, seen = 0; int ret; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_git_pass(git_index_iterator_new(&iterator, index)); expected = git_index_entrycount(index); diff --git a/tests/libgit2/index/tests256.c b/tests/libgit2/index/tests256.c index 97246ce4d5a..c720796d8bb 100644 --- a/tests/libgit2/index/tests256.c +++ b/tests/libgit2/index/tests256.c @@ -86,8 +86,11 @@ void test_index_tests256__empty_index(void) { #ifdef GIT_EXPERIMENTAL_SHA256 git_index *index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__open(&index, "in-memory-index", GIT_OID_SHA256)); + index_opts.oid_type = GIT_OID_SHA256; + + cl_git_pass(git_index_open_ext(&index, "in-memory-index", &index_opts)); cl_assert(index->on_disk == 0); cl_assert(git_index_entrycount(index) == 0); @@ -103,8 +106,11 @@ void test_index_tests256__default_test_index(void) git_index *index; unsigned int i; git_index_entry **entries; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&index, TEST_INDEX_PATH, &index_opts)); cl_assert(index->on_disk); cl_assert_equal_sz(git_index_entrycount(index), index_entry_count); @@ -129,8 +135,11 @@ void test_index_tests256__find_in_existing(void) #ifdef GIT_EXPERIMENTAL_SHA256 git_index *index; unsigned int i; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + index_opts.oid_type = GIT_OID_SHA256; + + cl_git_pass(git_index_open_ext(&index, TEST_INDEX_PATH, &index_opts)); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { size_t idx; @@ -148,8 +157,11 @@ void test_index_tests256__find_in_empty(void) #ifdef GIT_EXPERIMENTAL_SHA256 git_index *index; unsigned int i; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&index, "fake-index", &index_opts)); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path)); @@ -165,8 +177,11 @@ void test_index_tests256__find_prefix(void) git_index *index; const git_index_entry *entry; size_t pos; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + index_opts.oid_type = GIT_OID_SHA256; + + cl_git_pass(git_index_open_ext(&index, TEST_INDEX_PATH, &index_opts)); cl_git_pass(git_index_find_prefix(&pos, index, "Documentation")); entry = git_index_get_byindex(index, pos); @@ -186,10 +201,13 @@ void test_index_tests256__write(void) { #ifdef GIT_EXPERIMENTAL_SHA256 git_index *index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; copy_file(TEST_INDEX_PATH, "index_rewrite"); - cl_git_pass(git_index__open(&index, "index_rewrite", GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&index, "index_rewrite", &index_opts)); cl_assert(index->on_disk); cl_git_pass(git_index_write(index)); @@ -206,8 +224,11 @@ void test_index_tests256__sort1(void) #ifdef GIT_EXPERIMENTAL_SHA256 /* sort the entries in an empty index */ git_index *index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_index__open(&index, "fake-index", GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&index, "fake-index", &index_opts)); /* FIXME: this test is slightly dumb */ cl_assert(git_vector_is_sorted(&index->entries)); @@ -675,8 +696,11 @@ void test_index_tests256__write_tree_invalid_unowned_index(void) git_repository *repo; git_index_entry entry = {{0}}; git_oid tree_id; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__new(&idx, GIT_OID_SHA256)); + index_opts.oid_type = GIT_OID_SHA256; + + cl_git_pass(git_index_new_ext(&idx, &index_opts)); /* TODO: this one is failing */ cl_git_pass(git_oid__fromstr(&entry.id, "a8c2e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); @@ -947,6 +971,9 @@ void test_index_tests256__reload_from_disk(void) git_repository *repo; git_index *read_index; git_index *write_index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; cl_set_cleanup(&cleanup_myrepo, NULL); @@ -958,7 +985,7 @@ void test_index_tests256__reload_from_disk(void) cl_git_pass(git_repository_index(&write_index, repo)); cl_assert_equal_i(false, write_index->on_disk); - cl_git_pass(git_index__open(&read_index, write_index->index_file_path, GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&read_index, write_index->index_file_path, &index_opts)); cl_assert_equal_i(false, read_index->on_disk); /* Stage two new files against the write_index */ @@ -998,8 +1025,11 @@ void test_index_tests256__reload_while_ignoring_case(void) #ifdef GIT_EXPERIMENTAL_SHA256 git_index *index; unsigned int caps; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&index, TEST_INDEX_PATH, &index_opts)); cl_git_pass(git_vector_verify_sorted(&index->entries)); caps = git_index_caps(index); @@ -1025,8 +1055,11 @@ void test_index_tests256__change_icase_on_instance(void) git_index *index; unsigned int caps; const git_index_entry *e; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + index_opts.oid_type = GIT_OID_SHA256; + + cl_git_pass(git_index_open_ext(&index, TEST_INDEX_PATH, &index_opts)); cl_git_pass(git_vector_verify_sorted(&index->entries)); caps = git_index_caps(index); @@ -1085,8 +1118,11 @@ void test_index_tests256__can_iterate(void) const git_index_entry *entry; size_t i, iterator_idx = 0, found = 0; int ret; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&index, TEST_INDEX_PATH, &index_opts)); cl_git_pass(git_index_iterator_new(&iterator, index)); cl_assert(git_vector_is_sorted(&iterator->snap)); @@ -1130,8 +1166,11 @@ void test_index_tests256__can_modify_while_iterating(void) git_index_entry new_entry = {{0}}; size_t expected = 0, seen = 0; int ret; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; + + index_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_index__open(&index, TEST_INDEX_PATH, GIT_OID_SHA256)); + cl_git_pass(git_index_open_ext(&index, TEST_INDEX_PATH, &index_opts)); cl_git_pass(git_index_iterator_new(&iterator, index)); expected = git_index_entrycount(index); diff --git a/tests/libgit2/network/remote/local.c b/tests/libgit2/network/remote/local.c index 9f3c8b61179..88bf2da785e 100644 --- a/tests/libgit2/network/remote/local.c +++ b/tests/libgit2/network/remote/local.c @@ -2,6 +2,7 @@ #include "path.h" #include "posix.h" #include "git2/sys/repository.h" +#include "repository.h" static git_repository *repo; static git_str file_path_buf = GIT_STR_INIT; @@ -470,18 +471,11 @@ void test_network_remote_local__anonymous_remote_inmemory_repo(void) { git_repository *inmemory; git_remote *remote; - -#ifdef GIT_EXPERIMENTAL_SHA256 git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; -#endif git_str_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git"))); -#ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_repository_new(&inmemory, &repo_opts)); -#else - cl_git_pass(git_repository_new(&inmemory)); -#endif + cl_git_pass(git_repository_new_ext(&inmemory, &repo_opts)); cl_git_pass(git_remote_create_anonymous(&remote, inmemory, git_str_cstr(&file_path_buf))); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); cl_assert(git_remote_connected(remote)); diff --git a/tests/libgit2/object/raw/write.c b/tests/libgit2/object/raw/write.c index 346053df59a..b95deffdbfe 100644 --- a/tests/libgit2/object/raw/write.c +++ b/tests/libgit2/object/raw/write.c @@ -66,7 +66,7 @@ void test_body(object_data *d, git_rawobj *o) git_rawobj tmp; make_odb_dir(); - cl_git_pass(git_odb__open(&db, odb_dir, NULL)); + cl_git_pass(git_odb_open_ext(&db, odb_dir, NULL)); cl_git_pass(git_oid__fromstr(&id1, d->id, GIT_OID_SHA1)); streaming_write(&id2, db, o); diff --git a/tests/libgit2/object/tree/update.c b/tests/libgit2/object/tree/update.c index 1e82bdcd621..13373b6c4f7 100644 --- a/tests/libgit2/object/tree/update.c +++ b/tests/libgit2/object/tree/update.c @@ -29,7 +29,7 @@ void test_object_tree_update__remove_blob(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&idx)); cl_git_pass(git_index_read_tree(idx, base_tree)); cl_git_pass(git_index_remove(idx, path, 0)); cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo)); @@ -58,7 +58,7 @@ void test_object_tree_update__remove_blob_deeper(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&idx)); cl_git_pass(git_index_read_tree(idx, base_tree)); cl_git_pass(git_index_remove(idx, path, 0)); cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo)); @@ -89,7 +89,7 @@ void test_object_tree_update__remove_all_entries(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&idx)); cl_git_pass(git_index_read_tree(idx, base_tree)); cl_git_pass(git_index_remove(idx, path1, 0)); cl_git_pass(git_index_remove(idx, path2, 0)); @@ -120,7 +120,7 @@ void test_object_tree_update__replace_blob(void) cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&idx)); cl_git_pass(git_index_read_tree(idx, base_tree)); entry.path = path; @@ -172,7 +172,7 @@ void test_object_tree_update__add_blobs(void) int j; /* Create it with an index */ - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&idx)); base_tree = NULL; if (i == 1) { @@ -229,7 +229,7 @@ void test_object_tree_update__add_blobs_unsorted(void) int j; /* Create it with an index */ - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new(&idx)); base_tree = NULL; if (i == 1) { diff --git a/tests/libgit2/odb/backend/loose.c b/tests/libgit2/odb/backend/loose.c index f5a0b4f5caf..4e17bb96fe8 100644 --- a/tests/libgit2/odb/backend/loose.c +++ b/tests/libgit2/odb/backend/loose.c @@ -19,7 +19,7 @@ void test_odb_backend_loose__initialize(void) cl_git_pass(git_odb_backend_loose(&backend, "testrepo.git/objects", 0, 0, 0, 0)); #endif - cl_git_pass(git_odb__new(&_odb, NULL)); + cl_git_pass(git_odb_new(&_odb)); cl_git_pass(git_odb_add_backend(_odb, backend, 10)); cl_git_pass(git_repository_wrap_odb(&_repo, _odb)); } diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c index 462a1d333a6..036b13a5170 100644 --- a/tests/libgit2/odb/backend/mempack.c +++ b/tests/libgit2/odb/backend/mempack.c @@ -13,7 +13,7 @@ static git_odb_backend *_backend; void test_odb_backend_mempack__initialize(void) { cl_git_pass(git_mempack_new(&_backend)); - cl_git_pass(git_odb__new(&_odb, NULL)); + cl_git_pass(git_odb_new(&_odb)); cl_git_pass(git_odb_add_backend(_odb, _backend, 10)); cl_git_pass(git_repository_wrap_odb(&_repo, _odb)); } diff --git a/tests/libgit2/odb/backend/nobackend.c b/tests/libgit2/odb/backend/nobackend.c index e8af9a6d6fa..b33f79abb90 100644 --- a/tests/libgit2/odb/backend/nobackend.c +++ b/tests/libgit2/odb/backend/nobackend.c @@ -11,17 +11,15 @@ void test_odb_backend_nobackend__initialize(void) git_odb *odb; git_refdb *refdb; -#ifdef GIT_EXPERIMENTAL_SHA256 git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; + git_odb_options odb_opts = GIT_ODB_OPTIONS_INIT; repo_opts.oid_type = GIT_OID_SHA1; + odb_opts.oid_type = GIT_OID_SHA1; - cl_git_pass(git_repository_new(&_repo, &repo_opts)); -#else - cl_git_pass(git_repository_new(&_repo)); -#endif + cl_git_pass(git_repository_new_ext(&_repo, &repo_opts)); cl_git_pass(git_config_new(&config)); - cl_git_pass(git_odb__new(&odb, NULL)); + cl_git_pass(git_odb_new_ext(&odb, &odb_opts)); cl_git_pass(git_refdb_new(&refdb, _repo)); git_repository_set_config(_repo, config); diff --git a/tests/libgit2/odb/foreach.c b/tests/libgit2/odb/foreach.c index 56b3e882ce0..091bd783e5b 100644 --- a/tests/libgit2/odb/foreach.c +++ b/tests/libgit2/odb/foreach.c @@ -50,8 +50,11 @@ void test_odb_foreach__one_pack(void) { git_odb_backend *backend = NULL; int nobj = 0; + git_odb_options odb_opts = GIT_ODB_OPTIONS_INIT; - cl_git_pass(git_odb__new(&_odb, NULL)); + odb_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_odb_new_ext(&_odb, &odb_opts)); #ifdef GIT_EXPERIMENTAL_SHA256 cl_git_pass(git_odb_backend_one_pack(&backend, diff --git a/tests/libgit2/odb/loose.c b/tests/libgit2/odb/loose.c index 0409dfb2812..4ad47772c23 100644 --- a/tests/libgit2/odb/loose.c +++ b/tests/libgit2/odb/loose.c @@ -44,7 +44,7 @@ static void test_read_object(object_data *data) write_object_files(data); - cl_git_pass(git_odb__open(&odb, "test-objects", &opts)); + cl_git_pass(git_odb_open_ext(&odb, "test-objects", &opts)); cl_git_pass(git_oid__fromstr(&id, data->id, data->id_type)); cl_git_pass(git_odb_read(&obj, odb, &id)); @@ -70,7 +70,7 @@ static void test_read_header(object_data *data) write_object_files(data); - cl_git_pass(git_odb__open(&odb, "test-objects", &opts)); + cl_git_pass(git_odb_open_ext(&odb, "test-objects", &opts)); cl_git_pass(git_oid__fromstr(&id, data->id, data->id_type)); cl_git_pass(git_odb_read_header(&len, &type, odb, &id)); @@ -95,7 +95,7 @@ static void test_readstream_object(object_data *data, size_t blocksize) write_object_files(data); - cl_git_pass(git_odb__open(&odb, "test-objects", &opts)); + cl_git_pass(git_odb_open_ext(&odb, "test-objects", &opts)); cl_git_pass(git_oid__fromstr(&id, data->id, data->id_type)); cl_git_pass(git_odb_open_rstream(&stream, &tmp.len, &tmp.type, odb, &id)); @@ -139,7 +139,7 @@ void test_odb_loose__exists_sha1(void) git_odb *odb; write_object_files(&one); - cl_git_pass(git_odb__open(&odb, "test-objects", NULL)); + cl_git_pass(git_odb_open(&odb, "test-objects")); cl_git_pass(git_oid__fromstr(&id, one.id, GIT_OID_SHA1)); cl_assert(git_odb_exists(odb, &id)); @@ -170,7 +170,7 @@ void test_odb_loose__exists_sha256(void) odb_opts.oid_type = GIT_OID_SHA256; write_object_files(&one_sha256); - cl_git_pass(git_odb__open(&odb, "test-objects", &odb_opts)); + cl_git_pass(git_odb_open_ext(&odb, "test-objects", &odb_opts)); cl_git_pass(git_oid__fromstr(&id, one_sha256.id, GIT_OID_SHA256)); cl_assert(git_odb_exists(odb, &id)); @@ -304,7 +304,7 @@ static void test_write_object_permission( opts.dir_mode = dir_mode; opts.file_mode = file_mode; - cl_git_pass(git_odb__new(&odb, NULL)); + cl_git_pass(git_odb_new(&odb)); cl_git_pass(git_odb__backend_loose(&backend, "test-objects", &opts)); cl_git_pass(git_odb_add_backend(odb, backend, 1)); cl_git_pass(git_odb_write(&oid, odb, "Test data\n", 10, GIT_OBJECT_BLOB)); @@ -338,16 +338,17 @@ static void write_object_to_loose_odb(int fsync) git_odb *odb; git_odb_backend *backend; git_oid oid; - git_odb_backend_loose_options opts = GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT; + git_odb_options odb_opts = GIT_ODB_OPTIONS_INIT; + git_odb_backend_loose_options backend_opts = GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT; if (fsync) - opts.flags |= GIT_ODB_BACKEND_LOOSE_FSYNC; + backend_opts.flags |= GIT_ODB_BACKEND_LOOSE_FSYNC; - opts.dir_mode = 0777; - opts.file_mode = 0666; + backend_opts.dir_mode = 0777; + backend_opts.file_mode = 0666; - cl_git_pass(git_odb__new(&odb, NULL)); - cl_git_pass(git_odb__backend_loose(&backend, "test-objects", &opts)); + cl_git_pass(git_odb_new_ext(&odb, &odb_opts)); + cl_git_pass(git_odb__backend_loose(&backend, "test-objects", &backend_opts)); cl_git_pass(git_odb_add_backend(odb, backend, 1)); cl_git_pass(git_odb_write(&oid, odb, "Test data\n", 10, GIT_OBJECT_BLOB)); git_odb_free(odb); diff --git a/tests/libgit2/odb/mixed.c b/tests/libgit2/odb/mixed.c index 19e6dcebf1e..2cba8cb1479 100644 --- a/tests/libgit2/odb/mixed.c +++ b/tests/libgit2/odb/mixed.c @@ -5,7 +5,7 @@ static git_odb *_odb; void test_odb_mixed__initialize(void) { - cl_git_pass(git_odb__open(&_odb, cl_fixture("duplicate.git/objects"), NULL)); + cl_git_pass(git_odb_open_ext(&_odb, cl_fixture("duplicate.git/objects"), NULL)); } void test_odb_mixed__cleanup(void) diff --git a/tests/libgit2/odb/open.c b/tests/libgit2/odb/open.c index 395406d0f3c..05e65d2c0eb 100644 --- a/tests/libgit2/odb/open.c +++ b/tests/libgit2/odb/open.c @@ -1,4 +1,5 @@ #include "clar_libgit2.h" +#include "odb.h" void test_odb_open__initialize(void) { @@ -14,15 +15,14 @@ void test_odb_open__exists(void) { git_odb *odb; git_oid one, two; - -#ifdef GIT_EXPERIMENTAL_SHA256 git_odb_options opts = GIT_ODB_OPTIONS_INIT; - cl_git_pass(git_odb_open(&odb, "testrepo.git/objects", &opts)); + cl_git_pass(git_odb_open_ext(&odb, "testrepo.git/objects", &opts)); + +#ifdef GIT_EXPERIMENTAL_SHA256 cl_git_pass(git_oid_fromstr(&one, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); cl_git_pass(git_oid_fromstr(&two, "00112233445566778899aabbccddeeff00112233", GIT_OID_SHA1)); #else - cl_git_pass(git_odb_open(&odb, "testrepo.git/objects")); cl_git_pass(git_oid_fromstr(&one, "1385f264afb75a56a5bec74243be9b367ba4ca08")); cl_git_pass(git_oid_fromstr(&two, "00112233445566778899aabbccddeeff00112233")); #endif diff --git a/tests/libgit2/odb/packed.c b/tests/libgit2/odb/packed.c index b41041fc112..6fbe0a46dab 100644 --- a/tests/libgit2/odb/packed.c +++ b/tests/libgit2/odb/packed.c @@ -6,7 +6,7 @@ static git_odb *_odb; void test_odb_packed__initialize(void) { - cl_git_pass(git_odb__open(&_odb, cl_fixture("testrepo.git/objects"), NULL)); + cl_git_pass(git_odb_open_ext(&_odb, cl_fixture("testrepo.git/objects"), NULL)); } void test_odb_packed__cleanup(void) diff --git a/tests/libgit2/odb/packed256.c b/tests/libgit2/odb/packed256.c index 65220fd4c8b..3b04e88b558 100644 --- a/tests/libgit2/odb/packed256.c +++ b/tests/libgit2/odb/packed256.c @@ -13,7 +13,7 @@ void test_odb_packed256__initialize(void) opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_odb__open( + cl_git_pass(git_odb_open_ext( &_odb, cl_fixture("testrepo_256.git/objects"), &opts)); diff --git a/tests/libgit2/odb/packedone.c b/tests/libgit2/odb/packedone.c index 8637001ffa7..4dea474f95c 100644 --- a/tests/libgit2/odb/packedone.c +++ b/tests/libgit2/odb/packedone.c @@ -10,7 +10,8 @@ void test_odb_packedone__initialize(void) { git_odb_backend *backend = NULL; - cl_git_pass(git_odb__new(&_odb, NULL)); + cl_git_pass(git_odb_new_ext(&_odb, NULL)); + #ifdef GIT_EXPERIMENTAL_SHA256 cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx"), diff --git a/tests/libgit2/odb/packedone256.c b/tests/libgit2/odb/packedone256.c index fdeac42055f..6fc6a80814a 100644 --- a/tests/libgit2/odb/packedone256.c +++ b/tests/libgit2/odb/packedone256.c @@ -18,7 +18,7 @@ void test_odb_packedone256__initialize(void) odb_opts.oid_type = GIT_OID_SHA256; backend_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_odb__new(&_odb, &odb_opts)); + cl_git_pass(git_odb_new_ext(&_odb, &odb_opts)); cl_git_pass(git_odb_backend_one_pack( &backend, cl_fixture("testrepo_256.git/objects/pack/pack-e2f07f30db7e480ea84a0e64ee791b9b270067124b2609019b74f33f256f33fa.idx"), diff --git a/tests/libgit2/odb/sorting.c b/tests/libgit2/odb/sorting.c index 3fe52e852cd..95d471db5d4 100644 --- a/tests/libgit2/odb/sorting.c +++ b/tests/libgit2/odb/sorting.c @@ -42,7 +42,7 @@ static git_odb *_odb; void test_odb_sorting__initialize(void) { - cl_git_pass(git_odb__new(&_odb, NULL)); + cl_git_pass(git_odb_new(&_odb)); } void test_odb_sorting__cleanup(void) @@ -94,7 +94,7 @@ void test_odb_sorting__override_default_backend_priority(void) ); git_odb__backend_loose(&loose, "./testrepo.git/objects", NULL); - cl_git_pass(git_odb__open(&new_odb, cl_fixture("testrepo.git/objects"), NULL)); + cl_git_pass(git_odb_open(&new_odb, cl_fixture("testrepo.git/objects"))); cl_assert_equal_sz(2, git_odb_num_backends(new_odb)); cl_git_pass(git_odb_get_backend(&backend, new_odb, 0)); diff --git a/tests/libgit2/refs/iterator.c b/tests/libgit2/refs/iterator.c index a46db629085..d79d968a588 100644 --- a/tests/libgit2/refs/iterator.c +++ b/tests/libgit2/refs/iterator.c @@ -128,7 +128,7 @@ void test_refs_iterator__empty(void) git_reference *ref; git_repository *empty; - cl_git_pass(git_odb__new(&odb, NULL)); + cl_git_pass(git_odb_new(&odb)); cl_git_pass(git_repository_wrap_odb(&empty, odb)); cl_git_pass(git_reference_iterator_new(&iter, empty)); diff --git a/tests/libgit2/repo/new.c b/tests/libgit2/repo/new.c index 5136e60b09d..92a5a8cfa50 100644 --- a/tests/libgit2/repo/new.c +++ b/tests/libgit2/repo/new.c @@ -1,19 +1,15 @@ #include "clar_libgit2.h" #include "git2/sys/repository.h" +#include "repository.h" void test_repo_new__has_nothing(void) { git_repository *repo; - -#ifdef GIT_EXPERIMENTAL_SHA256 git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; repo_opts.oid_type = GIT_OID_SHA1; - cl_git_pass(git_repository_new(&repo, &repo_opts)); -#else - cl_git_pass(git_repository_new(&repo)); -#endif + cl_git_pass(git_repository_new_ext(&repo, &repo_opts)); cl_assert_equal_b(true, git_repository_is_bare(repo)); cl_assert_equal_p(NULL, git_repository_path(repo)); cl_assert_equal_p(NULL, git_repository_workdir(repo)); @@ -24,15 +20,11 @@ void test_repo_new__is_bare_until_workdir_set(void) { git_repository *repo; -#ifdef GIT_EXPERIMENTAL_SHA256 git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; repo_opts.oid_type = GIT_OID_SHA1; - cl_git_pass(git_repository_new(&repo, &repo_opts)); -#else - cl_git_pass(git_repository_new(&repo)); -#endif + cl_git_pass(git_repository_new_ext(&repo, &repo_opts)); cl_assert_equal_b(true, git_repository_is_bare(repo)); cl_git_pass(git_repository_set_workdir(repo, clar_sandbox_path(), 0)); @@ -44,16 +36,11 @@ void test_repo_new__is_bare_until_workdir_set(void) void test_repo_new__sha1(void) { git_repository *repo; - -#ifdef GIT_EXPERIMENTAL_SHA256 git_repository_new_options repo_opts = GIT_REPOSITORY_NEW_OPTIONS_INIT; repo_opts.oid_type = GIT_OID_SHA1; - cl_git_pass(git_repository_new(&repo, &repo_opts)); -#else - cl_git_pass(git_repository_new(&repo)); -#endif + cl_git_pass(git_repository_new_ext(&repo, &repo_opts)); cl_assert_equal_i(GIT_OID_SHA1, git_repository_oid_type(repo)); git_repository_free(repo); @@ -69,7 +56,7 @@ void test_repo_new__sha256(void) repo_opts.oid_type = GIT_OID_SHA256; - cl_git_pass(git_repository_new(&repo, &repo_opts)); + cl_git_pass(git_repository_new_ext(&repo, &repo_opts)); cl_assert_equal_i(GIT_OID_SHA256, git_repository_oid_type(repo)); git_repository_free(repo); diff --git a/tests/libgit2/repo/setters.c b/tests/libgit2/repo/setters.c index 1ad38bb8b80..8e2946d4d58 100644 --- a/tests/libgit2/repo/setters.c +++ b/tests/libgit2/repo/setters.c @@ -70,8 +70,11 @@ void test_repo_setters__setting_a_workdir_creates_a_gitlink(void) void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_one_properly_honors_the_refcount(void) { git_index *new_index; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; - cl_git_pass(git_index__open(&new_index, "./my-index", GIT_OID_SHA1)); + index_opts.oid_type = GIT_OID_SHA1; + + cl_git_pass(git_index_open_ext(&new_index, "./my-index", &index_opts)); cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_repository_set_index(repo, new_index); @@ -92,7 +95,7 @@ void test_repo_setters__setting_a_new_odb_on_a_repo_which_already_loaded_one_pro { git_odb *new_odb; - cl_git_pass(git_odb__open(&new_odb, "./testrepo.git/objects", NULL)); + cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects")); cl_assert(((git_refcount *)new_odb)->refcount.val == 1); git_repository_set_odb(repo, new_odb); diff --git a/tests/libgit2/reset/hard.c b/tests/libgit2/reset/hard.c index 06a8a049afc..fa7c0b3e633 100644 --- a/tests/libgit2/reset/hard.c +++ b/tests/libgit2/reset/hard.c @@ -247,13 +247,14 @@ void test_reset_hard__switch_file_to_dir(void) git_signature *sig; git_oid src_tree_id, tgt_tree_id; git_oid src_id, tgt_id; + git_index_options index_opts = GIT_INDEX_OPTIONS_INIT; cl_git_pass(git_repository_odb(&odb, repo)); cl_git_pass(git_odb_write(&entry.id, odb, "", 0, GIT_OBJECT_BLOB)); git_odb_free(odb); entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&idx, &index_opts)); cl_git_pass(git_signature_now(&sig, "foo", "bar")); /* Create the old tree */ diff --git a/tests/libgit2/status/worktree_init.c b/tests/libgit2/status/worktree_init.c index db6e71f1234..532b4bba084 100644 --- a/tests/libgit2/status/worktree_init.c +++ b/tests/libgit2/status/worktree_init.c @@ -66,7 +66,7 @@ void test_status_worktree_init__status_file_without_index_or_workdir(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_set_workdir(repo, "wd", false)); - cl_git_pass(git_index__open(&index, "empty-index", GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, "empty-index")); cl_assert_equal_i(0, (int)git_index_entrycount(index)); git_repository_set_index(repo, index); @@ -107,7 +107,7 @@ void test_status_worktree_init__status_file_with_clean_index_and_empty_workdir(v cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_set_workdir(repo, "wd", false)); - cl_git_pass(git_index__open(&index, "my-index", GIT_OID_SHA1)); + cl_git_pass(git_index_open(&index, "my-index")); fill_index_wth_head_entries(repo, index); git_repository_set_index(repo, index); diff --git a/tests/libgit2/submodule/lookup.c b/tests/libgit2/submodule/lookup.c index 14a624badef..2c5c6081f41 100644 --- a/tests/libgit2/submodule/lookup.c +++ b/tests/libgit2/submodule/lookup.c @@ -211,7 +211,7 @@ void test_submodule_lookup__lookup_even_with_missing_index(void) git_index *idx; /* give the repo an empty index */ - cl_git_pass(git_index__new(&idx, GIT_OID_SHA1)); + cl_git_pass(git_index_new_ext(&idx, NULL)); git_repository_set_index(g_repo, idx); git_index_free(idx); From c26d8a8b54fcb776f876f5ead2e69739271d4a66 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 1 Jan 2025 15:47:43 +0000 Subject: [PATCH 781/816] sha256: further API simplifications for OID parsing Introduce `git_oid_from_string`, `git_oid_from_prefix`, and `git_oid_from_raw`, all of which take a `git_oid_t` that indicates what type of OID should be parsed (SHA1 or SHA256). This allows users to continue to use `git_oid_fromstr` without any code changes, while remaining in a SHA1 world. Note that these are not perfect analogs to the `fromstr` APIs. * `git_oid_from_string` now takes a NUL terminated string, instead of allowing for non-NUL terminated strings. Adding a NUL check feels like an important safety consideration for C strings. * `git_oid_from_prefix` should be used for an OID substring and length. Previous usages of `git_oid_fromstr` with non-NUL terminated strings should move to `git_oid_from_prefix` with the hexsize for the given OID type. --- examples/general.c | 16 +-- examples/rev-list.c | 2 +- include/git2/oid.h | 62 ++++++++-- src/libgit2/commit_graph.c | 4 +- src/libgit2/fetch.c | 2 +- src/libgit2/fetchhead.c | 2 +- src/libgit2/index.c | 6 +- src/libgit2/indexer.c | 2 +- src/libgit2/merge.c | 2 +- src/libgit2/midx.c | 4 +- src/libgit2/notes.c | 2 +- src/libgit2/object.c | 2 +- src/libgit2/odb_loose.c | 5 +- src/libgit2/oid.c | 86 +++++--------- src/libgit2/oid.h | 16 +-- src/libgit2/pack.c | 10 +- src/libgit2/parse.c | 2 +- src/libgit2/patch_parse.c | 2 +- src/libgit2/rebase.c | 6 +- src/libgit2/refdb_fs.c | 10 +- src/libgit2/remote.c | 2 +- src/libgit2/revparse.c | 2 +- src/libgit2/transports/smart_pkt.c | 8 +- src/libgit2/tree-cache.c | 2 +- src/libgit2/tree.c | 2 +- tests/clar/clar_libgit2.h | 3 +- tests/libgit2/apply/apply_helpers.c | 2 +- tests/libgit2/apply/both.c | 12 +- tests/libgit2/apply/callbacks.c | 2 +- tests/libgit2/apply/check.c | 6 +- tests/libgit2/apply/index.c | 10 +- tests/libgit2/apply/tree.c | 6 +- tests/libgit2/apply/workdir.c | 8 +- tests/libgit2/checkout/binaryunicode.c | 4 +- tests/libgit2/checkout/conflict.c | 4 +- tests/libgit2/checkout/index.c | 6 +- tests/libgit2/checkout/tree.c | 36 +++--- tests/libgit2/checkout/typechange.c | 2 +- tests/libgit2/cherrypick/bare.c | 12 +- tests/libgit2/cherrypick/workdir.c | 36 +++--- tests/libgit2/commit/commit.c | 12 +- tests/libgit2/commit/parent.c | 2 +- tests/libgit2/commit/parse.c | 4 +- tests/libgit2/commit/write.c | 50 ++++---- tests/libgit2/core/oid.c | 12 +- tests/libgit2/core/oidarray.c | 8 +- tests/libgit2/core/pool.c | 2 +- tests/libgit2/diff/binary.c | 10 +- tests/libgit2/diff/blob.c | 36 +++--- tests/libgit2/diff/diff_helpers.c | 2 +- tests/libgit2/diff/format_email.c | 8 +- tests/libgit2/diff/index.c | 8 +- tests/libgit2/diff/patchid.c | 2 +- tests/libgit2/diff/rename.c | 2 +- tests/libgit2/diff/stats.c | 2 +- tests/libgit2/diff/workdir.c | 10 +- tests/libgit2/email/create.c | 4 +- tests/libgit2/fetch/local.c | 4 +- tests/libgit2/fetchhead/nonetwork.c | 22 ++-- tests/libgit2/filter/bare.c | 4 +- tests/libgit2/grafts/basic.c | 10 +- tests/libgit2/grafts/parse.c | 4 +- tests/libgit2/grafts/shallow.c | 4 +- tests/libgit2/graph/ahead_behind.c | 6 +- tests/libgit2/graph/commitgraph.c | 20 ++-- tests/libgit2/graph/descendant_of.c | 4 +- tests/libgit2/graph/reachable_from_any.c | 2 +- tests/libgit2/index/add.c | 6 +- tests/libgit2/index/bypath.c | 6 +- tests/libgit2/index/cache.c | 16 +-- tests/libgit2/index/conflicts.c | 74 ++++++------ tests/libgit2/index/crlf.c | 16 +-- tests/libgit2/index/names.c | 6 +- tests/libgit2/index/read_index.c | 14 +-- tests/libgit2/index/rename.c | 2 +- tests/libgit2/index/reuc.c | 70 +++++------ tests/libgit2/index/tests.c | 16 +-- tests/libgit2/index/tests256.c | 14 +-- tests/libgit2/iterator/index.c | 10 +- tests/libgit2/iterator/tree.c | 6 +- tests/libgit2/iterator/workdir.c | 2 +- tests/libgit2/merge/driver.c | 6 +- tests/libgit2/merge/files.c | 6 +- tests/libgit2/merge/merge_helpers.c | 10 +- tests/libgit2/merge/trees/renames.c | 2 +- tests/libgit2/merge/trees/treediff.c | 6 +- tests/libgit2/merge/trees/trivial.c | 4 +- tests/libgit2/merge/workdir/dirty.c | 2 +- tests/libgit2/merge/workdir/setup.c | 110 +++++++++--------- tests/libgit2/merge/workdir/simple.c | 18 +-- tests/libgit2/merge/workdir/trivial.c | 4 +- tests/libgit2/network/remote/rename.c | 2 +- tests/libgit2/notes/notes.c | 48 ++++---- tests/libgit2/notes/notesref.c | 2 +- tests/libgit2/object/blob/fromstream.c | 4 +- tests/libgit2/object/cache.c | 14 +-- .../libgit2/object/commit/commitstagedfile.c | 6 +- tests/libgit2/object/commit/parse.c | 2 +- tests/libgit2/object/lookup.c | 12 +- tests/libgit2/object/lookup256.c | 12 +- tests/libgit2/object/peel.c | 6 +- tests/libgit2/object/raw/chars.c | 6 +- tests/libgit2/object/raw/compare.c | 20 ++-- tests/libgit2/object/raw/convert.c | 6 +- tests/libgit2/object/raw/fromstr.c | 10 +- tests/libgit2/object/raw/hash.c | 32 ++--- tests/libgit2/object/raw/short.c | 2 +- tests/libgit2/object/raw/write.c | 2 +- tests/libgit2/object/shortid.c | 10 +- tests/libgit2/object/tag/parse.c | 2 +- tests/libgit2/object/tag/peel.c | 2 +- tests/libgit2/object/tag/read.c | 16 +-- tests/libgit2/object/tag/write.c | 18 +-- tests/libgit2/object/tree/attributes.c | 10 +- tests/libgit2/object/tree/duplicateentries.c | 16 +-- tests/libgit2/object/tree/frompath.c | 2 +- tests/libgit2/object/tree/parse.c | 2 +- tests/libgit2/object/tree/read.c | 4 +- tests/libgit2/object/tree/update.c | 30 ++--- tests/libgit2/object/tree/walk.c | 6 +- tests/libgit2/object/tree/write.c | 36 +++--- tests/libgit2/odb/alternates.c | 4 +- tests/libgit2/odb/backend/backend_helpers.c | 6 +- tests/libgit2/odb/backend/loose.c | 8 +- tests/libgit2/odb/backend/mempack.c | 4 +- tests/libgit2/odb/backend/multiple.c | 2 +- tests/libgit2/odb/backend/nonrefreshing.c | 4 +- tests/libgit2/odb/backend/refreshing.c | 4 +- tests/libgit2/odb/backend/simple.c | 26 ++--- tests/libgit2/odb/emptyobjects.c | 6 +- tests/libgit2/odb/freshen.c | 12 +- tests/libgit2/odb/largefiles.c | 4 +- tests/libgit2/odb/loose.c | 22 ++-- tests/libgit2/odb/mixed.c | 26 ++--- tests/libgit2/odb/open.c | 4 +- tests/libgit2/odb/packed.c | 6 +- tests/libgit2/odb/packed256.c | 6 +- tests/libgit2/odb/packedone.c | 4 +- tests/libgit2/odb/packedone256.c | 4 +- tests/libgit2/online/clone.c | 2 +- tests/libgit2/online/fetch.c | 4 +- tests/libgit2/online/push.c | 28 ++--- tests/libgit2/online/shallow.c | 6 +- tests/libgit2/pack/indexer.c | 4 +- tests/libgit2/pack/midx.c | 4 +- tests/libgit2/pack/sharing.c | 2 +- tests/libgit2/perf/helper__perf__do_merge.c | 4 +- tests/libgit2/rebase/abort.c | 12 +- tests/libgit2/rebase/inmemory.c | 10 +- tests/libgit2/rebase/iterator.c | 20 ++-- tests/libgit2/rebase/merge.c | 30 ++--- tests/libgit2/rebase/setup.c | 30 ++--- tests/libgit2/rebase/sign.c | 10 +- tests/libgit2/refs/basic.c | 2 +- tests/libgit2/refs/branches/delete.c | 4 +- tests/libgit2/refs/branches/iterator.c | 2 +- tests/libgit2/refs/create.c | 22 ++-- tests/libgit2/refs/delete.c | 2 +- tests/libgit2/refs/foreachglob.c | 2 +- tests/libgit2/refs/lookup.c | 2 +- tests/libgit2/refs/peel.c | 2 +- tests/libgit2/refs/races.c | 24 ++-- tests/libgit2/refs/read.c | 4 +- tests/libgit2/refs/reflog/messages.c | 6 +- tests/libgit2/refs/reflog/reflog.c | 22 ++-- tests/libgit2/refs/reflog/reflog_helpers.c | 4 +- tests/libgit2/refs/transactions.c | 10 +- tests/libgit2/repo/env.c | 6 +- tests/libgit2/repo/getters.c | 10 +- tests/libgit2/repo/head.c | 2 +- tests/libgit2/reset/hard.c | 6 +- tests/libgit2/revert/bare.c | 10 +- tests/libgit2/revert/rename.c | 2 +- tests/libgit2/revert/workdir.c | 40 +++---- tests/libgit2/revwalk/basic.c | 28 ++--- tests/libgit2/revwalk/hidecb.c | 4 +- tests/libgit2/revwalk/mergebase.c | 66 +++++------ tests/libgit2/revwalk/simplify.c | 4 +- tests/libgit2/status/single.c | 4 +- tests/libgit2/status/submodules.c | 2 +- tests/libgit2/status/worktree.c | 14 +-- tests/libgit2/submodule/add.c | 2 +- tests/libgit2/transports/smart/packet.c | 4 +- tests/libgit2/win32/forbidden.c | 4 +- 184 files changed, 1041 insertions(+), 1021 deletions(-) diff --git a/examples/general.c b/examples/general.c index 0275f84a24e..7b8fa2ac5a7 100644 --- a/examples/general.c +++ b/examples/general.c @@ -143,7 +143,7 @@ static void oid_parsing(git_oid *oid) * key we're working with. */ #ifdef GIT_EXPERIMENTAL_SHA256 - git_oid_fromstr(oid, hex, GIT_OID_SHA1); + git_oid_from_string(oid, hex, GIT_OID_SHA1); #else git_oid_fromstr(oid, hex); #endif @@ -292,8 +292,8 @@ static void commit_writing(git_repository *repo) * but you can also use */ #ifdef GIT_EXPERIMENTAL_SHA256 - git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1", GIT_OID_SHA1); - git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); + git_oid_from_string(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1", GIT_OID_SHA1); + git_oid_from_string(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); #else git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1"); git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); @@ -363,7 +363,7 @@ static void commit_parsing(git_repository *repo) printf("\n*Commit Parsing*\n"); #ifdef GIT_EXPERIMENTAL_SHA256 - git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1); + git_oid_from_string(&oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1); #else git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479"); #endif @@ -436,7 +436,7 @@ static void tag_parsing(git_repository *repo) * the same way that we would a commit (or any other object). */ #ifdef GIT_EXPERIMENTAL_SHA256 - git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1", GIT_OID_SHA1); + git_oid_from_string(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1", GIT_OID_SHA1); #else git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); #endif @@ -488,7 +488,7 @@ static void tree_parsing(git_repository *repo) * Create the oid and lookup the tree object just like the other objects. */ #ifdef GIT_EXPERIMENTAL_SHA256 - git_oid_fromstr(&oid, "f60079018b664e4e79329a7ef9559c8d9e0378d1", GIT_OID_SHA1); + git_oid_from_string(&oid, "f60079018b664e4e79329a7ef9559c8d9e0378d1", GIT_OID_SHA1); #else git_oid_fromstr(&oid, "f60079018b664e4e79329a7ef9559c8d9e0378d1"); #endif @@ -546,7 +546,7 @@ static void blob_parsing(git_repository *repo) printf("\n*Blob Parsing*\n"); #ifdef GIT_EXPERIMENTAL_SHA256 - git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1); + git_oid_from_string(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1); #else git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08"); #endif @@ -592,7 +592,7 @@ static void revwalking(git_repository *repo) printf("\n*Revwalking*\n"); #ifdef GIT_EXPERIMENTAL_SHA256 - git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); + git_oid_from_string(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); #else git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); #endif diff --git a/examples/rev-list.c b/examples/rev-list.c index cf8ac30c625..a7598b8247d 100644 --- a/examples/rev-list.c +++ b/examples/rev-list.c @@ -141,7 +141,7 @@ static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct ar continue; #ifdef GIT_EXPERIMENTAL_SHA256 - if ((error = git_oid_fromstr(&oid, curr, GIT_OID_SHA1))) + if ((error = git_oid_from_string(&oid, curr, GIT_OID_SHA1))) return error; #else if ((error = git_oid_fromstr(&oid, curr))) diff --git a/include/git2/oid.h b/include/git2/oid.h index 0af9737a04d..b9e02cee6a2 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -114,12 +114,62 @@ typedef struct git_oid { #ifdef GIT_EXPERIMENTAL_SHA256 -GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str, git_oid_t type); -GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str, git_oid_t type); -GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length, git_oid_t type); -GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw, git_oid_t type); +/** + * Parse a NUL terminated hex formatted object id string into a `git_oid`. + * + * The given string must be NUL terminated, and must be the hex size of + * the given object ID type - 40 characters for SHA1, 64 characters for + * SHA256. + * + * To parse an incomplete object ID (an object ID prefix), or a sequence + * of characters that is not NUL terminated, use `git_oid_from_prefix`. + * + * @param out oid structure the result is written into. + * @param str input hex string + * @param type object id type + * @return 0 or an error code + */ +GIT_EXTERN(int) git_oid_from_string( + git_oid *out, + const char *str, + git_oid_t type); -#else +/** + * Parse the given number of characters out of a hex formatted object id + * string into a `git_oid`. + * + * The given length can be between 0 and the hex size for the given object ID + * type - 40 characters for SHA1, 64 characters for SHA256. The remainder of + * the `git_oid` will be set to zeros. + * + * @param out oid structure the result is written into. + * @param str input hex prefix + * @param type object id type + * @return 0 or an error code + */ +GIT_EXTERN(int) git_oid_from_prefix( + git_oid *out, + const char *str, + size_t len, + git_oid_t type); + +/** + * Parse a raw object id into a `git_oid`. + * + * The appropriate number of bytes for the given object ID type will + * be read from the byte array - 20 bytes for SHA1, 32 bytes for SHA256. + * + * @param out oid structure the result is written into. + * @param raw raw object ID bytes + * @param type object id type + * @return 0 or an error code + */ +GIT_EXTERN(int) git_oid_from_raw( + git_oid *out, + const unsigned char *raw, + git_oid_t type); + +#endif /** * Parse a hex formatted object id into a git_oid. @@ -168,8 +218,6 @@ GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length); */ GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw); -#endif - /** * Format a git_oid into a hex string. * diff --git a/src/libgit2/commit_graph.c b/src/libgit2/commit_graph.c index 92785049e4e..f62b873cc01 100644 --- a/src/libgit2/commit_graph.c +++ b/src/libgit2/commit_graph.c @@ -502,7 +502,7 @@ static int git_commit_graph_entry_get_byindex( } commit_data = file->commit_data + pos * (oid_size + 4 * sizeof(uint32_t)); - git_oid__fromraw(&e->tree_oid, commit_data, file->oid_type); + git_oid_from_raw(&e->tree_oid, commit_data, file->oid_type); e->parent_indices[0] = ntohl(*((uint32_t *)(commit_data + oid_size))); e->parent_indices[1] = ntohl( *((uint32_t *)(commit_data + oid_size + sizeof(uint32_t)))); @@ -536,7 +536,7 @@ static int git_commit_graph_entry_get_byindex( } } - git_oid__fromraw(&e->sha1, &file->oid_lookup[pos * oid_size], file->oid_type); + git_oid_from_raw(&e->sha1, &file->oid_lookup[pos * oid_size], file->oid_type); return 0; } diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c index 8e2660f2172..3769f951176 100644 --- a/src/libgit2/fetch.c +++ b/src/libgit2/fetch.c @@ -80,7 +80,7 @@ static int maybe_want_oid(git_remote *remote, git_refspec *spec) oid_head = git__calloc(1, sizeof(git_remote_head)); GIT_ERROR_CHECK_ALLOC(oid_head); - git_oid__fromstr(&oid_head->oid, spec->src, remote->repo->oid_type); + git_oid_from_string(&oid_head->oid, spec->src, remote->repo->oid_type); if (spec->dst) { oid_head->name = git__strdup(spec->dst); diff --git a/src/libgit2/fetchhead.c b/src/libgit2/fetchhead.c index 2f276e5265e..08be282a521 100644 --- a/src/libgit2/fetchhead.c +++ b/src/libgit2/fetchhead.c @@ -202,7 +202,7 @@ static int fetchhead_ref_parse( return -1; } - if (git_oid__fromstr(oid, oid_str, oid_type) < 0) { + if (git_oid_from_string(oid, oid_str, oid_type) < 0) { const git_error *oid_err = git_error_last(); const char *err_msg = oid_err ? oid_err->message : "invalid object ID"; diff --git a/src/libgit2/index.c b/src/libgit2/index.c index 7610781fc16..45ebaedac91 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -2364,7 +2364,7 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) return index_error_invalid("reading reuc entry oid"); } - if (git_oid__fromraw(&lost->oid[i], (const unsigned char *) buffer, index->oid_type) < 0) + if (git_oid_from_raw(&lost->oid[i], (const unsigned char *) buffer, index->oid_type) < 0) return -1; size -= oid_size; @@ -2553,14 +2553,14 @@ static int read_entry( switch (index->oid_type) { case GIT_OID_SHA1: - if (git_oid__fromraw(&entry.id, source_sha1.oid, + if (git_oid_from_raw(&entry.id, source_sha1.oid, GIT_OID_SHA1) < 0) return -1; entry.flags = ntohs(source_sha1.flags); break; #ifdef GIT_EXPERIMENTAL_SHA256 case GIT_OID_SHA256: - if (git_oid__fromraw(&entry.id, source_sha256.oid, + if (git_oid_from_raw(&entry.id, source_sha256.oid, GIT_OID_SHA256) < 0) return -1; entry.flags = ntohs(source_sha256.flags); diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index e62daacfa51..f1c85cb88bf 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -1112,7 +1112,7 @@ static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats) return -1; } - git_oid__fromraw(&base, base_info, idx->oid_type); + git_oid_from_raw(&base, base_info, idx->oid_type); git_mwindow_close(&w); if (has_entry(idx, &base)) diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index 0c5bc0f82d0..eabb4bfa32c 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -616,7 +616,7 @@ int git_repository_mergehead_foreach( goto cleanup; } - if ((error = git_oid__fromstr(&oid, line, repo->oid_type)) < 0) + if ((error = git_oid_from_string(&oid, line, repo->oid_type)) < 0) goto cleanup; if ((error = cb(&oid, payload)) != 0) { diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index 1336ed85f88..a3f84984ca8 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -449,7 +449,7 @@ int git_midx_entry_find( return midx_error("invalid index into the packfile names table"); e->pack_index = pack_index; e->offset = offset; - git_oid__fromraw(&e->sha1, current, idx->oid_type); + git_oid_from_raw(&e->sha1, current, idx->oid_type); return 0; } @@ -467,7 +467,7 @@ int git_midx_foreach_entry( oid_size = git_oid_size(idx->oid_type); for (i = 0; i < idx->num_objects; ++i) { - if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * oid_size], idx->oid_type)) < 0) + if ((error = git_oid_from_raw(&oid, &idx->oid_lookup[i * oid_size], idx->oid_type)) < 0) return error; if ((error = cb(&oid, data)) != 0) diff --git a/src/libgit2/notes.c b/src/libgit2/notes.c index 13ca3824bf1..393c1363a39 100644 --- a/src/libgit2/notes.c +++ b/src/libgit2/notes.c @@ -704,7 +704,7 @@ static int process_entry_path( goto cleanup; } - error = git_oid__fromstr(annotated_object_id, buf.ptr, it->repo->oid_type); + error = git_oid_from_string(annotated_object_id, buf.ptr, it->repo->oid_type); cleanup: git_str_dispose(&buf); diff --git a/src/libgit2/object.c b/src/libgit2/object.c index 36665c67630..1fff9de2917 100644 --- a/src/libgit2/object.c +++ b/src/libgit2/object.c @@ -662,7 +662,7 @@ int git_object__parse_oid_header( if (buffer[header_len + sha_len] != '\n') return -1; - if (git_oid__fromstr(oid, buffer + header_len, oid_type) < 0) + if (git_oid_from_prefix(oid, buffer + header_len, sha_len, oid_type) < 0) return -1; *buffer_out = buffer + (header_len + sha_len + 1); diff --git a/src/libgit2/odb_loose.c b/src/libgit2/odb_loose.c index 51195d35778..c772511a6ea 100644 --- a/src/libgit2/odb_loose.c +++ b/src/libgit2/odb_loose.c @@ -552,7 +552,10 @@ static int locate_object_short_oid( return git_odb__error_ambiguous("multiple matches in loose objects"); /* Convert obtained hex formatted oid to raw */ - error = git_oid__fromstr(res_oid, (char *)state.res_oid, backend->options.oid_type); + error = git_oid_from_prefix(res_oid, (char *)state.res_oid, + git_oid_hexsize(backend->options.oid_type), + backend->options.oid_type); + if (error) return error; diff --git a/src/libgit2/oid.c b/src/libgit2/oid.c index 2bb7a6f6bc4..a550c4f693a 100644 --- a/src/libgit2/oid.c +++ b/src/libgit2/oid.c @@ -28,11 +28,7 @@ static int oid_error_invalid(const char *msg) return -1; } -int git_oid__fromstrn( - git_oid *out, - const char *str, - size_t length, - git_oid_t type) +int git_oid_from_prefix(git_oid *out, const char *str, size_t len, git_oid_t type) { size_t size, p; int v; @@ -43,10 +39,10 @@ int git_oid__fromstrn( if (!(size = git_oid_size(type))) return oid_error_invalid("unknown type"); - if (!length) + if (!len) return oid_error_invalid("too short"); - if (length > git_oid_hexsize(type)) + if (len > git_oid_hexsize(type)) return oid_error_invalid("too long"); #ifdef GIT_EXPERIMENTAL_SHA256 @@ -54,7 +50,7 @@ int git_oid__fromstrn( #endif memset(out->id, 0, size); - for (p = 0; p < length; p++) { + for (p = 0; p < len; p++) { v = git__fromhex(str[p]); if (v < 0) return oid_error_invalid("contains invalid characters"); @@ -65,54 +61,53 @@ int git_oid__fromstrn( return 0; } -int git_oid__fromstrp(git_oid *out, const char *str, git_oid_t type) +int git_oid_from_string(git_oid *out, const char *str, git_oid_t type) { - return git_oid__fromstrn(out, str, strlen(str), type); -} + size_t hexsize; -int git_oid__fromstr(git_oid *out, const char *str, git_oid_t type) -{ - return git_oid__fromstrn(out, str, git_oid_hexsize(type), type); -} + if (!(hexsize = git_oid_hexsize(type))) + return oid_error_invalid("unknown type"); -#ifdef GIT_EXPERIMENTAL_SHA256 -int git_oid_fromstrn( - git_oid *out, - const char *str, - size_t length, - git_oid_t type) -{ - return git_oid__fromstrn(out, str, length, type); -} + if (git_oid_from_prefix(out, str, hexsize, type) < 0) + return -1; -int git_oid_fromstrp(git_oid *out, const char *str, git_oid_t type) -{ - return git_oid_fromstrn(out, str, strlen(str), type); + if (str[hexsize] != '\0') + return oid_error_invalid("too long"); + + return 0; } -int git_oid_fromstr(git_oid *out, const char *str, git_oid_t type) +int git_oid_from_raw(git_oid *out, const unsigned char *raw, git_oid_t type) { - return git_oid_fromstrn(out, str, git_oid_hexsize(type), type); + size_t size; + + if (!(size = git_oid_size(type))) + return oid_error_invalid("unknown type"); + +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = type; +#endif + memcpy(out->id, raw, size); + return 0; } -#else + int git_oid_fromstrn( git_oid *out, const char *str, size_t length) { - return git_oid__fromstrn(out, str, length, GIT_OID_SHA1); + return git_oid_from_prefix(out, str, length, GIT_OID_SHA1); } int git_oid_fromstrp(git_oid *out, const char *str) { - return git_oid__fromstrn(out, str, strlen(str), GIT_OID_SHA1); + return git_oid_from_prefix(out, str, strlen(str), GIT_OID_SHA1); } int git_oid_fromstr(git_oid *out, const char *str) { - return git_oid__fromstrn(out, str, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1); + return git_oid_from_prefix(out, str, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1); } -#endif int git_oid_nfmt(char *str, size_t n, const git_oid *oid) { @@ -227,31 +222,10 @@ char *git_oid_tostr(char *out, size_t n, const git_oid *oid) return out; } -int git_oid__fromraw(git_oid *out, const unsigned char *raw, git_oid_t type) -{ - size_t size; - - if (!(size = git_oid_size(type))) - return oid_error_invalid("unknown type"); - -#ifdef GIT_EXPERIMENTAL_SHA256 - out->type = type; -#endif - memcpy(out->id, raw, size); - return 0; -} - -#ifdef GIT_EXPERIMENTAL_SHA256 -int git_oid_fromraw(git_oid *out, const unsigned char *raw, git_oid_t type) -{ - return git_oid__fromraw(out, raw, type); -} -#else int git_oid_fromraw(git_oid *out, const unsigned char *raw) { - return git_oid__fromraw(out, raw, GIT_OID_SHA1); + return git_oid_from_raw(out, raw, GIT_OID_SHA1); } -#endif int git_oid_cpy(git_oid *out, const git_oid *src) { diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h index 9415915fcb2..cfcabce7111 100644 --- a/src/libgit2/oid.h +++ b/src/libgit2/oid.h @@ -267,17 +267,11 @@ GIT_INLINE(void) git_oid_clear(git_oid *out, git_oid_t type) /* SHA256 support */ -int git_oid__fromstr(git_oid *out, const char *str, git_oid_t type); - -int git_oid__fromstrp(git_oid *out, const char *str, git_oid_t type); - -int git_oid__fromstrn( - git_oid *out, - const char *str, - size_t length, - git_oid_t type); - -int git_oid__fromraw(git_oid *out, const unsigned char *raw, git_oid_t type); +#ifndef GIT_EXPERIMENTAL_SHA256 +int git_oid_from_string(git_oid *out, const char *str, git_oid_t type); +int git_oid_from_prefix(git_oid *out, const char *str, size_t len, git_oid_t type); +int git_oid_from_raw(git_oid *out, const unsigned char *data, git_oid_t type); +#endif int git_oid_global_init(void); diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index 8bdaac3a8d3..cf63b204e31 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -1002,7 +1002,7 @@ int get_delta_base( *curpos += used; } else if (type == GIT_OBJECT_REF_DELTA) { git_oid base_oid; - git_oid__fromraw(&base_oid, base_info, p->oid_type); + git_oid_from_raw(&base_oid, base_info, p->oid_type); /* If we have the cooperative cache, search in it first */ if (p->has_cache) { @@ -1372,7 +1372,7 @@ int git_pack_foreach_entry( git_array_clear(oids); GIT_ERROR_CHECK_ALLOC(oid); } - git_oid__fromraw(oid, p->ids[i], p->oid_type); + git_oid_from_raw(oid, p->ids[i], p->oid_type); } git_mutex_unlock(&p->lock); @@ -1441,7 +1441,7 @@ int git_pack_foreach_entry_offset( ntohl(*((uint32_t *)(large_offset_ptr + 4))); } - git_oid__fromraw(¤t_oid, (index + p->oid_size * i), p->oid_type); + git_oid_from_raw(¤t_oid, (index + p->oid_size * i), p->oid_type); if ((error = cb(¤t_oid, current_offset, data)) != 0) { error = git_error_set_after_callback(error); goto cleanup; @@ -1450,7 +1450,7 @@ int git_pack_foreach_entry_offset( } else { for (i = 0; i < p->num_objects; i++) { current_offset = ntohl(*(const uint32_t *)(index + (p->oid_size + 4) * i)); - git_oid__fromraw(¤t_oid, (index + (p->oid_size + 4) * i + 4), p->oid_type); + git_oid_from_raw(¤t_oid, (index + (p->oid_size + 4) * i + 4), p->oid_type); if ((error = cb(¤t_oid, current_offset, data)) != 0) { error = git_error_set_after_callback(error); goto cleanup; @@ -1595,7 +1595,7 @@ static int pack_entry_find_offset( } *offset_out = offset; - git_oid__fromraw(found_oid, current, p->oid_type); + git_oid_from_raw(found_oid, current, p->oid_type); #ifdef INDEX_DEBUG_LOOKUP { diff --git a/src/libgit2/parse.c b/src/libgit2/parse.c index 9eb86a3f584..ea693462144 100644 --- a/src/libgit2/parse.c +++ b/src/libgit2/parse.c @@ -109,7 +109,7 @@ int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx, git_oid_t oid_type) if (ctx->line_len < oid_hexsize) return -1; - if ((git_oid__fromstrn(out, ctx->line, oid_hexsize, oid_type)) < 0) + if ((git_oid_from_prefix(out, ctx->line, oid_hexsize, oid_type)) < 0) return -1; git_parse_advance_chars(ctx, oid_hexsize); return 0; diff --git a/src/libgit2/patch_parse.c b/src/libgit2/patch_parse.c index 04f2a582ab1..0a157178074 100644 --- a/src/libgit2/patch_parse.c +++ b/src/libgit2/patch_parse.c @@ -178,7 +178,7 @@ static int parse_header_oid( } if (len < GIT_OID_MINPREFIXLEN || len > hexsize || - git_oid__fromstrn(oid, ctx->parse_ctx.line, len, ctx->opts.oid_type) < 0) + git_oid_from_prefix(oid, ctx->parse_ctx.line, len, ctx->opts.oid_type) < 0) return git_parse_err("invalid hex formatted object id at line %"PRIuZ, ctx->parse_ctx.line_num); diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c index 77e442e981d..eb8a728357c 100644 --- a/src/libgit2/rebase.c +++ b/src/libgit2/rebase.c @@ -197,7 +197,7 @@ GIT_INLINE(int) rebase_readoid( return error; if (str_out->size != git_oid_hexsize(rebase->repo->oid_type) || - git_oid__fromstr(out, str_out->ptr, rebase->repo->oid_type) < 0) { + git_oid_from_string(out, str_out->ptr, rebase->repo->oid_type) < 0) { git_error_set(GIT_ERROR_REBASE, "the file '%s' contains an invalid object ID", filename); return -1; } @@ -1333,8 +1333,8 @@ static int rebase_copy_notes( if (strlen(fromstr) != git_oid_hexsize(rebase->repo->oid_type) || strlen(tostr) != git_oid_hexsize(rebase->repo->oid_type) || - git_oid__fromstr(&from, fromstr, rebase->repo->oid_type) < 0 || - git_oid__fromstr(&to, tostr, rebase->repo->oid_type) < 0) + git_oid_from_string(&from, fromstr, rebase->repo->oid_type) < 0 || + git_oid_from_string(&to, tostr, rebase->repo->oid_type) < 0) goto on_error; if ((error = rebase_copy_note(rebase, notes_ref.ptr, &from, &to, committer)) < 0) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index aa42782998b..1138ebe74d3 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -160,7 +160,7 @@ static int packed_reload(refdb_fs_backend *backend) /* parse " \n" */ - if (git_oid__fromstr(&oid, scan, backend->oid_type) < 0) + if (git_oid_from_prefix(&oid, scan, oid_hexsize, backend->oid_type) < 0) goto parse_failed; scan += oid_hexsize; @@ -181,7 +181,7 @@ static int packed_reload(refdb_fs_backend *backend) /* look for optional "^\n" */ if (*scan == '^') { - if (git_oid__fromstr(&oid, scan + 1, backend->oid_type) < 0) + if (git_oid_from_prefix(&oid, scan + 1, oid_hexsize, backend->oid_type) < 0) goto parse_failed; scan += oid_hexsize + 1; @@ -228,7 +228,7 @@ static int loose_parse_oid( goto corrupted; /* we need to get 40 OID characters from the file */ - if (git_oid__fromstr(oid, str, oid_type) < 0) + if (git_oid_from_prefix(oid, str, oid_hexsize, oid_type) < 0) goto corrupted; /* If the file is longer than 40 chars, the 41st must be a space */ @@ -723,7 +723,7 @@ static int packed_lookup( git_oid oid, peel, *peel_ptr = NULL; if (data_end - rec < (long)oid_hexsize || - git_oid__fromstr(&oid, rec, backend->oid_type) < 0) { + git_oid_from_prefix(&oid, rec, oid_hexsize, backend->oid_type) < 0) { goto parse_failed; } rec += oid_hexsize + 1; @@ -739,7 +739,7 @@ static int packed_lookup( if (*rec == '^') { rec++; if (data_end - rec < (long)oid_hexsize || - git_oid__fromstr(&peel, rec, backend->oid_type) < 0) { + git_oid_from_prefix(&peel, rec, oid_hexsize, backend->oid_type) < 0) { goto parse_failed; } peel_ptr = &peel; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 92c5043b811..0b674c5ef2c 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1959,7 +1959,7 @@ static int update_tips_for_spec( if (git_oid__is_hexstr(spec->src, remote->repo->oid_type)) { git_oid id; - if ((error = git_oid__fromstr(&id, spec->src, remote->repo->oid_type)) < 0) + if ((error = git_oid_from_string(&id, spec->src, remote->repo->oid_type)) < 0) goto on_error; if (spec->dst && diff --git a/src/libgit2/revparse.c b/src/libgit2/revparse.c index 9083e7a3cdc..2238ba5269c 100644 --- a/src/libgit2/revparse.c +++ b/src/libgit2/revparse.c @@ -23,7 +23,7 @@ static int maybe_sha_or_abbrev( { git_oid oid; - if (git_oid__fromstrn(&oid, spec, speclen, repo->oid_type) < 0) + if (git_oid_from_prefix(&oid, spec, speclen, repo->oid_type) < 0) return GIT_ENOTFOUND; return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJECT_ANY); diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 7ea8676e966..29ccb83ac72 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -64,7 +64,7 @@ static int ack_pkt( len -= 4; if (len < oid_hexsize || - git_oid__fromstr(&pkt->oid, line, data->oid_type) < 0) + git_oid_from_prefix(&pkt->oid, line, oid_hexsize, data->oid_type) < 0) goto out_err; line += oid_hexsize; len -= oid_hexsize; @@ -295,7 +295,7 @@ static int ref_pkt( oid_hexsize = git_oid_hexsize(data->oid_type); if (len < oid_hexsize || - git_oid__fromstr(&pkt->head.oid, line, data->oid_type) < 0) + git_oid_from_prefix(&pkt->head.oid, line, oid_hexsize, data->oid_type) < 0) goto out_err; line += oid_hexsize; len -= oid_hexsize; @@ -468,7 +468,7 @@ static int shallow_pkt( if (len != oid_hexsize) goto out_err; - git_oid__fromstr(&pkt->oid, line, data->oid_type); + git_oid_from_prefix(&pkt->oid, line, oid_hexsize, data->oid_type); line += oid_hexsize + 1; len -= oid_hexsize + 1; @@ -507,7 +507,7 @@ static int unshallow_pkt( if (len != oid_hexsize) goto out_err; - git_oid__fromstr(&pkt->oid, line, data->oid_type); + git_oid_from_prefix(&pkt->oid, line, oid_hexsize, data->oid_type); line += oid_hexsize + 1; len -= oid_hexsize + 1; diff --git a/src/libgit2/tree-cache.c b/src/libgit2/tree-cache.c index 95d879860f1..f3c895f4cf8 100644 --- a/src/libgit2/tree-cache.c +++ b/src/libgit2/tree-cache.c @@ -118,7 +118,7 @@ static int read_tree_internal( if (buffer + oid_size > buffer_end) goto corrupted; - git_oid__fromraw(&tree->oid, (const unsigned char *)buffer, oid_type); + git_oid_from_raw(&tree->oid, (const unsigned char *)buffer, oid_type); buffer += oid_size; } diff --git a/src/libgit2/tree.c b/src/libgit2/tree.c index ad9d8af28f5..2c89d516e74 100644 --- a/src/libgit2/tree.c +++ b/src/libgit2/tree.c @@ -435,7 +435,7 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size, git_oid_t oi entry->filename = buffer; buffer += filename_len + 1; - git_oid__fromraw(&entry->oid, (unsigned char *)buffer, oid_type); + git_oid_from_raw(&entry->oid, (unsigned char *)buffer, oid_type); buffer += oid_size; } diff --git a/tests/clar/clar_libgit2.h b/tests/clar/clar_libgit2.h index d8105c841b4..c6cad6835f7 100644 --- a/tests/clar/clar_libgit2.h +++ b/tests/clar/clar_libgit2.h @@ -171,8 +171,9 @@ GIT_INLINE(void) clar__assert_equal_oidstr( const char *one_str, const git_oid *two) { git_oid one; + git_oid_t oid_type = git_oid_type(two); - if (git_oid__fromstr(&one, one_str, git_oid_type(two)) < 0) { + if (git_oid_from_prefix(&one, one_str, git_oid_hexsize(oid_type), oid_type) < 0) { clar__fail(file, func, line, desc, "could not parse oid string", 1); } else { clar__assert_equal_oid(file, func, line, desc, &one, two); diff --git a/tests/libgit2/apply/apply_helpers.c b/tests/libgit2/apply/apply_helpers.c index e78b8ffcb09..384038722f8 100644 --- a/tests/libgit2/apply/apply_helpers.c +++ b/tests/libgit2/apply/apply_helpers.c @@ -14,7 +14,7 @@ static int iterator_compare(const git_index_entry *entry, void *_data) struct iterator_compare_data *data = (struct iterator_compare_data *)_data; cl_assert_equal_i(GIT_INDEX_ENTRY_STAGE(entry), data->expected[data->idx].stage); - cl_git_pass(git_oid__fromstr(&expected_id, data->expected[data->idx].oid_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, data->expected[data->idx].oid_str, GIT_OID_SHA1)); cl_assert_equal_oid(&entry->id, &expected_id); cl_assert_equal_i(entry->mode, data->expected[data->idx].mode); cl_assert_equal_s(entry->path, data->expected[data->idx].path); diff --git a/tests/libgit2/apply/both.c b/tests/libgit2/apply/both.c index 44c5b19371f..d3d040c985c 100644 --- a/tests/libgit2/apply/both.c +++ b/tests/libgit2/apply/both.c @@ -12,7 +12,7 @@ void test_apply_both__initialize(void) repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_oid__fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); @@ -42,8 +42,8 @@ void test_apply_both__generated_diff(void) size_t both_expected_cnt = sizeof(both_expected) / sizeof(struct merge_index_entry); - git_oid__fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); - git_oid__fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); + git_oid_from_string(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); @@ -192,7 +192,7 @@ void test_apply_both__index_must_match_workdir(void) memset(&idx_entry, 0, sizeof(git_index_entry)); idx_entry.mode = 0100644; idx_entry.path = "asparagus.txt"; - cl_git_pass(git_oid__fromstr(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538", GIT_OID_SHA1)); cl_git_pass(git_index_add(index, &idx_entry)); cl_git_pass(git_index_write(index)); @@ -290,7 +290,7 @@ void test_apply_both__keeps_nonconflicting_changes(void) memset(&idx_entry, 0, sizeof(git_index_entry)); idx_entry.mode = 0100644; idx_entry.path = "beef.txt"; - cl_git_pass(git_oid__fromstr(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e", GIT_OID_SHA1)); cl_git_pass(git_index_add(index, &idx_entry)); cl_git_pass(git_index_remove(index, "bouilli.txt", 0)); @@ -386,7 +386,7 @@ void test_apply_both__honors_crlf_attributes(void) cl_git_rmfile("merge-recursive/asparagus.txt"); cl_git_rmfile("merge-recursive/veal.txt"); - git_oid__fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); diff --git a/tests/libgit2/apply/callbacks.c b/tests/libgit2/apply/callbacks.c index f076ca48622..cda06e6c6b3 100644 --- a/tests/libgit2/apply/callbacks.c +++ b/tests/libgit2/apply/callbacks.c @@ -12,7 +12,7 @@ void test_apply_callbacks__initialize(void) repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_oid__fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); diff --git a/tests/libgit2/apply/check.c b/tests/libgit2/apply/check.c index 0c1f86dc531..8f37e00b1f9 100644 --- a/tests/libgit2/apply/check.c +++ b/tests/libgit2/apply/check.c @@ -12,7 +12,7 @@ void test_apply_check__initialize(void) repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_oid__fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); @@ -32,8 +32,8 @@ void test_apply_check__generate_diff(void) git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; git_apply_options opts = GIT_APPLY_OPTIONS_INIT; - cl_git_pass(git_oid__fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); diff --git a/tests/libgit2/apply/index.c b/tests/libgit2/apply/index.c index 564d55c8c1c..e0fb7f2a455 100644 --- a/tests/libgit2/apply/index.c +++ b/tests/libgit2/apply/index.c @@ -12,7 +12,7 @@ void test_apply_index__initialize(void) repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_oid__fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); @@ -42,8 +42,8 @@ void test_apply_index__generate_diff(void) size_t index_expected_cnt = sizeof(index_expected) / sizeof(struct merge_index_entry); - git_oid__fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); - git_oid__fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); + git_oid_from_string(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); @@ -233,7 +233,7 @@ void test_apply_index__keeps_nonconflicting_changes(void) memset(&idx_entry, 0, sizeof(git_index_entry)); idx_entry.mode = 0100644; idx_entry.path = "beef.txt"; - cl_git_pass(git_oid__fromstr(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e", GIT_OID_SHA1)); cl_git_pass(git_index_add(index, &idx_entry)); cl_git_pass(git_index_remove(index, "bouilli.txt", 0)); @@ -279,7 +279,7 @@ void test_apply_index__can_apply_nonconflicting_file_changes(void) memset(&idx_entry, 0, sizeof(git_index_entry)); idx_entry.mode = 0100644; idx_entry.path = "asparagus.txt"; - cl_git_pass(git_oid__fromstr(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538", GIT_OID_SHA1)); cl_git_pass(git_index_add(index, &idx_entry)); cl_git_pass(git_index_write(index)); diff --git a/tests/libgit2/apply/tree.c b/tests/libgit2/apply/tree.c index b97fe8d352b..0e5b65fd7c1 100644 --- a/tests/libgit2/apply/tree.c +++ b/tests/libgit2/apply/tree.c @@ -35,8 +35,8 @@ void test_apply_tree__one(void) { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, }; - git_oid__fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); - git_oid__fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); + git_oid_from_string(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); @@ -75,7 +75,7 @@ void test_apply_tree__adds_file(void) { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, }; - git_oid__fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); diff --git a/tests/libgit2/apply/workdir.c b/tests/libgit2/apply/workdir.c index 5ae56847a80..6b95ec04bce 100644 --- a/tests/libgit2/apply/workdir.c +++ b/tests/libgit2/apply/workdir.c @@ -12,7 +12,7 @@ void test_apply_workdir__initialize(void) repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_oid__fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); @@ -42,8 +42,8 @@ void test_apply_workdir__generated_diff(void) size_t workdir_expected_cnt = sizeof(workdir_expected) / sizeof(struct merge_index_entry); - git_oid__fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); - git_oid__fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); + git_oid_from_string(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); cl_git_pass(git_commit_tree(&a_tree, a_commit)); @@ -171,7 +171,7 @@ void test_apply_workdir__modified_index_with_unmodified_workdir_is_ok(void) idx_entry.mode = 0100644; idx_entry.path = "veal.txt"; - cl_git_pass(git_oid__fromstr(&idx_entry.id, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&idx_entry.id, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", GIT_OID_SHA1)); cl_git_pass(git_index_add(index, &idx_entry)); cl_git_pass(git_index_remove(index, "asparagus.txt", 0)); diff --git a/tests/libgit2/checkout/binaryunicode.c b/tests/libgit2/checkout/binaryunicode.c index e4cab66a350..5cefa77e2ee 100644 --- a/tests/libgit2/checkout/binaryunicode.c +++ b/tests/libgit2/checkout/binaryunicode.c @@ -34,12 +34,12 @@ static void execute_test(void) git_commit_free(commit); /* Verify that the lenna.jpg file was checked out correctly */ - cl_git_pass(git_oid__fromstr(&check, "8ab005d890fe53f65eda14b23672f60d9f4ec5a1", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&check, "8ab005d890fe53f65eda14b23672f60d9f4ec5a1", GIT_OID_SHA1)); cl_git_pass(git_odb__hashfile(&oid, "binaryunicode/lenna.jpg", GIT_OBJECT_BLOB, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &check); /* Verify that the text file was checked out correctly */ - cl_git_pass(git_oid__fromstr(&check, "965b223880dd4249e2c66a0cc0b4cffe1dc40f5a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&check, "965b223880dd4249e2c66a0cc0b4cffe1dc40f5a", GIT_OID_SHA1)); cl_git_pass(git_odb__hashfile(&oid, "binaryunicode/utf16_withbom_noeol_crlf.txt", GIT_OBJECT_BLOB, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &check); } diff --git a/tests/libgit2/checkout/conflict.c b/tests/libgit2/checkout/conflict.c index ab4d0aba4d4..29134a077aa 100644 --- a/tests/libgit2/checkout/conflict.c +++ b/tests/libgit2/checkout/conflict.c @@ -104,7 +104,7 @@ static void create_index(struct checkout_index_entry *entries, size_t entries_le entry.mode = entries[i].mode; GIT_INDEX_ENTRY_STAGE_SET(&entry, entries[i].stage); - git_oid__fromstr(&entry.id, entries[i].oid_str, GIT_OID_SHA1); + git_oid_from_string(&entry.id, entries[i].oid_str, GIT_OID_SHA1); entry.path = entries[i].path; cl_git_pass(git_index_add(g_index, &entry)); @@ -155,7 +155,7 @@ static void ensure_workdir_oid(const char *path, const char *oid_str) { git_oid expected, actual; - cl_git_pass(git_oid__fromstr(&expected, oid_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, oid_str, GIT_OID_SHA1)); cl_git_pass(git_repository_hashfile(&actual, g_repo, path, GIT_OBJECT_BLOB, NULL)); cl_assert_equal_oid(&expected, &actual); } diff --git a/tests/libgit2/checkout/index.c b/tests/libgit2/checkout/index.c index aa85e24a616..8ca72e426e6 100644 --- a/tests/libgit2/checkout/index.c +++ b/tests/libgit2/checkout/index.c @@ -788,15 +788,15 @@ static void add_conflict(git_index *index, const char *path) entry.mode = 0100644; entry.path = path; - git_oid__fromstr(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); GIT_INDEX_ENTRY_STAGE_SET(&entry, 1); cl_git_pass(git_index_add(index, &entry)); - git_oid__fromstr(&entry.id, "4e886e602529caa9ab11d71f86634bd1b6e0de10", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "4e886e602529caa9ab11d71f86634bd1b6e0de10", GIT_OID_SHA1); GIT_INDEX_ENTRY_STAGE_SET(&entry, 2); cl_git_pass(git_index_add(index, &entry)); - git_oid__fromstr(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); GIT_INDEX_ENTRY_STAGE_SET(&entry, 3); cl_git_pass(git_index_add(index, &entry)); } diff --git a/tests/libgit2/checkout/tree.c b/tests/libgit2/checkout/tree.c index b9f51f7b977..ae4c31dce83 100644 --- a/tests/libgit2/checkout/tree.c +++ b/tests/libgit2/checkout/tree.c @@ -139,8 +139,8 @@ void test_checkout_tree__doesnt_write_unrequested_files_to_worktree(void) git_commit* p_chomped_commit; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; - git_oid__fromstr(&master_oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); - git_oid__fromstr(&chomped_oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); + git_oid_from_string(&master_oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&chomped_oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&p_master_commit, g_repo, &master_oid)); cl_git_pass(git_commit_lookup(&p_chomped_commit, g_repo, &chomped_oid)); @@ -609,7 +609,7 @@ void test_checkout_tree__donot_update_deleted_file_by_default(void) cl_git_pass(git_repository_index(&index, g_repo)); - cl_git_pass(git_oid__fromstr(&old_id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&old_id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&old_commit, g_repo, &old_id)); cl_git_pass(git_reset(g_repo, (git_object *)old_commit, GIT_RESET_HARD, NULL)); @@ -619,7 +619,7 @@ void test_checkout_tree__donot_update_deleted_file_by_default(void) cl_assert(!git_fs_path_exists("testrepo/branch_file.txt")); - cl_git_pass(git_oid__fromstr(&new_id, "099fabac3a9ea935598528c27f866e34089c2eff", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&new_id, "099fabac3a9ea935598528c27f866e34089c2eff", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&new_commit, g_repo, &new_id)); @@ -934,16 +934,16 @@ static void create_conflict(const char *path) memset(&entry, 0x0, sizeof(git_index_entry)); entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&entry, 1); - git_oid__fromstr(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); entry.path = path; cl_git_pass(git_index_add(index, &entry)); GIT_INDEX_ENTRY_STAGE_SET(&entry, 2); - git_oid__fromstr(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); cl_git_pass(git_index_add(index, &entry)); GIT_INDEX_ENTRY_STAGE_SET(&entry, 3); - git_oid__fromstr(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); cl_git_pass(git_index_add(index, &entry)); cl_git_pass(git_index_write(index)); @@ -979,7 +979,7 @@ void test_checkout_tree__filemode_preserved_in_index(void) cl_git_pass(git_repository_index(&index, g_repo)); /* test a freshly added executable */ - cl_git_pass(git_oid__fromstr(&executable_oid, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -990,7 +990,7 @@ void test_checkout_tree__filemode_preserved_in_index(void) /* Now start with a commit which has a text file */ - cl_git_pass(git_oid__fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -1001,7 +1001,7 @@ void test_checkout_tree__filemode_preserved_in_index(void) /* And then check out to a commit which converts the text file to an executable */ - cl_git_pass(git_oid__fromstr(&executable_oid, "144344043ba4d4a405da03de3844aa829ae8be0e", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "144344043ba4d4a405da03de3844aa829ae8be0e", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -1012,7 +1012,7 @@ void test_checkout_tree__filemode_preserved_in_index(void) /* Finally, check out the text file again and check that the exec bit is cleared */ - cl_git_pass(git_oid__fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -1054,7 +1054,7 @@ void test_checkout_tree__filemode_preserved_in_workdir(void) opts.checkout_strategy = GIT_CHECKOUT_FORCE; /* test a freshly added executable */ - cl_git_pass(git_oid__fromstr(&executable_oid, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -1064,7 +1064,7 @@ void test_checkout_tree__filemode_preserved_in_workdir(void) /* Now start with a commit which has a text file */ - cl_git_pass(git_oid__fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -1074,7 +1074,7 @@ void test_checkout_tree__filemode_preserved_in_workdir(void) /* And then check out to a commit which converts the text file to an executable */ - cl_git_pass(git_oid__fromstr(&executable_oid, "144344043ba4d4a405da03de3844aa829ae8be0e", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "144344043ba4d4a405da03de3844aa829ae8be0e", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -1084,7 +1084,7 @@ void test_checkout_tree__filemode_preserved_in_workdir(void) /* Finally, check out the text file again and check that the exec bit is cleared */ - cl_git_pass(git_oid__fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); @@ -1103,7 +1103,7 @@ void test_checkout_tree__removes_conflicts(void) git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_index *index; - cl_git_pass(git_oid__fromstr(&commit_id, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&commit_id, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &commit_id)); opts.checkout_strategy = GIT_CHECKOUT_FORCE; @@ -1146,7 +1146,7 @@ void test_checkout_tree__removes_conflicts_only_by_pathscope(void) git_index *index; const char *path = "executable.txt"; - cl_git_pass(git_oid__fromstr(&commit_id, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&commit_id, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &commit_id)); opts.checkout_strategy = GIT_CHECKOUT_FORCE; @@ -1574,7 +1574,7 @@ static void modify_index_ondisk(void) cl_git_pass(git_repository_open(&other_repo, git_repository_workdir(g_repo))); cl_git_pass(git_repository_index(&other_index, other_repo)); - cl_git_pass(git_oid__fromstr(&entry.id, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); entry.mode = 0100644; entry.path = "README"; diff --git a/tests/libgit2/checkout/typechange.c b/tests/libgit2/checkout/typechange.c index 1fa2d3095b4..dfdb77e9222 100644 --- a/tests/libgit2/checkout/typechange.c +++ b/tests/libgit2/checkout/typechange.c @@ -319,7 +319,7 @@ void test_checkout_typechange__status_char(void) git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; char expected[8] = {'M', 'M', 'R', 'T', 'D', 'R', 'A', 'R'}; - git_oid__fromstr(&oid, "9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a", GIT_OID_SHA1); + git_oid_from_string(&oid, "9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); diffopts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; cl_git_pass(git_diff__commit(&diff, g_repo, commit, &diffopts)); diff --git a/tests/libgit2/cherrypick/bare.c b/tests/libgit2/cherrypick/bare.c index 66446889940..6c24a446561 100644 --- a/tests/libgit2/cherrypick/bare.c +++ b/tests/libgit2/cherrypick/bare.c @@ -32,10 +32,10 @@ void test_cherrypick_bare__automerge(void) { 0100644, "df6b290e0bd6a89b01d69f66687e8abf385283ca", 0, "file3.txt" }, }; - git_oid__fromstr(&head_oid, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - git_oid__fromstr(&cherry_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick_commit(&index, repo, commit, head, 0, NULL)); @@ -62,10 +62,10 @@ void test_cherrypick_bare__conflicts(void) { 0100644, "e233b9ed408a95e9d4b65fec7fc34943a556deb2", 3, "file3.txt" }, }; - git_oid__fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - git_oid__fromstr(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick_commit(&index, repo, commit, head, 0, NULL)); @@ -89,10 +89,10 @@ void test_cherrypick_bare__orphan(void) { 0100644, "9ccb9bf50c011fd58dcbaa65df917bf79539717f", 0, "orphan.txt" }, }; - git_oid__fromstr(&head_oid, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - git_oid__fromstr(&cherry_oid, "74f06b5bfec6d33d7264f73606b57a7c0b963819", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "74f06b5bfec6d33d7264f73606b57a7c0b963819", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick_commit(&index, repo, commit, head, 0, NULL)); diff --git a/tests/libgit2/cherrypick/workdir.c b/tests/libgit2/cherrypick/workdir.c index 21e0b1447ee..45b8349e1ed 100644 --- a/tests/libgit2/cherrypick/workdir.c +++ b/tests/libgit2/cherrypick/workdir.c @@ -57,7 +57,7 @@ void test_cherrypick_workdir__automerge(void) cl_git_pass(git_signature_new(&signature, "Picker", "picker@example.org", time(NULL), 0)); - git_oid__fromstr(&head_oid, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e", GIT_OID_SHA1); for (i = 0; i < 3; ++i) { git_commit *head = NULL, *commit = NULL; @@ -67,7 +67,7 @@ void test_cherrypick_workdir__automerge(void) cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, cherrypick_oids[i], GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, cherrypick_oids[i], GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, NULL)); @@ -110,7 +110,7 @@ void test_cherrypick_workdir__empty_result(void) cl_git_pass(git_signature_new(&signature, "Picker", "picker@example.org", time(NULL), 0)); - git_oid__fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); /* Create an untracked file that should not conflict */ cl_git_mkfile(TEST_REPO_PATH "/file4.txt", ""); @@ -119,7 +119,7 @@ void test_cherrypick_workdir__empty_result(void) cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, cherrypick_oid, GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, cherrypick_oid, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, NULL)); @@ -151,12 +151,12 @@ void test_cherrypick_workdir__conflicts(void) { 0100644, "e233b9ed408a95e9d4b65fec7fc34943a556deb2", 3, "file3.txt" }, }; - git_oid__fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, NULL)); @@ -259,12 +259,12 @@ void test_cherrypick_workdir__conflict_use_ours(void) /* leave the index in a conflicted state, but checkout "ours" to the workdir */ opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_USE_OURS; - git_oid__fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, &opts)); @@ -302,11 +302,11 @@ void test_cherrypick_workdir__rename(void) opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; - git_oid__fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, "2a26c7e88b285613b302ba76712bc998863f3cbc", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "2a26c7e88b285613b302ba76712bc998863f3cbc", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, &opts)); @@ -337,11 +337,11 @@ void test_cherrypick_workdir__both_renamed(void) opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; - git_oid__fromstr(&head_oid, "44cd2ed2052c9c68f9a439d208e9614dc2a55c70", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "44cd2ed2052c9c68f9a439d208e9614dc2a55c70", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, "2a26c7e88b285613b302ba76712bc998863f3cbc", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "2a26c7e88b285613b302ba76712bc998863f3cbc", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, &opts)); @@ -388,11 +388,11 @@ void test_cherrypick_workdir__merge_fails_without_mainline_specified(void) git_commit *head, *commit; git_oid head_oid, cherry_oid; - git_oid__fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_must_fail(git_cherrypick(repo, commit, NULL)); @@ -420,11 +420,11 @@ void test_cherrypick_workdir__merge_first_parent(void) opts.mainline = 1; - git_oid__fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, &opts)); @@ -452,11 +452,11 @@ void test_cherrypick_workdir__merge_second_parent(void) opts.mainline = 2; - git_oid__fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff", GIT_OID_SHA1); + git_oid_from_string(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); cl_git_pass(git_cherrypick(repo, commit, &opts)); diff --git a/tests/libgit2/commit/commit.c b/tests/libgit2/commit/commit.c index 140f87d0c72..bdd08b9f7df 100644 --- a/tests/libgit2/commit/commit.c +++ b/tests/libgit2/commit/commit.c @@ -26,10 +26,10 @@ void test_commit_commit__create_unexisting_update_ref(void) git_signature *s; git_reference *ref; - git_oid__fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); - git_oid__fromstr(&oid, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OID_SHA1); + git_oid_from_string(&oid, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, _repo, &oid)); cl_git_pass(git_signature_now(&s, "alice", "alice@example.com")); @@ -59,10 +59,10 @@ void test_commit_commit__create_initial_commit(void) git_signature *s; git_reference *ref; - git_oid__fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); - git_oid__fromstr(&oid, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OID_SHA1); + git_oid_from_string(&oid, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, _repo, &oid)); cl_git_pass(git_signature_now(&s, "alice", "alice@example.com")); @@ -89,10 +89,10 @@ void test_commit_commit__create_initial_commit_parent_not_current(void) git_commit *commit; git_signature *s; - git_oid__fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); - git_oid__fromstr(&oid, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OID_SHA1); + git_oid_from_string(&oid, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, _repo, &oid)); cl_git_pass(git_signature_now(&s, "alice", "alice@example.com")); diff --git a/tests/libgit2/commit/parent.c b/tests/libgit2/commit/parent.c index 1ec96babb1e..ddbb8a44d61 100644 --- a/tests/libgit2/commit/parent.c +++ b/tests/libgit2/commit/parent.c @@ -9,7 +9,7 @@ void test_commit_parent__initialize(void) cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); - git_oid__fromstr(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); + git_oid_from_string(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); } diff --git a/tests/libgit2/commit/parse.c b/tests/libgit2/commit/parse.c index 3a1fc3d26bd..6dda8a7e5a0 100644 --- a/tests/libgit2/commit/parse.c +++ b/tests/libgit2/commit/parse.c @@ -343,7 +343,7 @@ void test_commit_parse__details0(void) { unsigned int parents, p; git_commit *parent = NULL, *old_parent = NULL; - git_oid__fromstr(&id, commit_ids[i], GIT_OID_SHA1); + git_oid_from_string(&id, commit_ids[i], GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, g_repo, &id)); @@ -533,7 +533,7 @@ corrupt signature\n"; git_buf_dispose(&signed_data); /* Try to parse a tree */ - cl_git_pass(git_oid__fromstr(&commit_id, "45dd856fdd4d89b884c340ba0e047752d9b085d6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&commit_id, "45dd856fdd4d89b884c340ba0e047752d9b085d6", GIT_OID_SHA1)); cl_git_fail_with(GIT_ENOTFOUND, git_commit_extract_signature(&signature, &signed_data, g_repo, &commit_id, NULL)); cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass); diff --git a/tests/libgit2/commit/write.c b/tests/libgit2/commit/write.c index 890f7384b1a..0fd228bc883 100644 --- a/tests/libgit2/commit/write.c +++ b/tests/libgit2/commit/write.c @@ -51,10 +51,10 @@ void test_commit_write__from_memory(void) git_commit *parent; git_tree *tree; - git_oid__fromstr(&tree_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, tree_id_str, GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); - git_oid__fromstr(&parent_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, parent_id_str, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&parent, g_repo, &parent_id)); /* create signatures */ @@ -107,14 +107,14 @@ void test_commit_write__into_buf(void) git_oid parent_id; git_buf commit = GIT_BUF_INIT; - git_oid__fromstr(&tree_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, tree_id_str, GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); /* create signatures */ cl_git_pass(git_signature_new(&committer, committer_name, committer_email, 123456789, 60)); cl_git_pass(git_signature_new(&author, committer_name, committer_email, 987654321, 90)); - git_oid__fromstr(&parent_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, parent_id_str, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&parent, g_repo, &parent_id)); cl_git_pass(git_commit_create_buffer(&commit, g_repo, author, committer, @@ -148,7 +148,7 @@ void test_commit_write__root(void) git_reflog *log; const git_reflog_entry *entry; - git_oid__fromstr(&tree_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, tree_id_str, GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); /* create signatures */ @@ -242,34 +242,34 @@ void test_commit_write__can_write_invalid_objects(void) cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0)); /* this is a valid tree and parent */ - git_oid__fromstr(&tree_id, tree_id_str, GIT_OID_SHA1); - git_oid__fromstr(&parent_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, parent_id_str, GIT_OID_SHA1); - git_oid__fromstr(&expected_id, "c8571bbec3a72c4bcad31648902e5a453f1adece", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "c8571bbec3a72c4bcad31648902e5a453f1adece", GIT_OID_SHA1); cl_git_pass(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); cl_assert_equal_oid(&expected_id, &commit_id); /* this is a wholly invented tree id */ - git_oid__fromstr(&tree_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); - git_oid__fromstr(&parent_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); + git_oid_from_string(&parent_id, parent_id_str, GIT_OID_SHA1); - git_oid__fromstr(&expected_id, "996008340b8e68d69bf3c28d7c57fb7ec3c8e202", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "996008340b8e68d69bf3c28d7c57fb7ec3c8e202", GIT_OID_SHA1); cl_git_pass(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); cl_assert_equal_oid(&expected_id, &commit_id); /* this is a wholly invented parent id */ - git_oid__fromstr(&tree_id, tree_id_str, GIT_OID_SHA1); - git_oid__fromstr(&parent_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); + git_oid_from_string(&tree_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); - git_oid__fromstr(&expected_id, "d78f660cab89d9791ca6714b57978bf2a7e709fd", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "d78f660cab89d9791ca6714b57978bf2a7e709fd", GIT_OID_SHA1); cl_git_pass(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); cl_assert_equal_oid(&expected_id, &commit_id); /* these are legitimate objects, but of the wrong type */ - git_oid__fromstr(&tree_id, parent_id_str, GIT_OID_SHA1); - git_oid__fromstr(&parent_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, tree_id_str, GIT_OID_SHA1); - git_oid__fromstr(&expected_id, "5d80c07414e3f18792949699dfcacadf7748f361", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "5d80c07414e3f18792949699dfcacadf7748f361", GIT_OID_SHA1); cl_git_pass(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); cl_assert_equal_oid(&expected_id, &commit_id); } @@ -279,23 +279,23 @@ void test_commit_write__can_validate_objects(void) git_oid tree_id, parent_id, commit_id; /* this is a valid tree and parent */ - git_oid__fromstr(&tree_id, tree_id_str, GIT_OID_SHA1); - git_oid__fromstr(&parent_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, parent_id_str, GIT_OID_SHA1); cl_git_pass(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); /* this is a wholly invented tree id */ - git_oid__fromstr(&tree_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); - git_oid__fromstr(&parent_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); + git_oid_from_string(&parent_id, parent_id_str, GIT_OID_SHA1); cl_git_fail(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); /* this is a wholly invented parent id */ - git_oid__fromstr(&tree_id, tree_id_str, GIT_OID_SHA1); - git_oid__fromstr(&parent_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); + git_oid_from_string(&tree_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1); cl_git_fail(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); /* these are legitimate objects, but of the wrong type */ - git_oid__fromstr(&tree_id, parent_id_str, GIT_OID_SHA1); - git_oid__fromstr(&parent_id, tree_id_str, GIT_OID_SHA1); + git_oid_from_string(&tree_id, parent_id_str, GIT_OID_SHA1); + git_oid_from_string(&parent_id, tree_id_str, GIT_OID_SHA1); cl_git_fail(create_commit_from_ids(&commit_id, &tree_id, &parent_id)); } diff --git a/tests/libgit2/core/oid.c b/tests/libgit2/core/oid.c index a405b3344d7..3b20061cbfb 100644 --- a/tests/libgit2/core/oid.c +++ b/tests/libgit2/core/oid.c @@ -21,14 +21,14 @@ const char *str_oid_sha256_m = "d3e63d2f2e43d1fee23a74bf19a0ede156cba2d1bd602eba void test_core_oid__initialize(void) { - cl_git_pass(git_oid__fromstr(&id_sha1, str_oid_sha1, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstrp(&idp_sha1, str_oid_sha1_p, GIT_OID_SHA1)); - cl_git_fail(git_oid__fromstrp(&idm_sha1, str_oid_sha1_m, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id_sha1, str_oid_sha1, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&idp_sha1, str_oid_sha1_p, strlen(str_oid_sha1_p), GIT_OID_SHA1)); + cl_git_fail(git_oid_from_prefix(&idm_sha1, str_oid_sha1_m, strlen(str_oid_sha1_m), GIT_OID_SHA1)); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_oid__fromstr(&id_sha256, str_oid_sha256, GIT_OID_SHA256)); - cl_git_pass(git_oid__fromstrp(&idp_sha256, str_oid_sha256_p, GIT_OID_SHA256)); - cl_git_fail(git_oid__fromstrp(&idm_sha256, str_oid_sha256_m, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id_sha256, str_oid_sha256, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_prefix(&idp_sha256, str_oid_sha256_p, strlen(str_oid_sha256_p), GIT_OID_SHA256)); + cl_git_fail(git_oid_from_prefix(&idm_sha256, str_oid_sha256_m, strlen(str_oid_sha256_m), GIT_OID_SHA256)); #endif } diff --git a/tests/libgit2/core/oidarray.c b/tests/libgit2/core/oidarray.c index 4a9e47c701d..6f607c85be0 100644 --- a/tests/libgit2/core/oidarray.c +++ b/tests/libgit2/core/oidarray.c @@ -20,10 +20,10 @@ void test_core_oidarray__add_and_remove_oid_from_shallowarray(void) git_oid oid_0_obj, oid_1_obj, oid_2_obj, oid_3_obj; git_array_oid_t array = GIT_ARRAY_INIT; - git_oid__fromstr(&oid_0_obj, oid_0, GIT_OID_SHA1); - git_oid__fromstr(&oid_1_obj, oid_1, GIT_OID_SHA1); - git_oid__fromstr(&oid_2_obj, oid_2, GIT_OID_SHA1); - git_oid__fromstr(&oid_3_obj, oid_3, GIT_OID_SHA1); + git_oid_from_string(&oid_0_obj, oid_0, GIT_OID_SHA1); + git_oid_from_string(&oid_1_obj, oid_1, GIT_OID_SHA1); + git_oid_from_string(&oid_2_obj, oid_2, GIT_OID_SHA1); + git_oid_from_string(&oid_3_obj, oid_3, GIT_OID_SHA1); /* add some initial ids */ git_oidarray__add(&array, &oid_0_obj); diff --git a/tests/libgit2/core/pool.c b/tests/libgit2/core/pool.c index cf01cb9d182..83332f2d08d 100644 --- a/tests/libgit2/core/pool.c +++ b/tests/libgit2/core/pool.c @@ -22,7 +22,7 @@ void test_core_pool__oid(void) for (j = 0; j < 8; j++) oid_hex[j] = to_hex[(i >> (4 * j)) & 0x0f]; - cl_git_pass(git_oid__fromstr(oid, oid_hex, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(oid, oid_hex, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1)); } #ifndef GIT_DEBUG_POOL diff --git a/tests/libgit2/diff/binary.c b/tests/libgit2/diff/binary.c index 3bf39f34ad7..11061788d68 100644 --- a/tests/libgit2/diff/binary.c +++ b/tests/libgit2/diff/binary.c @@ -31,12 +31,12 @@ static void test_patch( git_patch *patch; git_buf actual = GIT_BUF_INIT; - cl_git_pass(git_oid__fromstr(&id_one, one, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id_one, one, GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit_one, repo, &id_one)); cl_git_pass(git_commit_tree(&tree_one, commit_one)); if (two) { - cl_git_pass(git_oid__fromstr(&id_two, two, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id_two, two, GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit_two, repo, &id_two)); cl_git_pass(git_commit_tree(&tree_two, commit_two)); } else { @@ -289,7 +289,7 @@ void test_diff_binary__empty_for_no_diff(void) repo = cl_git_sandbox_init("renames"); - cl_git_pass(git_oid__fromstr(&id, "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, repo, &id)); cl_git_pass(git_commit_tree(&tree, commit)); @@ -510,8 +510,8 @@ void test_diff_binary__blob_to_blob(void) cl_git_pass(git_index_add_bypath(index, "untimely.txt")); cl_git_pass(git_index_write(index)); - git_oid__fromstr(&old_id, "9a69d960ae94b060f56c2a8702545e2bb1abb935", GIT_OID_SHA1); - git_oid__fromstr(&new_id, "1111d4f11f4b35bf6759e0fb714fe09731ef0840", GIT_OID_SHA1); + git_oid_from_string(&old_id, "9a69d960ae94b060f56c2a8702545e2bb1abb935", GIT_OID_SHA1); + git_oid_from_string(&new_id, "1111d4f11f4b35bf6759e0fb714fe09731ef0840", GIT_OID_SHA1); cl_git_pass(git_blob_lookup(&old_blob, repo, &old_id)); cl_git_pass(git_blob_lookup(&new_blob, repo, &new_id)); diff --git a/tests/libgit2/diff/blob.c b/tests/libgit2/diff/blob.c index cb7e48b8d7d..235407512e1 100644 --- a/tests/libgit2/diff/blob.c +++ b/tests/libgit2/diff/blob.c @@ -45,11 +45,11 @@ void test_diff_blob__initialize(void) memset(&expected, 0, sizeof(expected)); /* tests/resources/attr/root_test4.txt */ - cl_git_pass(git_oid__fromstrn(&oid, "a0f7217a", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, "a0f7217a", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&d, g_repo, &oid, 8)); /* alien.png */ - cl_git_pass(git_oid__fromstrn(&oid, "edf3dcee", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, "edf3dcee", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&alien, g_repo, &oid, 8)); } @@ -86,10 +86,10 @@ void test_diff_blob__patch_with_freed_blobs(void) git_buf buf = GIT_BUF_INIT; /* tests/resources/attr/root_test1 */ - cl_git_pass(git_oid__fromstrn(&a_oid, "45141a79", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&a_oid, "45141a79", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4)); /* tests/resources/attr/root_test2 */ - cl_git_pass(git_oid__fromstrn(&b_oid, "4d713dc4", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&b_oid, "4d713dc4", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4)); cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, NULL)); @@ -110,15 +110,15 @@ void test_diff_blob__can_compare_text_blobs(void) git_oid a_oid, b_oid, c_oid; /* tests/resources/attr/root_test1 */ - cl_git_pass(git_oid__fromstrn(&a_oid, "45141a79", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&a_oid, "45141a79", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4)); /* tests/resources/attr/root_test2 */ - cl_git_pass(git_oid__fromstrn(&b_oid, "4d713dc4", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&b_oid, "4d713dc4", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4)); /* tests/resources/attr/root_test3 */ - cl_git_pass(git_oid__fromstrn(&c_oid, "c96bbb2c2557a832", 16, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&c_oid, "c96bbb2c2557a832", 16, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 16)); /* Doing the equivalent of a `git diff -U1` on these files */ @@ -201,15 +201,15 @@ void test_diff_blob__can_compare_text_blobs_with_patch(void) git_patch *p; /* tests/resources/attr/root_test1 */ - cl_git_pass(git_oid__fromstrn(&a_oid, "45141a79", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&a_oid, "45141a79", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8)); /* tests/resources/attr/root_test2 */ - cl_git_pass(git_oid__fromstrn(&b_oid, "4d713dc4", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&b_oid, "4d713dc4", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 8)); /* tests/resources/attr/root_test3 */ - cl_git_pass(git_oid__fromstrn(&c_oid, "c96bbb2c2557a832", 16, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&c_oid, "c96bbb2c2557a832", 16, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 16)); /* Doing the equivalent of a `git diff -U1` on these files */ @@ -475,7 +475,7 @@ void test_diff_blob__can_compare_two_binary_blobs(void) git_oid h_oid; /* heart.png */ - cl_git_pass(git_oid__fromstrn(&h_oid, "de863bff", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&h_oid, "de863bff", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&heart, g_repo, &h_oid, 8)); cl_git_pass(git_diff_blobs( @@ -543,7 +543,7 @@ void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void) opts.context_lines = 3; /* tests/resources/attr/root_test1 from commit f5b0af1 */ - cl_git_pass(git_oid__fromstrn(&old_d_oid, "fe773770", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&old_d_oid, "fe773770", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&old_d, g_repo, &old_d_oid, 8)); /* Test with default inter-hunk-context (not set) => default is 0 */ @@ -652,7 +652,7 @@ void test_diff_blob__can_compare_blob_to_buffer(void) const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n"; /* tests/resources/attr/root_test1 */ - cl_git_pass(git_oid__fromstrn(&a_oid, "45141a79", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&a_oid, "45141a79", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8)); /* diff from blob a to content of b */ @@ -694,7 +694,7 @@ void test_diff_blob__can_compare_blob_to_buffer_with_patch(void) size_t tc, ta, td; /* tests/resources/attr/root_test1 */ - cl_git_pass(git_oid__fromstrn(&a_oid, "45141a79", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&a_oid, "45141a79", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8)); /* diff from blob a to content of b */ @@ -773,10 +773,10 @@ void test_diff_blob__binary_data_comparisons(void) opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; - cl_git_pass(git_oid__fromstrn(&oid, "45141a79", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, "45141a79", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8)); - cl_git_pass(git_oid__fromstrn(&oid, "b435cd56", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, "b435cd56", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8)); /* non-binary to reference content */ @@ -879,11 +879,11 @@ void test_diff_blob__using_path_and_attributes(void) opts.context_lines = 0; opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; - cl_git_pass(git_oid__fromstrn(&oid, "45141a79", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, "45141a79", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8)); /* 20b: "Hello from the root\n" */ - cl_git_pass(git_oid__fromstrn(&oid, "b435cd56", 8, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, "b435cd56", 8, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8)); /* 33b: "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\n0123456789\n" */ diff --git a/tests/libgit2/diff/diff_helpers.c b/tests/libgit2/diff/diff_helpers.c index 6a76a92e7e8..79148f42c95 100644 --- a/tests/libgit2/diff/diff_helpers.c +++ b/tests/libgit2/diff/diff_helpers.c @@ -11,7 +11,7 @@ git_tree *resolve_commit_oid_to_tree( git_object *obj = NULL; git_tree *tree = NULL; - if (git_oid__fromstrn(&oid, partial_oid, len, GIT_OID_SHA1) == 0) + if (git_oid_from_prefix(&oid, partial_oid, len, GIT_OID_SHA1) == 0) cl_git_pass(git_object_lookup_prefix(&obj, repo, &oid, len, GIT_OBJECT_ANY)); cl_git_pass(git_object_peel((git_object **) &tree, obj, GIT_OBJECT_TREE)); diff --git a/tests/libgit2/diff/format_email.c b/tests/libgit2/diff/format_email.c index 2726edb0ddd..614fcbc114c 100644 --- a/tests/libgit2/diff/format_email.c +++ b/tests/libgit2/diff/format_email.c @@ -28,7 +28,7 @@ static void assert_email_match( git_diff *diff = NULL; git_buf buf = GIT_BUF_INIT; - git_oid__fromstr(&oid, oidstr, GIT_OID_SHA1); + git_oid_from_string(&oid, oidstr, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); @@ -228,7 +228,7 @@ void test_diff_format_email__multiple(void) "\n"; - git_oid__fromstr(&oid, "10808fe9c9be5a190c0ba68d1a002233fb363508", GIT_OID_SHA1); + git_oid_from_string(&oid, "10808fe9c9be5a190c0ba68d1a002233fb363508", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); opts.id = git_commit_id(commit); @@ -245,7 +245,7 @@ void test_diff_format_email__multiple(void) diff = NULL; commit = NULL; - git_oid__fromstr(&oid, "873806f6f27e631eb0b23e4b56bea2bfac14a373", GIT_OID_SHA1); + git_oid_from_string(&oid, "873806f6f27e631eb0b23e4b56bea2bfac14a373", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); opts.id = git_commit_id(commit); @@ -324,7 +324,7 @@ void test_diff_format_email__invalid_no(void) git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; git_buf buf = GIT_BUF_INIT; - git_oid__fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", GIT_OID_SHA1); + git_oid_from_string(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); diff --git a/tests/libgit2/diff/index.c b/tests/libgit2/diff/index.c index c6b7037e4c0..de2280070f6 100644 --- a/tests/libgit2/diff/index.c +++ b/tests/libgit2/diff/index.c @@ -186,9 +186,9 @@ static void do_conflicted_diff(diff_expects *exp, unsigned long flags) ancestor.path = ours.path = theirs.path = "staged_changes"; ancestor.mode = ours.mode = theirs.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&ancestor.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); - git_oid__fromstr(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); - git_oid__fromstr(&theirs.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); + git_oid_from_string(&ancestor.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); + git_oid_from_string(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); + git_oid_from_string(&theirs.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(index, &ancestor, &ours, &theirs)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, index, &opts)); @@ -256,7 +256,7 @@ void test_diff_index__not_in_head_conflicted(void) theirs.path = "file_not_in_head"; theirs.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&theirs.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); + git_oid_from_string(&theirs.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(index, NULL, NULL, &theirs)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, index, NULL)); diff --git a/tests/libgit2/diff/patchid.c b/tests/libgit2/diff/patchid.c index 91807e7b747..2cd9473f247 100644 --- a/tests/libgit2/diff/patchid.c +++ b/tests/libgit2/diff/patchid.c @@ -7,7 +7,7 @@ static void verify_patch_id(const char *diff_content, const char *expected_id) git_oid expected_oid, actual_oid; git_diff *diff; - cl_git_pass(git_oid__fromstr(&expected_oid, expected_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, expected_id, GIT_OID_SHA1)); cl_git_pass(diff_from_buffer(&diff, diff_content, strlen(diff_content))); cl_git_pass(git_diff_patchid(&actual_oid, diff, NULL)); diff --git a/tests/libgit2/diff/rename.c b/tests/libgit2/diff/rename.c index 61a2f839cb3..a5bbfe447bc 100644 --- a/tests/libgit2/diff/rename.c +++ b/tests/libgit2/diff/rename.c @@ -574,7 +574,7 @@ void test_diff_rename__working_directory_changes(void) /* again with exact match blob */ - cl_git_pass(git_oid__fromstr(&id, blobsha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, blobsha, GIT_OID_SHA1)); cl_git_pass(git_blob_lookup(&blob, g_repo, &id)); cl_git_pass(git_str_set( &content, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob))); diff --git a/tests/libgit2/diff/stats.c b/tests/libgit2/diff/stats.c index 7af89155084..f808136220a 100644 --- a/tests/libgit2/diff/stats.c +++ b/tests/libgit2/diff/stats.c @@ -27,7 +27,7 @@ static void diff_stats_from_commit_oid( git_commit *commit; git_diff *diff; - git_oid__fromstr(&oid, oidstr, GIT_OID_SHA1); + git_oid_from_string(&oid, oidstr, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); cl_git_pass(git_diff__commit(&diff, _repo, commit, NULL)); if (rename) diff --git a/tests/libgit2/diff/workdir.c b/tests/libgit2/diff/workdir.c index c2a0c79283e..602460908bb 100644 --- a/tests/libgit2/diff/workdir.c +++ b/tests/libgit2/diff/workdir.c @@ -86,11 +86,11 @@ void test_diff_workdir__to_index_with_conflicts(void) /* Adding an entry that represents a rename gets two files in conflict */ our_entry.path = "subdir/modified_file"; our_entry.mode = 0100644; - git_oid__fromstr(&our_entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); their_entry.path = "subdir/rename_conflict"; their_entry.mode = 0100644; - git_oid__fromstr(&their_entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_conflict_add(index, NULL, &our_entry, &their_entry)); @@ -2015,9 +2015,9 @@ void test_diff_workdir__to_index_conflicted(void) { ancestor.path = ours.path = theirs.path = "_file"; ancestor.mode = ours.mode = theirs.mode = 0100644; - git_oid__fromstr(&ancestor.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); - git_oid__fromstr(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); - git_oid__fromstr(&theirs.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); + git_oid_from_string(&ancestor.id, "d427e0b2e138501a3d15cc376077a3631e15bd46", GIT_OID_SHA1); + git_oid_from_string(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); + git_oid_from_string(&theirs.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(index, &ancestor, &ours, &theirs)); cl_git_pass(git_diff_tree_to_index(&diff1, g_repo, a, index, NULL)); diff --git a/tests/libgit2/email/create.c b/tests/libgit2/email/create.c index cd3ccf7002b..1a69dc4f267 100644 --- a/tests/libgit2/email/create.c +++ b/tests/libgit2/email/create.c @@ -25,7 +25,7 @@ static void email_for_commit( git_commit *commit = NULL; git_diff *diff = NULL; - git_oid__fromstr(&oid, commit_id, GIT_OID_SHA1); + git_oid_from_string(&oid, commit_id, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); @@ -324,7 +324,7 @@ void test_email_create__custom_summary_and_body(void) opts.subject_prefix = "PPPPPATCH"; - git_oid__fromstr(&oid, "627e7e12d87e07a83fad5b6bfa25e86ead4a5270", GIT_OID_SHA1); + git_oid_from_string(&oid, "627e7e12d87e07a83fad5b6bfa25e86ead4a5270", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); cl_git_pass(git_email_create_from_diff(&buf, diff, 2, 4, &oid, summary, body, git_commit_author(commit), &opts)); diff --git a/tests/libgit2/fetch/local.c b/tests/libgit2/fetch/local.c index 5d2417f1cd3..ca307a881e8 100644 --- a/tests/libgit2/fetch/local.c +++ b/tests/libgit2/fetch/local.c @@ -26,7 +26,7 @@ void test_fetch_local__defaults(void) cl_fixture("testrepo.git"))); cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL)); - git_oid__fromstr(&expected_id, "258f0e2a959a364e40ed6603d5d44fbb24765b10", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "258f0e2a959a364e40ed6603d5d44fbb24765b10", GIT_OID_SHA1); cl_git_pass(git_revparse_single(&obj, repo, "refs/remotes/test/haacked")); cl_assert_equal_oid(&expected_id, git_object_id(obj)); @@ -47,7 +47,7 @@ void test_fetch_local__reachable_commit(void) refspecs.strings = &refspec; refspecs.count = 1; - git_oid__fromstr(&expected_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); cl_git_pass(git_remote_create(&remote, repo, "test", cl_fixture("testrepo.git"))); diff --git a/tests/libgit2/fetchhead/nonetwork.c b/tests/libgit2/fetchhead/nonetwork.c index e92b85fa53c..ac86d611af4 100644 --- a/tests/libgit2/fetchhead/nonetwork.c +++ b/tests/libgit2/fetchhead/nonetwork.c @@ -29,7 +29,7 @@ static void populate_fetchhead(git_vector *out, git_repository *repo) git_fetchhead_ref *fetchhead_ref; git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 1, @@ -37,7 +37,7 @@ static void populate_fetchhead(git_vector *out, git_repository *repo) "https://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "0966a434eb1a025db6b71485ab63a3bfbea520b6", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, @@ -45,7 +45,7 @@ static void populate_fetchhead(git_vector *out, git_repository *repo) "https://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, @@ -53,7 +53,7 @@ static void populate_fetchhead(git_vector *out, git_repository *repo) "https://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "d96c4e80345534eccee5ac7b07fc7603b56124cb", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, @@ -61,7 +61,7 @@ static void populate_fetchhead(git_vector *out, git_repository *repo) "https://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "55a1a760df4b86a02094a904dfa511deb5655905", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, @@ -69,7 +69,7 @@ static void populate_fetchhead(git_vector *out, git_repository *repo) "https://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "8f50ba15d49353813cc6e20298002c0d17b0a9ee", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, @@ -176,7 +176,7 @@ static int read_old_style_cb(const char *name, const char *url, GIT_UNUSED(payload); - git_oid__fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1); + git_oid_from_string(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1); cl_assert(name == NULL); cl_assert(url == NULL); @@ -203,7 +203,7 @@ static int read_type_missing(const char *ref_name, const char *remote_url, GIT_UNUSED(payload); - git_oid__fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1); + git_oid_from_string(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1); cl_assert_equal_s("name", ref_name); cl_assert_equal_s("remote_url", remote_url); @@ -230,7 +230,7 @@ static int read_name_missing(const char *ref_name, const char *remote_url, GIT_UNUSED(payload); - git_oid__fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1); + git_oid_from_string(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1); cl_assert(ref_name == NULL); cl_assert_equal_s("remote_url", remote_url); @@ -534,13 +534,13 @@ void test_fetchhead_nonetwork__credentials_are_stripped(void) git_fetchhead_ref *ref; git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&ref, &oid, 0, "refs/tags/commit_tree", "http://foo:bar@github.com/libgit2/TestGitRepository")); cl_assert_equal_s(ref->remote_url, "http://github.com/libgit2/TestGitRepository"); git_fetchhead_ref_free(ref); - cl_git_pass(git_oid__fromstr(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0", GIT_OID_SHA1)); cl_git_pass(git_fetchhead_ref_create(&ref, &oid, 0, "refs/tags/commit_tree", "https://foo:bar@github.com/libgit2/TestGitRepository")); cl_assert_equal_s(ref->remote_url, "https://github.com/libgit2/TestGitRepository"); diff --git a/tests/libgit2/filter/bare.c b/tests/libgit2/filter/bare.c index f53cfcb4919..afbccd73228 100644 --- a/tests/libgit2/filter/bare.c +++ b/tests/libgit2/filter/bare.c @@ -140,7 +140,7 @@ void test_filter_bare__from_specific_commit_one(void) opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES; opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT; - cl_git_pass(git_oid__fromstr(&opts.attr_commit_id, "b8986fec0f7bde90f78ac72706e782d82f24f2f0", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&opts.attr_commit_id, "b8986fec0f7bde90f78ac72706e782d82f24f2f0", GIT_OID_SHA1)); cl_git_pass(git_revparse_single( (git_object **)&blob, g_repo, "055c872")); /* ident */ @@ -165,7 +165,7 @@ void test_filter_bare__from_specific_commit_with_no_attributes_file(void) opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES; opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT; - cl_git_pass(git_oid__fromstr(&opts.attr_commit_id, "5afb6a14a864e30787857dd92af837e8cdd2cb1b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&opts.attr_commit_id, "5afb6a14a864e30787857dd92af837e8cdd2cb1b", GIT_OID_SHA1)); cl_git_pass(git_revparse_single( (git_object **)&blob, g_repo, "799770d")); /* all-lf */ diff --git a/tests/libgit2/grafts/basic.c b/tests/libgit2/grafts/basic.c index 30c87f908af..ad208b7f2a1 100644 --- a/tests/libgit2/grafts/basic.c +++ b/tests/libgit2/grafts/basic.c @@ -25,10 +25,10 @@ void test_grafts_basic__graft_add(void) cl_git_pass(git_grafts_new(&grafts, GIT_OID_SHA1)); cl_assert(oid1 = git_array_alloc(parents)); - cl_git_pass(git_oid__fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9", GIT_OID_SHA1)); git_oid_cpy(oid1, &oid_src); - git_oid__fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1); + git_oid_from_string(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1); cl_git_pass(git_grafts_add(grafts, &oid_src, parents)); git_array_clear(parents); @@ -73,17 +73,17 @@ void test_grafts_basic__grafted_objects(void) git_oid oid; git_commit *commit; - cl_git_pass(git_oid__fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_assert_equal_i(1, git_commit_parentcount(commit)); git_commit_free(commit); - cl_git_pass(git_oid__fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_assert_equal_i(1, git_commit_parentcount(commit)); git_commit_free(commit); - cl_git_pass(git_oid__fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_assert_equal_i(4, git_commit_parentcount(commit)); git_commit_free(commit); diff --git a/tests/libgit2/grafts/parse.c b/tests/libgit2/grafts/parse.c index 3b0618a1d99..f268a2a1712 100644 --- a/tests/libgit2/grafts/parse.c +++ b/tests/libgit2/grafts/parse.c @@ -46,14 +46,14 @@ static void assert_graft_contains(git_grafts *grafts, const char *graft, size_t va_list ap; size_t i = 0; - cl_git_pass(git_oid__fromstr(&oid, graft, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, graft, GIT_OID_SHA1)); cl_git_pass(git_grafts_get(&commit, grafts, &oid)); cl_assert_equal_oid(&commit->oid, &oid); cl_assert_equal_i(commit->parents.size, n); va_start(ap, n); while (i < n) { - cl_git_pass(git_oid__fromstr(&oid, va_arg(ap, const char *), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, va_arg(ap, const char *), GIT_OID_SHA1)); cl_assert_equal_oid(&commit->parents.ptr[i], &oid); i++; } diff --git a/tests/libgit2/grafts/shallow.c b/tests/libgit2/grafts/shallow.c index 349e9e9b2fd..ceb56ed5a7c 100644 --- a/tests/libgit2/grafts/shallow.c +++ b/tests/libgit2/grafts/shallow.c @@ -9,7 +9,7 @@ static git_oid g_shallow_oid; void test_grafts_shallow__initialize(void) { - cl_git_pass(git_oid__fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); } void test_grafts_shallow__cleanup(void) @@ -61,7 +61,7 @@ void test_grafts_shallow__cache_clearing(void) git_grafts *grafts; git_oid tmp_oid; - cl_git_pass(git_oid__fromstr(&tmp_oid, "0000000000000000000000000000000000000000", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tmp_oid, "0000000000000000000000000000000000000000", GIT_OID_SHA1)); g_repo = cl_git_sandbox_init("shallow.git"); cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo)); diff --git a/tests/libgit2/graph/ahead_behind.c b/tests/libgit2/graph/ahead_behind.c index dd828c5f37b..66db34b0f55 100644 --- a/tests/libgit2/graph/ahead_behind.c +++ b/tests/libgit2/graph/ahead_behind.c @@ -10,7 +10,7 @@ void test_graph_ahead_behind__initialize(void) git_oid oid; cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); - cl_git_pass(git_oid__fromstr(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); } @@ -29,8 +29,8 @@ void test_graph_ahead_behind__returns_correct_result(void) git_oid oid2; git_commit *other; - cl_git_pass(git_oid__fromstr(&oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&oid2, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid2, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &oid, &oid2)); cl_assert_equal_sz(2, ahead); diff --git a/tests/libgit2/graph/commitgraph.c b/tests/libgit2/graph/commitgraph.c index 363806bd9e9..4000882d713 100644 --- a/tests/libgit2/graph/commitgraph.c +++ b/tests/libgit2/graph/commitgraph.c @@ -19,28 +19,28 @@ void test_graph_commitgraph__parse(void) cl_git_pass(git_commit_graph_file_open(&file, git_str_cstr(&commit_graph_path), GIT_OID_SHA1)); cl_assert_equal_i(git_commit_graph_file_needs_refresh(file, git_str_cstr(&commit_graph_path)), 0); - cl_git_pass(git_oid__fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_find(&e, file, &id, GIT_OID_SHA1_HEXSIZE)); cl_assert_equal_oid(&e.sha1, &id); - cl_git_pass(git_oid__fromstr(&id, "418382dff1ffb8bdfba833f4d8bbcde58b1e7f47", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "418382dff1ffb8bdfba833f4d8bbcde58b1e7f47", GIT_OID_SHA1)); cl_assert_equal_oid(&e.tree_oid, &id); cl_assert_equal_i(e.generation, 1); cl_assert_equal_i(e.commit_time, UINT64_C(1273610423)); cl_assert_equal_i(e.parent_count, 0); - cl_git_pass(git_oid__fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_find(&e, file, &id, GIT_OID_SHA1_HEXSIZE)); cl_assert_equal_oid(&e.sha1, &id); cl_assert_equal_i(e.generation, 5); cl_assert_equal_i(e.commit_time, UINT64_C(1274813907)); cl_assert_equal_i(e.parent_count, 2); - cl_git_pass(git_oid__fromstr(&id, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 0)); cl_assert_equal_oid(&parent.sha1, &id); cl_assert_equal_i(parent.generation, 4); - cl_git_pass(git_oid__fromstr(&id, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 1)); cl_assert_equal_oid(&parent.sha1, &id); cl_assert_equal_i(parent.generation, 3); @@ -62,26 +62,26 @@ void test_graph_commitgraph__parse_octopus_merge(void) cl_git_pass(git_str_joinpath(&commit_graph_path, git_repository_path(repo), "objects/info/commit-graph")); cl_git_pass(git_commit_graph_file_open(&file, git_str_cstr(&commit_graph_path), GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&id, "d71c24b3b113fd1d1909998c5bfe33b86a65ee03", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "d71c24b3b113fd1d1909998c5bfe33b86a65ee03", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_find(&e, file, &id, GIT_OID_SHA1_HEXSIZE)); cl_assert_equal_oid(&e.sha1, &id); - cl_git_pass(git_oid__fromstr(&id, "348f16ffaeb73f319a75cec5b16a0a47d2d5e27c", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "348f16ffaeb73f319a75cec5b16a0a47d2d5e27c", GIT_OID_SHA1)); cl_assert_equal_oid(&e.tree_oid, &id); cl_assert_equal_i(e.generation, 7); cl_assert_equal_i(e.commit_time, UINT64_C(1447083009)); cl_assert_equal_i(e.parent_count, 3); - cl_git_pass(git_oid__fromstr(&id, "ad2ace9e15f66b3d1138922e6ffdc3ea3f967fa6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "ad2ace9e15f66b3d1138922e6ffdc3ea3f967fa6", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 0)); cl_assert_equal_oid(&parent.sha1, &id); cl_assert_equal_i(parent.generation, 6); - cl_git_pass(git_oid__fromstr(&id, "483065df53c0f4a02cdc6b2910b05d388fc17ffb", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "483065df53c0f4a02cdc6b2910b05d388fc17ffb", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 1)); cl_assert_equal_oid(&parent.sha1, &id); cl_assert_equal_i(parent.generation, 2); - cl_git_pass(git_oid__fromstr(&id, "815b5a1c80ca749d705c7aa0cb294a00cbedd340", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "815b5a1c80ca749d705c7aa0cb294a00cbedd340", GIT_OID_SHA1)); cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 2)); cl_assert_equal_oid(&parent.sha1, &id); cl_assert_equal_i(parent.generation, 6); diff --git a/tests/libgit2/graph/descendant_of.c b/tests/libgit2/graph/descendant_of.c index b6dffae0671..594066c42b6 100644 --- a/tests/libgit2/graph/descendant_of.c +++ b/tests/libgit2/graph/descendant_of.c @@ -9,7 +9,7 @@ void test_graph_descendant_of__initialize(void) cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); - git_oid__fromstr(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); + git_oid_from_string(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); } @@ -50,6 +50,6 @@ void test_graph_descendant_of__nopath(void) { git_oid oid; - git_oid__fromstr(&oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); + git_oid_from_string(&oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); cl_assert_equal_i(0, git_graph_descendant_of(_repo, git_commit_id(commit), &oid)); } diff --git a/tests/libgit2/graph/reachable_from_any.c b/tests/libgit2/graph/reachable_from_any.c index 04706fbb456..161b640020f 100644 --- a/tests/libgit2/graph/reachable_from_any.c +++ b/tests/libgit2/graph/reachable_from_any.c @@ -17,7 +17,7 @@ void test_graph_reachable_from_any__initialize(void) repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_oid__fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); + git_oid_from_string(&oid, "539bd011c4822c560c1d17cab095006b7a10f707", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); git_commit_free(commit); diff --git a/tests/libgit2/index/add.c b/tests/libgit2/index/add.c index 588a2ad148c..d4290019b6a 100644 --- a/tests/libgit2/index/add.c +++ b/tests/libgit2/index/add.c @@ -28,7 +28,7 @@ static void test_add_entry( { git_index_entry entry = {{0}}; - cl_git_pass(git_oid__fromstr(&entry.id, idstr, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, idstr, GIT_OID_SHA1)); entry.path = mode == GIT_FILEMODE_TREE ? "test_folder" : "test_file"; entry.mode = mode; @@ -90,11 +90,11 @@ void test_index_add__two_slash_prefixed(void) orig_count = git_index_entrycount(g_index); - cl_git_pass(git_oid__fromstr(&one.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); one.path = "/a"; one.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&two.id, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two.id, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc", GIT_OID_SHA1)); two.path = "/a"; two.mode = GIT_FILEMODE_BLOB; diff --git a/tests/libgit2/index/bypath.c b/tests/libgit2/index/bypath.c index 15c11af5f0b..ef105462d49 100644 --- a/tests/libgit2/index/bypath.c +++ b/tests/libgit2/index/bypath.c @@ -131,7 +131,7 @@ void test_index_bypath__add_honors_existing_case_2(void) clar__skip(); dummy.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b", GIT_OID_SHA1)); /* note that `git_index_add` does no checking to canonical directories */ dummy.path = "Just_a_dir/file0.txt"; @@ -187,7 +187,7 @@ void test_index_bypath__add_honors_existing_case_3(void) clar__skip(); dummy.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b", GIT_OID_SHA1)); dummy.path = "just_a_dir/filea.txt"; cl_git_pass(git_index_add(g_idx, &dummy)); @@ -218,7 +218,7 @@ void test_index_bypath__add_honors_existing_case_4(void) clar__skip(); dummy.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&dummy.id, "f990a25a74d1a8281ce2ab018ea8df66795cd60b", GIT_OID_SHA1)); dummy.path = "just_a_dir/a/b/c/d/e/file1.txt"; cl_git_pass(git_index_add(g_idx, &dummy)); diff --git a/tests/libgit2/index/cache.c b/tests/libgit2/index/cache.c index 1d0f8a3ebf2..7207308414c 100644 --- a/tests/libgit2/index/cache.c +++ b/tests/libgit2/index/cache.c @@ -26,7 +26,7 @@ void test_index_cache__write_extension_at_root(void) cl_git_pass(git_index_open_ext(&index, index_file, NULL)); cl_assert(index->tree == NULL); - cl_git_pass(git_oid__fromstr(&id, tree_id_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, tree_id_str, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_git_pass(git_index_read_tree(index, tree)); git_tree_free(tree); @@ -59,7 +59,7 @@ void test_index_cache__write_extension_invalidated_root(void) cl_git_pass(git_index_open_ext(&index, index_file, &index_opts)); cl_assert(index->tree == NULL); - cl_git_pass(git_oid__fromstr(&id, tree_id_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, tree_id_str, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_git_pass(git_index_read_tree(index, tree)); git_tree_free(tree); @@ -101,7 +101,7 @@ void test_index_cache__read_tree_no_children(void) cl_git_pass(git_index_new(&index)); cl_assert(index->tree == NULL); - cl_git_pass(git_oid__fromstr(&id, "45dd856fdd4d89b884c340ba0e047752d9b085d6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "45dd856fdd4d89b884c340ba0e047752d9b085d6", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_git_pass(git_index_read_tree(index, tree)); git_tree_free(tree); @@ -114,7 +114,7 @@ void test_index_cache__read_tree_no_children(void) memset(&entry, 0x0, sizeof(git_index_entry)); entry.path = "new.txt"; entry.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&entry.id, "d4bcc68acd4410bf836a39f20afb2c2ece09584e", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "d4bcc68acd4410bf836a39f20afb2c2ece09584e", GIT_OID_SHA1); cl_git_pass(git_index_add(index, &entry)); cl_assert_equal_i(-1, index->tree->entry_count); @@ -135,7 +135,7 @@ void test_index_cache__two_levels(void) memset(&entry, 0x0, sizeof(entry)); entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&entry.id, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); entry.path = "top-level.txt"; cl_git_pass(git_index_add(index, &entry)); @@ -159,7 +159,7 @@ void test_index_cache__two_levels(void) cl_assert(git_tree_cache_get(index->tree, "subdir")); entry.path = "top-level.txt"; - cl_git_pass(git_oid__fromstr(&entry.id, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc", GIT_OID_SHA1)); cl_git_pass(git_index_add(index, &entry)); /* writ out the index after we invalidate the root */ @@ -194,7 +194,7 @@ void test_index_cache__read_tree_children(void) memset(&entry, 0x0, sizeof(git_index_entry)); entry.path = "top-level"; entry.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); cl_git_pass(git_index_add(index, &entry)); @@ -220,7 +220,7 @@ void test_index_cache__read_tree_children(void) /* override with a slightly different id, also dummy */ entry.path = "subdir/some-file"; - git_oid__fromstr(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); cl_git_pass(git_index_add(index, &entry)); cl_assert_equal_i(-1, index->tree->entry_count); diff --git a/tests/libgit2/index/conflicts.c b/tests/libgit2/index/conflicts.c index 353886f7b53..cecdc5d3303 100644 --- a/tests/libgit2/index/conflicts.c +++ b/tests/libgit2/index/conflicts.c @@ -37,17 +37,17 @@ void test_index_conflicts__add(void) ancestor_entry.path = "test-one.txt"; ancestor_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1); - git_oid__fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); our_entry.path = "test-one.txt"; our_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 2); - git_oid__fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); their_entry.path = "test-one.txt"; their_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 2); - git_oid__fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); @@ -68,17 +68,17 @@ void test_index_conflicts__add_fixes_incorrect_stage(void) ancestor_entry.path = "test-one.txt"; ancestor_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 3); - git_oid__fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); our_entry.path = "test-one.txt"; our_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 1); - git_oid__fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); their_entry.path = "test-one.txt"; their_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 2); - git_oid__fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); @@ -111,17 +111,17 @@ void test_index_conflicts__add_detects_invalid_filemode(void) ancestor_entry.path = "test-one.txt"; ancestor_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 3); - git_oid__fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); our_entry.path = "test-one.txt"; our_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 1); - git_oid__fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); their_entry.path = "test-one.txt"; their_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 2); - git_oid__fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); /* Corrupt the conflict entry's mode */ conflict_entry[i]->mode = 027431745; @@ -151,17 +151,17 @@ void test_index_conflicts__add_removes_stage_zero(void) ancestor_entry.path = "test-one.txt"; ancestor_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 3); - git_oid__fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); our_entry.path = "test-one.txt"; our_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 1); - git_oid__fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); their_entry.path = "test-one.txt"; their_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 2); - git_oid__fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); @@ -189,13 +189,13 @@ void test_index_conflicts__get(void) cl_assert_equal_s("conflicts-one.txt", conflict_entry[0]->path); - git_oid__fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[0]->id); - git_oid__fromstr(&oid, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[1]->id); - git_oid__fromstr(&oid, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[2]->id); cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], @@ -203,13 +203,13 @@ void test_index_conflicts__get(void) cl_assert_equal_s("conflicts-two.txt", conflict_entry[0]->path); - git_oid__fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[0]->id); - git_oid__fromstr(&oid, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[1]->id); - git_oid__fromstr(&oid, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[2]->id); } @@ -223,29 +223,29 @@ void test_index_conflicts__iterate(void) cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator)); - git_oid__fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[0]->id); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); - git_oid__fromstr(&oid, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[1]->id); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); - git_oid__fromstr(&oid, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[2]->id); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator)); - git_oid__fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[0]->id); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); - git_oid__fromstr(&oid, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[1]->id); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); - git_oid__fromstr(&oid, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[2]->id); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); @@ -357,7 +357,7 @@ void test_index_conflicts__partial(void) ancestor_entry.path = "test-one.txt"; ancestor_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1); - git_oid__fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, NULL, NULL)); cl_assert(git_index_entrycount(repo_index) == 9); @@ -387,17 +387,17 @@ void test_index_conflicts__case_matters(void) ancestor_entry.path = upper_case; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, GIT_INDEX_STAGE_ANCESTOR); - git_oid__fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); ancestor_entry.mode = GIT_FILEMODE_BLOB; our_entry.path = upper_case; GIT_INDEX_ENTRY_STAGE_SET(&our_entry, GIT_INDEX_STAGE_OURS); - git_oid__fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); our_entry.mode = GIT_FILEMODE_BLOB; their_entry.path = upper_case; GIT_INDEX_ENTRY_STAGE_SET(&their_entry, GIT_INDEX_STAGE_THEIRS); - git_oid__fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); their_entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_conflict_add(repo_index, @@ -405,17 +405,17 @@ void test_index_conflicts__case_matters(void) ancestor_entry.path = mixed_case; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, GIT_INDEX_STAGE_ANCESTOR); - git_oid__fromstr(&ancestor_entry.id, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); ancestor_entry.mode = GIT_FILEMODE_BLOB; our_entry.path = mixed_case; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, GIT_INDEX_STAGE_ANCESTOR); - git_oid__fromstr(&our_entry.id, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); ancestor_entry.mode = GIT_FILEMODE_BLOB; their_entry.path = mixed_case; GIT_INDEX_ENTRY_STAGE_SET(&their_entry, GIT_INDEX_STAGE_THEIRS); - git_oid__fromstr(&their_entry.id, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); their_entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_conflict_add(repo_index, @@ -434,29 +434,29 @@ void test_index_conflicts__case_matters(void) correct_case = upper_case; cl_assert_equal_s(correct_case, conflict_entry[0]->path); - git_oid__fromstr(&oid, ignorecase ? CONFLICTS_TWO_ANCESTOR_OID : CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ignorecase ? CONFLICTS_TWO_ANCESTOR_OID : CONFLICTS_ONE_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[0]->id); cl_assert_equal_s(correct_case, conflict_entry[1]->path); - git_oid__fromstr(&oid, ignorecase ? CONFLICTS_TWO_OUR_OID : CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ignorecase ? CONFLICTS_TWO_OUR_OID : CONFLICTS_ONE_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[1]->id); cl_assert_equal_s(correct_case, conflict_entry[2]->path); - git_oid__fromstr(&oid, ignorecase ? CONFLICTS_TWO_THEIR_OID : CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ignorecase ? CONFLICTS_TWO_THEIR_OID : CONFLICTS_ONE_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[2]->id); cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, mixed_case)); cl_assert_equal_s(mixed_case, conflict_entry[0]->path); - git_oid__fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[0]->id); cl_assert_equal_s(mixed_case, conflict_entry[1]->path); - git_oid__fromstr(&oid, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[1]->id); cl_assert_equal_s(mixed_case, conflict_entry[2]->path); - git_oid__fromstr(&oid, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, CONFLICTS_TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&oid, &conflict_entry[2]->id); } diff --git a/tests/libgit2/index/crlf.c b/tests/libgit2/index/crlf.c index 0a7d51aed4d..e1788f18a7c 100644 --- a/tests/libgit2/index/crlf.c +++ b/tests/libgit2/index/crlf.c @@ -243,7 +243,7 @@ void test_index_crlf__autocrlf_false_no_attrs(void) cl_git_pass(git_index_add_bypath(g_index, "newfile.txt")); entry = git_index_get_bypath(g_index, "newfile.txt", 0); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, (GIT_EOL_NATIVE == GIT_EOL_CRLF) ? FILE_OID_CRLF : FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); @@ -262,7 +262,7 @@ void test_index_crlf__autocrlf_true_no_attrs(void) cl_git_pass(git_index_add_bypath(g_index, "newfile.txt")); entry = git_index_get_bypath(g_index, "newfile.txt", 0); - cl_git_pass(git_oid__fromstr(&oid, FILE_OID_LF, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); } @@ -279,7 +279,7 @@ void test_index_crlf__autocrlf_input_no_attrs(void) cl_git_pass(git_index_add_bypath(g_index, "newfile.txt")); entry = git_index_get_bypath(g_index, "newfile.txt", 0); - cl_git_pass(git_oid__fromstr(&oid, FILE_OID_LF, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); } @@ -298,7 +298,7 @@ void test_index_crlf__autocrlf_false_text_auto_attr(void) cl_git_pass(git_index_add_bypath(g_index, "newfile.txt")); entry = git_index_get_bypath(g_index, "newfile.txt", 0); - cl_git_pass(git_oid__fromstr(&oid, FILE_OID_LF, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); } @@ -317,7 +317,7 @@ void test_index_crlf__autocrlf_true_text_auto_attr(void) cl_git_pass(git_index_add_bypath(g_index, "newfile.txt")); entry = git_index_get_bypath(g_index, "newfile.txt", 0); - cl_git_pass(git_oid__fromstr(&oid, FILE_OID_LF, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); } @@ -336,7 +336,7 @@ void test_index_crlf__autocrlf_input_text_auto_attr(void) cl_git_pass(git_index_add_bypath(g_index, "newfile.txt")); entry = git_index_get_bypath(g_index, "newfile.txt", 0); - cl_git_pass(git_oid__fromstr(&oid, FILE_OID_LF, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); } @@ -356,7 +356,7 @@ void test_index_crlf__safecrlf_true_autocrlf_input_text_auto_attr(void) entry = git_index_get_bypath(g_index, "newfile.txt", 0); cl_assert(entry); - cl_git_pass(git_oid__fromstr(&oid, FILE_OID_LF, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); cl_git_mkfile("./crlf/newfile2.txt", FILE_CONTENTS_CRLF); @@ -377,7 +377,7 @@ void test_index_crlf__safecrlf_true_autocrlf_input_text__no_attr(void) entry = git_index_get_bypath(g_index, "newfile.txt", 0); cl_assert(entry); - cl_git_pass(git_oid__fromstr(&oid, FILE_OID_LF, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, FILE_OID_LF, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); cl_git_mkfile("./crlf/newfile2.txt", FILE_CONTENTS_CRLF); diff --git a/tests/libgit2/index/names.c b/tests/libgit2/index/names.c index 2a41100aac2..1121021e462 100644 --- a/tests/libgit2/index/names.c +++ b/tests/libgit2/index/names.c @@ -42,21 +42,21 @@ static void index_add_conflicts(void) entry.path = conflict[0]; entry.mode = GIT_FILEMODE_BLOB; GIT_INDEX_ENTRY_STAGE_SET(&entry, GIT_INDEX_STAGE_ANCESTOR); - git_oid__fromstr(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81", GIT_OID_SHA1); cl_git_pass(git_index_add(repo_index, &entry)); /* ours */ entry.path = conflict[1]; entry.mode = GIT_FILEMODE_BLOB; GIT_INDEX_ENTRY_STAGE_SET(&entry, GIT_INDEX_STAGE_OURS); - git_oid__fromstr(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81", GIT_OID_SHA1); cl_git_pass(git_index_add(repo_index, &entry)); /* theirs */ entry.path = conflict[2]; entry.mode = GIT_FILEMODE_BLOB; GIT_INDEX_ENTRY_STAGE_SET(&entry, GIT_INDEX_STAGE_THEIRS); - git_oid__fromstr(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81", GIT_OID_SHA1); cl_git_pass(git_index_add(repo_index, &entry)); } } diff --git a/tests/libgit2/index/read_index.c b/tests/libgit2/index/read_index.c index caaf40f7967..fbd671c2fe1 100644 --- a/tests/libgit2/index/read_index.c +++ b/tests/libgit2/index/read_index.c @@ -52,7 +52,7 @@ void test_index_read_index__maintains_stat_cache(void) /* add a new entry that will not have stat data */ memset(&new_entry, 0, sizeof(git_index_entry)); new_entry.path = "Hello"; - git_oid__fromstr(&new_entry.id, "0123456789012345678901234567890123456789", GIT_OID_SHA1); + git_oid_from_string(&new_entry.id, "0123456789012345678901234567890123456789", GIT_OID_SHA1); new_entry.file_size = 1234; new_entry.mode = 0100644; cl_git_pass(git_index_add(new_index, &new_entry)); @@ -82,7 +82,7 @@ static bool roundtrip_with_read_index(const char *tree_idstr) git_tree *tree; git_index *tree_index; - cl_git_pass(git_oid__fromstr(&tree_id, tree_idstr, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tree_id, tree_idstr, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); cl_git_pass(git_index_new(&tree_index)); cl_git_pass(git_index_read_tree(tree_index, tree)); @@ -117,7 +117,7 @@ void test_index_read_index__read_and_writes(void) index_opts.oid_type = GIT_OID_SHA1; - cl_git_pass(git_oid__fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); cl_git_pass(git_index_new_ext(&tree_index, &index_opts)); cl_git_pass(git_index_read_tree(tree_index, tree)); @@ -154,17 +154,17 @@ static void add_conflicts(git_index *index, const char *filename) ancestor_entry.path = filename; ancestor_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1); - git_oid__fromstr(&ancestor_entry.id, ancestor_ids[conflict_idx], GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, ancestor_ids[conflict_idx], GIT_OID_SHA1); our_entry.path = filename; our_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 2); - git_oid__fromstr(&our_entry.id, our_ids[conflict_idx], GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, our_ids[conflict_idx], GIT_OID_SHA1); their_entry.path = filename; their_entry.mode = 0100644; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 2); - git_oid__fromstr(&their_entry.id, their_ids[conflict_idx], GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, their_ids[conflict_idx], GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(index, &ancestor_entry, &our_entry, &their_entry)); @@ -178,7 +178,7 @@ void test_index_read_index__handles_conflicts(void) git_index_conflict_iterator *conflict_iterator; const git_index_entry *ancestor, *ours, *theirs; - cl_git_pass(git_oid__fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); cl_git_pass(git_index_new_ext(&index, NULL)); cl_git_pass(git_index_new_ext(&new_index, NULL)); diff --git a/tests/libgit2/index/rename.c b/tests/libgit2/index/rename.c index 9b132cb61b0..509601357f0 100644 --- a/tests/libgit2/index/rename.c +++ b/tests/libgit2/index/rename.c @@ -22,7 +22,7 @@ void test_index_rename__single_file(void) cl_git_pass(git_index_add_bypath(index, "lame.name.txt")); cl_assert(git_index_entrycount(index) == 1); - cl_git_pass(git_oid__fromstr(&expected, "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a", GIT_OID_SHA1)); cl_assert(!git_index_find(&position, index, "lame.name.txt")); diff --git a/tests/libgit2/index/reuc.c b/tests/libgit2/index/reuc.c index 7d8766c57f7..6c7923d2ed5 100644 --- a/tests/libgit2/index/reuc.c +++ b/tests/libgit2/index/reuc.c @@ -38,9 +38,9 @@ void test_index_reuc__add(void) git_oid ancestor_oid, our_oid, their_oid; const git_index_reuc_entry *reuc; - git_oid__fromstr(&ancestor_oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); - git_oid__fromstr(&our_oid, ONE_OUR_OID, GIT_OID_SHA1); - git_oid__fromstr(&their_oid, ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_oid, ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_oid, ONE_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_reuc_add(repo_index, "newfile.txt", 0100644, &ancestor_oid, @@ -66,8 +66,8 @@ void test_index_reuc__add_no_ancestor(void) const git_index_reuc_entry *reuc; memset(&ancestor_oid, 0x0, sizeof(git_oid)); - git_oid__fromstr(&our_oid, ONE_OUR_OID, GIT_OID_SHA1); - git_oid__fromstr(&their_oid, ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_oid, ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_oid, ONE_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_reuc_add(repo_index, "newfile.txt", 0, NULL, @@ -100,11 +100,11 @@ void test_index_reuc__read_bypath(void) cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); - git_oid__fromstr(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[0], &oid); - git_oid__fromstr(&oid, TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[1], &oid); - git_oid__fromstr(&oid, TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[2], &oid); cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "one.txt")); @@ -113,11 +113,11 @@ void test_index_reuc__read_bypath(void) cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); - git_oid__fromstr(&oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[0], &oid); - git_oid__fromstr(&oid, ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ONE_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[1], &oid); - git_oid__fromstr(&oid, ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ONE_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[2], &oid); } @@ -145,11 +145,11 @@ void test_index_reuc__ignore_case(void) cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); - git_oid__fromstr(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[0], &oid); - git_oid__fromstr(&oid, TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[1], &oid); - git_oid__fromstr(&oid, TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[2], &oid); } @@ -166,11 +166,11 @@ void test_index_reuc__read_byindex(void) cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); - git_oid__fromstr(&oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[0], &oid); - git_oid__fromstr(&oid, ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ONE_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[1], &oid); - git_oid__fromstr(&oid, ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, ONE_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[2], &oid); cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 1)); @@ -179,11 +179,11 @@ void test_index_reuc__read_byindex(void) cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); - git_oid__fromstr(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[0], &oid); - git_oid__fromstr(&oid, TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[1], &oid); - git_oid__fromstr(&oid, TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[2], &oid); } @@ -200,9 +200,9 @@ void test_index_reuc__updates_existing(void) index_caps |= GIT_INDEX_CAPABILITY_IGNORE_CASE; cl_git_pass(git_index_set_caps(repo_index, index_caps)); - git_oid__fromstr(&ancestor_oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); - git_oid__fromstr(&our_oid, TWO_OUR_OID, GIT_OID_SHA1); - git_oid__fromstr(&their_oid, TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_oid, TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_oid, TWO_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_reuc_add(repo_index, "two.txt", 0100644, &ancestor_oid, @@ -219,11 +219,11 @@ void test_index_reuc__updates_existing(void) cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); cl_assert_equal_s("TWO.txt", reuc->path); - git_oid__fromstr(&oid, TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[0], &oid); - git_oid__fromstr(&oid, TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[1], &oid); - git_oid__fromstr(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[2], &oid); } @@ -245,11 +245,11 @@ void test_index_reuc__remove(void) cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); - git_oid__fromstr(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[0], &oid); - git_oid__fromstr(&oid, TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_OUR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[1], &oid); - git_oid__fromstr(&oid, TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&oid, TWO_THEIR_OID, GIT_OID_SHA1); cl_assert_equal_oid(&reuc->oid[2], &oid); } @@ -261,18 +261,18 @@ void test_index_reuc__write(void) git_index_clear(repo_index); /* Write out of order to ensure sorting is correct */ - git_oid__fromstr(&ancestor_oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); - git_oid__fromstr(&our_oid, TWO_OUR_OID, GIT_OID_SHA1); - git_oid__fromstr(&their_oid, TWO_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_oid, TWO_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_oid, TWO_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_oid, TWO_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_reuc_add(repo_index, "two.txt", 0100644, &ancestor_oid, 0100644, &our_oid, 0100644, &their_oid)); - git_oid__fromstr(&ancestor_oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); - git_oid__fromstr(&our_oid, ONE_OUR_OID, GIT_OID_SHA1); - git_oid__fromstr(&their_oid, ONE_THEIR_OID, GIT_OID_SHA1); + git_oid_from_string(&ancestor_oid, ONE_ANCESTOR_OID, GIT_OID_SHA1); + git_oid_from_string(&our_oid, ONE_OUR_OID, GIT_OID_SHA1); + git_oid_from_string(&their_oid, ONE_THEIR_OID, GIT_OID_SHA1); cl_git_pass(git_index_reuc_add(repo_index, "one.txt", 0100644, &ancestor_oid, diff --git a/tests/libgit2/index/tests.c b/tests/libgit2/index/tests.c index fb064ea2172..63486ff54a5 100644 --- a/tests/libgit2/index/tests.c +++ b/tests/libgit2/index/tests.c @@ -259,7 +259,7 @@ void test_index_tests__add(void) * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ - cl_git_pass(git_oid__fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); /* Add the new file to the index */ cl_git_pass(git_index_add_bypath(index, "test.txt")); @@ -304,7 +304,7 @@ void test_index_tests__add_frombuffer(void) * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ - cl_git_pass(git_oid__fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); /* Add the new file to the index */ memset(&entry, 0x0, sizeof(git_index_entry)); @@ -447,7 +447,7 @@ void test_index_tests__add_frombuffer_reset_entry(void) * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ - cl_git_pass(git_oid__fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); cl_git_pass(git_index_add_bypath(index, "test.txt")); @@ -511,7 +511,7 @@ void test_index_tests__add_issue_1397(void) * This has been generated by executing the following * $ git hash-object crlf_file.txt */ - cl_git_pass(git_oid__fromstr(&id1, "8312e0889a9cbab77c732b6bc39b51a683e3a318", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, "8312e0889a9cbab77c732b6bc39b51a683e3a318", GIT_OID_SHA1)); /* Make sure the initial SHA-1 is correct */ cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL); @@ -600,7 +600,7 @@ static void assert_add_fails(git_repository *repo, const char *fn) entry.path = fn; entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", GIT_OID_SHA1)); cl_git_fail(git_index_add(index, &entry)); @@ -708,7 +708,7 @@ void test_index_tests__write_tree_invalid_unowned_index(void) cl_git_pass(git_index_new_ext(&idx, &index_opts)); - cl_git_pass(git_oid__fromstr(&entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318", GIT_OID_SHA1)); entry.path = "foo"; entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_add(idx, &entry)); @@ -1150,12 +1150,12 @@ void test_index_tests__can_modify_while_iterating(void) * ensure that our iterator is backed by a snapshot and thus returns * the number of entries from when the iterator was created. */ - cl_git_pass(git_oid__fromstr(&new_entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&new_entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318", GIT_OID_SHA1)); new_entry.path = "newfile"; new_entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_add(index, &new_entry)); - cl_git_pass(git_oid__fromstr(&new_entry.id, "4141414141414141414141414141414141414141", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&new_entry.id, "4141414141414141414141414141414141414141", GIT_OID_SHA1)); new_entry.path = "Makefile"; new_entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_add(index, &new_entry)); diff --git a/tests/libgit2/index/tests256.c b/tests/libgit2/index/tests256.c index c720796d8bb..7f94ab23fff 100644 --- a/tests/libgit2/index/tests256.c +++ b/tests/libgit2/index/tests256.c @@ -273,7 +273,7 @@ void test_index_tests256__add(void) * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ - cl_git_pass(git_oid__fromstr(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); /* Add the new file to the index */ cl_git_pass(git_index_add_bypath(index, "test.txt")); @@ -320,7 +320,7 @@ void test_index_tests256__add_frombuffer(void) * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ - cl_git_pass(git_oid__fromstr(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); /* Add the new file to the index */ memset(&entry, 0x0, sizeof(git_index_entry)); @@ -469,7 +469,7 @@ void test_index_tests256__add_frombuffer_reset_entry(void) * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ - cl_git_pass(git_oid__fromstr(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id1, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); cl_git_pass(git_index_add_bypath(index, "test.txt")); @@ -588,7 +588,7 @@ static void assert_add_fails(git_repository *repo, const char *fn) entry.path = fn; entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&entry.id, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&entry.id, "aea29dc305d40e362df25c3fdeed5502fd56b182af01b7740d297a24459333c5", GIT_OID_SHA256)); cl_git_fail(git_index_add(index, &entry)); @@ -703,7 +703,7 @@ void test_index_tests256__write_tree_invalid_unowned_index(void) cl_git_pass(git_index_new_ext(&idx, &index_opts)); /* TODO: this one is failing */ - cl_git_pass(git_oid__fromstr(&entry.id, "a8c2e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&entry.id, "a8c2e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); entry.path = "foo"; entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_add(idx, &entry)); @@ -1181,12 +1181,12 @@ void test_index_tests256__can_modify_while_iterating(void) * ensure that our iterator is backed by a snapshot and thus returns * the number of entries from when the iterator was created. */ - cl_git_pass(git_oid__fromstr(&new_entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&new_entry.id, "8312e0a89a9cbab77c732b6bc39b51a783e3a318a847f46cba7614cac9814291", GIT_OID_SHA256)); new_entry.path = "newfile"; new_entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_add(index, &new_entry)); - cl_git_pass(git_oid__fromstr(&new_entry.id, "4141414141414141414141414141414141414141414141414141414141414141", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&new_entry.id, "4141414141414141414141414141414141414141414141414141414141414141", GIT_OID_SHA256)); new_entry.path = "Makefile"; new_entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_add(index, &new_entry)); diff --git a/tests/libgit2/iterator/index.c b/tests/libgit2/iterator/index.c index e5ebec60c18..2f50bfab022 100644 --- a/tests/libgit2/iterator/index.c +++ b/tests/libgit2/iterator/index.c @@ -52,7 +52,7 @@ static void index_iterator_test( if (expected_oids != NULL) { git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, expected_oids[count], GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, expected_oids[count], GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &entry->id); } @@ -999,7 +999,7 @@ static void create_paths(git_index *index, const char *root, int depth) memset(&entry, 0, sizeof(git_index_entry)); entry.path = fullpath.ptr; entry.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&entry.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); cl_git_pass(git_index_add(index, &entry)); } else if (depth > 0) { @@ -1296,17 +1296,17 @@ static void add_conflict( ancestor.path = ancestor_path; ancestor.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&ancestor.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); + git_oid_from_string(&ancestor.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); GIT_INDEX_ENTRY_STAGE_SET(&ancestor, 1); ours.path = our_path; ours.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&ours.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); + git_oid_from_string(&ours.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); GIT_INDEX_ENTRY_STAGE_SET(&ours, 2); theirs.path = their_path; theirs.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&theirs.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); + git_oid_from_string(&theirs.id, "d44e18fb93b7107b5cd1b95d601591d77869a1b6", GIT_OID_SHA1); GIT_INDEX_ENTRY_STAGE_SET(&theirs, 3); cl_git_pass(git_index_conflict_add(index, &ancestor, &ours, &theirs)); diff --git a/tests/libgit2/iterator/tree.c b/tests/libgit2/iterator/tree.c index 81035bb8deb..3ebf49d4091 100644 --- a/tests/libgit2/iterator/tree.c +++ b/tests/libgit2/iterator/tree.c @@ -675,7 +675,7 @@ void test_iterator_tree__case_conflicts_0(void) g_repo = cl_git_sandbox_init("icase"); - cl_git_pass(git_oid__fromstr(&blob_id, blob_sha, GIT_OID_SHA1)); /* lookup blob */ + cl_git_pass(git_oid_from_string(&blob_id, blob_sha, GIT_OID_SHA1)); /* lookup blob */ /* create tree with: A/1.file, A/3.file, a/2.file, a/4.file */ build_test_tree( @@ -729,7 +729,7 @@ void test_iterator_tree__case_conflicts_1(void) g_repo = cl_git_sandbox_init("icase"); - cl_git_pass(git_oid__fromstr(&blob_id, blob_sha, GIT_OID_SHA1)); /* lookup blob */ + cl_git_pass(git_oid_from_string(&blob_id, blob_sha, GIT_OID_SHA1)); /* lookup blob */ /* create: A/a A/b/1 A/c a/a a/b a/C */ build_test_tree(&Ab_id, g_repo, "b|1|", &blob_id); @@ -798,7 +798,7 @@ void test_iterator_tree__case_conflicts_2(void) g_repo = cl_git_sandbox_init("icase"); - cl_git_pass(git_oid__fromstr(&blob_id, blob_sha, GIT_OID_SHA1)); /* lookup blob */ + cl_git_pass(git_oid_from_string(&blob_id, blob_sha, GIT_OID_SHA1)); /* lookup blob */ build_test_tree(&d1, g_repo, "b|16|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|15|,b|FOO|", &blob_id, &blob_id); diff --git a/tests/libgit2/iterator/workdir.c b/tests/libgit2/iterator/workdir.c index 327f1f65b66..59feb4546c8 100644 --- a/tests/libgit2/iterator/workdir.c +++ b/tests/libgit2/iterator/workdir.c @@ -1514,7 +1514,7 @@ void test_iterator_workdir__hash_when_requested(void) for (i = 0; i < sizeof(expected) / sizeof(struct merge_index_entry); i++) { cl_git_pass(git_iterator_advance(&entry, iter)); - cl_git_pass(git_oid__fromstr(&expected_id, expected[i].oid_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, expected[i].oid_str, GIT_OID_SHA1)); cl_assert_equal_oid(&expected_id, &entry->id); cl_assert_equal_s(expected[i].path, entry->path); } diff --git a/tests/libgit2/merge/driver.c b/tests/libgit2/merge/driver.c index fd73c3770a9..16780afba57 100644 --- a/tests/libgit2/merge/driver.c +++ b/tests/libgit2/merge/driver.c @@ -22,7 +22,7 @@ void test_merge_driver__initialize(void) repo = cl_git_sandbox_init(TEST_REPO_PATH); git_repository_index(&repo_index, repo); - git_oid__fromstr(&automergeable_id, AUTOMERGEABLE_IDSTR, GIT_OID_SHA1); + git_oid_from_string(&automergeable_id, AUTOMERGEABLE_IDSTR, GIT_OID_SHA1); /* Ensure that the user's merge.conflictstyle doesn't interfere */ cl_git_pass(git_repository_config(&cfg, repo)); @@ -145,7 +145,7 @@ static void merge_branch(void) git_oid their_id; git_annotated_commit *their_head; - cl_git_pass(git_oid__fromstr(&their_id, BRANCH_ID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_id, BRANCH_ID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_id)); cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head, @@ -299,7 +299,7 @@ void test_merge_driver__default_can_be_specified(void) merge_opts.default_driver = "custom"; - cl_git_pass(git_oid__fromstr(&their_id, BRANCH_ID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_id, BRANCH_ID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_id)); cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head, diff --git a/tests/libgit2/merge/files.c b/tests/libgit2/merge/files.c index 6c1c2e13f78..0f2dfbdf428 100644 --- a/tests/libgit2/merge/files.c +++ b/tests/libgit2/merge/files.c @@ -149,15 +149,15 @@ void test_merge_files__automerge_from_index(void) git_merge_file_result result = {0}; git_index_entry ancestor, ours, theirs; - git_oid__fromstr(&ancestor.id, "6212c31dab5e482247d7977e4f0dd3601decf13b", GIT_OID_SHA1); + git_oid_from_string(&ancestor.id, "6212c31dab5e482247d7977e4f0dd3601decf13b", GIT_OID_SHA1); ancestor.path = "automergeable.txt"; ancestor.mode = 0100644; - git_oid__fromstr(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); + git_oid_from_string(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", GIT_OID_SHA1); ours.path = "automergeable.txt"; ours.mode = 0100755; - git_oid__fromstr(&theirs.id, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe", GIT_OID_SHA1); + git_oid_from_string(&theirs.id, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe", GIT_OID_SHA1); theirs.path = "newname.txt"; theirs.mode = 0100644; diff --git a/tests/libgit2/merge/merge_helpers.c b/tests/libgit2/merge/merge_helpers.c index 1406987e53f..3746c191ae4 100644 --- a/tests/libgit2/merge/merge_helpers.c +++ b/tests/libgit2/merge/merge_helpers.c @@ -165,7 +165,7 @@ static int index_entry_eq_merge_index_entry(const struct merge_index_entry *expe bool test_oid; if (strlen(expected->oid_str) != 0) { - cl_git_pass(git_oid__fromstr(&expected_oid, expected->oid_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, expected->oid_str, GIT_OID_SHA1)); test_oid = 1; } else test_oid = 0; @@ -304,21 +304,21 @@ int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], return 0; if (expected[i].ancestor_mode > 0) { - cl_git_pass(git_oid__fromstr(&expected_oid, expected[i].ancestor_oid_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, expected[i].ancestor_oid_str, GIT_OID_SHA1)); if (git_oid_cmp(&reuc_entry->oid[0], &expected_oid) != 0) return 0; } if (expected[i].our_mode > 0) { - cl_git_pass(git_oid__fromstr(&expected_oid, expected[i].our_oid_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, expected[i].our_oid_str, GIT_OID_SHA1)); if (git_oid_cmp(&reuc_entry->oid[1], &expected_oid) != 0) return 0; } if (expected[i].their_mode > 0) { - cl_git_pass(git_oid__fromstr(&expected_oid, expected[i].their_oid_str, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, expected[i].their_oid_str, GIT_OID_SHA1)); if (git_oid_cmp(&reuc_entry->oid[2], &expected_oid) != 0) return 0; @@ -353,7 +353,7 @@ int merge_test_workdir(git_repository *repo, const struct merge_index_entry expe for (i = 0; i < expected_len; i++) { git_blob_create_from_workdir(&actual_oid, repo, expected[i].path); - git_oid__fromstr(&expected_oid, expected[i].oid_str, GIT_OID_SHA1); + git_oid_from_string(&expected_oid, expected[i].oid_str, GIT_OID_SHA1); if (git_oid_cmp(&actual_oid, &expected_oid) != 0) return 0; diff --git a/tests/libgit2/merge/trees/renames.c b/tests/libgit2/merge/trees/renames.c index 9507b51bc9e..a93d4751756 100644 --- a/tests/libgit2/merge/trees/renames.c +++ b/tests/libgit2/merge/trees/renames.c @@ -286,7 +286,7 @@ void test_merge_trees_renames__cache_recomputation(void) void *data; size_t i; - cl_git_pass(git_oid__fromstr(&blob, "a2d8d1824c68541cca94ffb90f79291eba495921", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&blob, "a2d8d1824c68541cca94ffb90f79291eba495921", GIT_OID_SHA1)); /* * Create a 50MB blob that consists of NUL bytes only. It is important diff --git a/tests/libgit2/merge/trees/treediff.c b/tests/libgit2/merge/trees/treediff.c index 094018d3cf6..5c786f12250 100644 --- a/tests/libgit2/merge/trees/treediff.c +++ b/tests/libgit2/merge/trees/treediff.c @@ -61,9 +61,9 @@ static void test_find_differences( opts.metric->similarity = git_diff_find_similar__calc_similarity; opts.metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; - cl_git_pass(git_oid__fromstr(&ancestor_oid, ancestor_oidstr, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&ours_oid, ours_oidstr, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&theirs_oid, theirs_oidstr, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&ancestor_oid, ancestor_oidstr, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&ours_oid, ours_oidstr, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&theirs_oid, theirs_oidstr, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&ancestor_tree, repo, &ancestor_oid)); cl_git_pass(git_tree_lookup(&ours_tree, repo, &ours_oid)); diff --git a/tests/libgit2/merge/trees/trivial.c b/tests/libgit2/merge/trees/trivial.c index 287a53cfe7a..41c2408d52f 100644 --- a/tests/libgit2/merge/trees/trivial.c +++ b/tests/libgit2/merge/trees/trivial.c @@ -258,7 +258,7 @@ void test_merge_trees_trivial__13(void) cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch")); cl_assert(entry = git_index_get_bypath(result, "modified-in-13.txt", 0)); - cl_git_pass(git_oid__fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b", GIT_OID_SHA1)); cl_assert_equal_oid(&expected_oid, &entry->id); cl_assert(git_index_reuc_entrycount(result) == 0); @@ -277,7 +277,7 @@ void test_merge_trees_trivial__14(void) cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch")); cl_assert(entry = git_index_get_bypath(result, "modified-in-14-branch.txt", 0)); - cl_git_pass(git_oid__fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9", GIT_OID_SHA1)); cl_assert(git_oid_cmp(&entry->id, &expected_oid) == 0); cl_assert(git_index_reuc_entrycount(result) == 0); diff --git a/tests/libgit2/merge/workdir/dirty.c b/tests/libgit2/merge/workdir/dirty.c index 570e7c759e5..82d93b6c069 100644 --- a/tests/libgit2/merge/workdir/dirty.c +++ b/tests/libgit2/merge/workdir/dirty.c @@ -94,7 +94,7 @@ static int merge_branch(void) git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; int error; - cl_git_pass(git_oid__fromstr(&their_oids[0], MERGE_BRANCH_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_oids[0], MERGE_BRANCH_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_head, repo, &their_oids[0])); error = git_merge(repo, (const git_annotated_commit **)&their_head, 1, &merge_opts, &checkout_opts); diff --git a/tests/libgit2/merge/workdir/setup.c b/tests/libgit2/merge/workdir/setup.c index 98ccdf700e0..84496c436e1 100644 --- a/tests/libgit2/merge/workdir/setup.c +++ b/tests/libgit2/merge/workdir/setup.c @@ -78,7 +78,7 @@ void test_merge_workdir_setup__one_branch(void) git_reference *octo1_ref; git_annotated_commit *our_head, *their_heads[1]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -104,10 +104,10 @@ void test_merge_workdir_setup__one_oid(void) git_oid octo1_oid; git_annotated_commit *our_head, *their_heads[1]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); @@ -129,7 +129,7 @@ void test_merge_workdir_setup__two_branches(void) git_reference *octo2_ref; git_annotated_commit *our_head, *their_heads[2]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -162,7 +162,7 @@ void test_merge_workdir_setup__three_branches(void) git_reference *octo3_ref; git_annotated_commit *our_head, *their_heads[3]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -200,16 +200,16 @@ void test_merge_workdir_setup__three_oids(void) git_oid octo3_oid; git_annotated_commit *our_head, *their_heads[3]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); - cl_git_pass(git_oid__fromstr(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo2_oid)); - cl_git_pass(git_oid__fromstr(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); @@ -233,13 +233,13 @@ void test_merge_workdir_setup__branches_and_oids_1(void) git_oid octo2_oid; git_annotated_commit *our_head, *their_heads[2]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); - cl_git_pass(git_oid__fromstr(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo2_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); @@ -266,19 +266,19 @@ void test_merge_workdir_setup__branches_and_oids_2(void) git_oid octo4_oid; git_annotated_commit *our_head, *their_heads[4]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_annotated_commit_from_ref(&their_heads[0], repo, octo1_ref)); - cl_git_pass(git_oid__fromstr(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo2_oid)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH)); cl_git_pass(git_annotated_commit_from_ref(&their_heads[2], repo, octo3_ref)); - cl_git_pass(git_oid__fromstr(&octo4_oid, OCTO4_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo4_oid, OCTO4_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[3], repo, &octo4_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); @@ -308,16 +308,16 @@ void test_merge_workdir_setup__branches_and_oids_3(void) git_reference *octo4_ref; git_annotated_commit *our_head, *their_heads[4]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); - cl_git_pass(git_oid__fromstr(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH)); @@ -351,16 +351,16 @@ void test_merge_workdir_setup__branches_and_oids_4(void) git_reference *octo5_ref; git_annotated_commit *our_head, *their_heads[5]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); cl_git_pass(git_annotated_commit_from_ref(&their_heads[1], repo, octo2_ref)); - cl_git_pass(git_oid__fromstr(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH)); @@ -397,7 +397,7 @@ void test_merge_workdir_setup__three_same_branches(void) git_reference *octo1_3_ref; git_annotated_commit *our_head, *their_heads[3]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -435,16 +435,16 @@ void test_merge_workdir_setup__three_same_oids(void) git_oid octo1_3_oid; git_annotated_commit *our_head, *their_heads[3]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &octo1_1_oid)); - cl_git_pass(git_oid__fromstr(&octo1_2_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_2_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[1], repo, &octo1_2_oid)); - cl_git_pass(git_oid__fromstr(&octo1_3_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_3_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[2], repo, &octo1_3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); @@ -512,7 +512,7 @@ void test_merge_workdir_setup__remote_tracking_one_branch(void) cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); @@ -542,7 +542,7 @@ void test_merge_workdir_setup__remote_tracking_two_branches(void) cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); @@ -579,7 +579,7 @@ void test_merge_workdir_setup__remote_tracking_three_branches(void) cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(create_remote_tracking_branch(OCTO3_BRANCH, OCTO3_OID)); - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); @@ -618,7 +618,7 @@ void test_merge_workdir_setup__normal_branch_and_remote_tracking_branch(void) cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -652,7 +652,7 @@ void test_merge_workdir_setup__remote_tracking_branch_and_normal_branch(void) cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); @@ -689,7 +689,7 @@ void test_merge_workdir_setup__two_remote_tracking_branch_and_two_normal_branche cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(create_remote_tracking_branch(OCTO4_BRANCH, OCTO4_OID)); - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -730,10 +730,10 @@ void test_merge_workdir_setup__pull_one(void) git_oid octo1_1_oid; git_annotated_commit *our_head, *their_heads[1]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_1_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); @@ -755,13 +755,13 @@ void test_merge_workdir_setup__pull_two(void) git_oid octo2_oid; git_annotated_commit *our_head, *their_heads[2]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); - cl_git_pass(git_oid__fromstr(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); @@ -785,16 +785,16 @@ void test_merge_workdir_setup__pull_three(void) git_oid octo3_oid; git_annotated_commit *our_head, *their_heads[3]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); - cl_git_pass(git_oid__fromstr(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); - cl_git_pass(git_oid__fromstr(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.url/repo.git", &octo3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); @@ -818,16 +818,16 @@ void test_merge_workdir_setup__three_remotes(void) git_oid octo3_oid; git_annotated_commit *our_head, *their_heads[3]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); - cl_git_pass(git_oid__fromstr(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); - cl_git_pass(git_oid__fromstr(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.third/repo.git", &octo3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); @@ -852,19 +852,19 @@ void test_merge_workdir_setup__two_remotes(void) git_oid octo4_oid; git_annotated_commit *our_head, *their_heads[4]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); - cl_git_pass(git_oid__fromstr(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo1_oid, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); - cl_git_pass(git_oid__fromstr(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo2_oid, OCTO2_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); - cl_git_pass(git_oid__fromstr(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo3_oid, OCTO3_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.first/repo.git", &octo3_oid)); - cl_git_pass(git_oid__fromstr(&octo4_oid, OCTO4_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&octo4_oid, OCTO4_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&their_heads[3], repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH, "http://remote.second/repo.git", &octo4_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); @@ -888,7 +888,7 @@ void test_merge_workdir_setup__id_from_head(void) git_reference *ref; git_annotated_commit *heads[3]; - cl_git_pass(git_oid__fromstr(&expected_id, OCTO1_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, OCTO1_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_fetchhead(&heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &expected_id)); id = git_annotated_commit_id(heads[0]); cl_assert_equal_i(1, git_oid_equal(id, &expected_id)); @@ -920,7 +920,7 @@ static int annotated_commit_foreach_cb(const git_oid *oid, void *payload) git_oid expected_oid; struct annotated_commit_cb_data *cb_data = payload; - git_oid__fromstr(&expected_oid, cb_data->oid_str[cb_data->i], GIT_OID_SHA1); + git_oid_from_string(&expected_oid, cb_data->oid_str[cb_data->i], GIT_OID_SHA1); cl_assert(git_oid_cmp(&expected_oid, oid) == 0); cb_data->i++; return 0; @@ -998,7 +998,7 @@ void test_merge_workdir_setup__retained_after_success(void) git_reference *octo1_ref; git_annotated_commit *our_head, *their_heads[1]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -1025,7 +1025,7 @@ void test_merge_workdir_setup__removed_after_failure(void) git_reference *octo1_ref; git_annotated_commit *our_head, *their_heads[1]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -1052,7 +1052,7 @@ void test_merge_workdir_setup__unlocked_after_success(void) git_reference *octo1_ref; git_annotated_commit *our_head, *their_heads[1]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); @@ -1075,7 +1075,7 @@ void test_merge_workdir_setup__unlocked_after_conflict(void) git_reference *octo1_ref; git_annotated_commit *our_head, *their_heads[1]; - cl_git_pass(git_oid__fromstr(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, ORIG_HEAD, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); diff --git a/tests/libgit2/merge/workdir/simple.c b/tests/libgit2/merge/workdir/simple.c index 17faabff06c..c92277d8599 100644 --- a/tests/libgit2/merge/workdir/simple.c +++ b/tests/libgit2/merge/workdir/simple.c @@ -99,7 +99,7 @@ static void merge_simple_branch(int merge_file_favor, int addl_checkout_strategy git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - cl_git_pass(git_oid__fromstr(&their_oids[0], THEIRS_SIMPLE_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_oids[0], THEIRS_SIMPLE_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = merge_file_favor; @@ -180,14 +180,14 @@ void test_merge_workdir_simple__index_reload(void) cl_git_pass(git_index_read(repo_index, 0)); entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&entry.id, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", GIT_OID_SHA1)); entry.path = "automergeable.txt"; cl_git_pass(git_index_add(repo_index, &entry)); cl_git_pass(git_index_add_bypath(tmp_index, "automergeable.txt")); cl_git_pass(git_index_write(tmp_index)); - cl_git_pass(git_oid__fromstr(&their_oid, THEIRS_SIMPLE_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_oid, THEIRS_SIMPLE_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oid)); cl_git_pass(git_merge(repo, (const git_annotated_commit **)their_heads, 1, NULL, NULL)); @@ -669,7 +669,7 @@ void test_merge_workdir_simple__directory_file(void) cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_id)); cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL)); - cl_git_pass(git_oid__fromstr(&their_oids[0], THEIRS_DIRECTORY_FILE, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_oids[0], THEIRS_DIRECTORY_FILE, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = 0; @@ -700,7 +700,7 @@ void test_merge_workdir_simple__unrelated(void) { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, }; - cl_git_pass(git_oid__fromstr(&their_oids[0], THEIRS_UNRELATED_PARENT, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_oids[0], THEIRS_UNRELATED_PARENT, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = 0; @@ -731,7 +731,7 @@ void test_merge_workdir_simple__unrelated_with_conflicts(void) { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, }; - cl_git_pass(git_oid__fromstr(&their_oids[0], THEIRS_UNRELATED_OID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_oids[0], THEIRS_UNRELATED_OID, GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&their_heads[0], repo, &their_oids[0])); merge_opts.file_favor = 0; @@ -755,8 +755,8 @@ void test_merge_workdir_simple__binary(void) { 0100644, "836b8b82b26cab22eaaed8820877c76d6c8bca19", 3, "binary" }, }; - cl_git_pass(git_oid__fromstr(&our_oid, "cc338e4710c9b257106b8d16d82f86458d5beaf1", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&their_oid, "ad01aebfdf2ac13145efafe3f9fcf798882f1730", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_oid, "cc338e4710c9b257106b8d16d82f86458d5beaf1", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&their_oid, "ad01aebfdf2ac13145efafe3f9fcf798882f1730", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL)); @@ -770,7 +770,7 @@ void test_merge_workdir_simple__binary(void) cl_git_pass(git_index_add_bypath(repo_index, "binary")); cl_assert((binary_entry = git_index_get_bypath(repo_index, "binary", 0)) != NULL); - cl_git_pass(git_oid__fromstr(&our_file_oid, "23ed141a6ae1e798b2f721afedbe947c119111ba", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&our_file_oid, "23ed141a6ae1e798b2f721afedbe947c119111ba", GIT_OID_SHA1)); cl_assert(git_oid_cmp(&binary_entry->id, &our_file_oid) == 0); git_annotated_commit_free(their_head); diff --git a/tests/libgit2/merge/workdir/trivial.c b/tests/libgit2/merge/workdir/trivial.c index 364182c8993..88ce033329a 100644 --- a/tests/libgit2/merge/workdir/trivial.c +++ b/tests/libgit2/merge/workdir/trivial.c @@ -222,7 +222,7 @@ void test_merge_workdir_trivial__13(void) cl_git_pass(merge_trivial("trivial-13", "trivial-13-branch")); cl_assert(entry = git_index_get_bypath(repo_index, "modified-in-13.txt", 0)); - cl_git_pass(git_oid__fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b", GIT_OID_SHA1)); cl_assert(git_oid_cmp(&entry->id, &expected_oid) == 0); cl_assert(git_index_reuc_entrycount(repo_index) == 0); @@ -238,7 +238,7 @@ void test_merge_workdir_trivial__14(void) cl_git_pass(merge_trivial("trivial-14", "trivial-14-branch")); cl_assert(entry = git_index_get_bypath(repo_index, "modified-in-14-branch.txt", 0)); - cl_git_pass(git_oid__fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9", GIT_OID_SHA1)); cl_assert(git_oid_cmp(&entry->id, &expected_oid) == 0); cl_assert(git_index_reuc_entrycount(repo_index) == 0); diff --git a/tests/libgit2/network/remote/rename.c b/tests/libgit2/network/remote/rename.c index e02a4ce35c3..39e91fa23f4 100644 --- a/tests/libgit2/network/remote/rename.c +++ b/tests/libgit2/network/remote/rename.c @@ -170,7 +170,7 @@ void test_network_remote_rename__overwrite_ref_in_target(void) git_branch_iterator *iter; git_strarray problems = {0}; - cl_git_pass(git_oid__fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); cl_git_pass(git_reference_create(&ref, _repo, "refs/remotes/renamed/master", &id, 1, NULL)); git_reference_free(ref); diff --git a/tests/libgit2/notes/notes.c b/tests/libgit2/notes/notes.c index 06c4409551b..fb0a70d059c 100644 --- a/tests/libgit2/notes/notes.c +++ b/tests/libgit2/notes/notes.c @@ -33,7 +33,7 @@ static void create_note(git_oid *note_oid, const char *canonical_namespace, cons { git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, target_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, target_sha, GIT_OID_SHA1)); cl_git_pass(git_note_create(note_oid, _repo, canonical_namespace, _sig, _sig, &oid, message, 0)); } @@ -60,10 +60,10 @@ static int note_list_cb( cl_assert(*count < EXPECTATIONS_COUNT); - cl_git_pass(git_oid__fromstr(&expected_note_oid, list_expectations[*count].note_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_note_oid, list_expectations[*count].note_sha, GIT_OID_SHA1)); cl_assert_equal_oid(&expected_note_oid, blob_id); - cl_git_pass(git_oid__fromstr(&expected_target_oid, list_expectations[*count].annotated_object_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_target_oid, list_expectations[*count].annotated_object_sha, GIT_OID_SHA1)); cl_assert_equal_oid(&expected_target_oid, annotated_obj_id); (*count)++; @@ -85,12 +85,12 @@ static int note_list_create_cb( size_t i; for (i = 0; notes[i].note_oid != NULL; i++) { - cl_git_pass(git_oid__fromstr(&expected_note_oid, notes[i].note_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_note_oid, notes[i].note_oid, GIT_OID_SHA1)); if (git_oid_cmp(&expected_note_oid, blob_oid) != 0) continue; - cl_git_pass(git_oid__fromstr(&expected_target_oid, notes[i].object_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_target_oid, notes[i].object_oid, GIT_OID_SHA1)); if (git_oid_cmp(&expected_target_oid, annotated_obj_id) != 0) continue; @@ -140,7 +140,7 @@ void test_notes_notes__can_create_a_note_from_commit(void) { NULL, NULL, 0 } }; - cl_git_pass(git_oid__fromstr(&oid, can_create_a_note_from_commit[0].object_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, can_create_a_note_from_commit[0].object_oid, GIT_OID_SHA1)); cl_git_pass(git_note_commit_create(¬es_commit_out, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1)); @@ -169,11 +169,11 @@ void test_notes_notes__can_create_a_note_from_commit_given_an_existing_commit(vo { NULL, NULL, 0 } }; - cl_git_pass(git_oid__fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); cl_git_pass(git_note_commit_create(¬es_commit_out, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 0)); - cl_git_pass(git_oid__fromstr(&oid, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); git_commit_lookup(&existing_notes_commit, _repo, ¬es_commit_out); @@ -274,7 +274,7 @@ void test_notes_notes__inserting_a_note_without_passing_a_namespace_uses_the_def git_note *note, *default_namespace_note; git_buf default_ref = GIT_BUF_INIT; - cl_git_pass(git_oid__fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); cl_git_pass(git_note_default_ref(&default_ref, _repo)); create_note(¬e_oid, NULL, "08b041783f40edfe12bb406c9c9a8a040177c125", "hello world\n"); @@ -295,7 +295,7 @@ void test_notes_notes__can_insert_a_note_with_a_custom_namespace(void) git_oid note_oid, target_oid; git_note *note; - cl_git_pass(git_oid__fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); create_note(¬e_oid, "refs/notes/some/namespace", "08b041783f40edfe12bb406c9c9a8a040177c125", "hello world on a custom namespace\n"); @@ -315,7 +315,7 @@ void test_notes_notes__creating_a_note_on_a_target_which_already_has_one_returns int error; git_oid note_oid, target_oid; - cl_git_pass(git_oid__fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); create_note(¬e_oid, NULL, "08b041783f40edfe12bb406c9c9a8a040177c125", "hello world\n"); error = git_note_create(¬e_oid, _repo, NULL, _sig, _sig, &target_oid, "hello world\n", 0); @@ -334,7 +334,7 @@ void test_notes_notes__creating_a_note_on_a_target_can_overwrite_existing_note(v git_oid note_oid, target_oid; git_note *note, *namespace_note; - cl_git_pass(git_oid__fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); create_note(¬e_oid, NULL, "08b041783f40edfe12bb406c9c9a8a040177c125", "hello old world\n"); cl_git_pass(git_note_create(¬e_oid, _repo, NULL, _sig, _sig, &target_oid, "hello new world\n", 1)); @@ -381,7 +381,7 @@ void test_notes_notes__can_read_a_note(void) create_note(¬e_oid, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 4a20\n"); - cl_git_pass(git_oid__fromstr(&target_oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); cl_git_pass(git_note_read(¬e, _repo, "refs/notes/i-can-see-dead-notes", &target_oid)); @@ -397,7 +397,7 @@ void test_notes_notes__can_read_a_note_from_a_commit(void) git_commit *notes_commit; git_note *note; - cl_git_pass(git_oid__fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); cl_git_pass(git_note_commit_create(¬es_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1)); cl_git_pass(git_commit_lookup(¬es_commit, _repo, ¬es_commit_oid)); cl_assert(notes_commit); @@ -416,7 +416,7 @@ void test_notes_notes__attempt_to_read_a_note_from_a_commit_with_no_note_fails(v git_commit *notes_commit; git_note *note; - cl_git_pass(git_oid__fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); cl_git_pass(git_note_commit_create(¬es_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1)); @@ -450,7 +450,7 @@ void test_notes_notes__can_insert_a_note_in_an_existing_fanout(void) git_oid note_oid, target_oid; git_note *_note; - cl_git_pass(git_oid__fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); for (i = 0; i < MESSAGES_COUNT; i++) { cl_git_pass(git_note_create(¬e_oid, _repo, "refs/notes/fanout", _sig, _sig, &target_oid, messages[i], 0)); @@ -470,10 +470,10 @@ void test_notes_notes__can_read_a_note_in_an_existing_fanout(void) git_oid note_oid, target_oid; git_note *note; - cl_git_pass(git_oid__fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); cl_git_pass(git_note_read(¬e, _repo, "refs/notes/fanout", &target_oid)); - cl_git_pass(git_oid__fromstr(¬e_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(¬e_oid, "08b041783f40edfe12bb406c9c9a8a040177c125", GIT_OID_SHA1)); cl_assert_equal_oid(git_note_id(note), ¬e_oid); git_note_free(note); @@ -487,7 +487,7 @@ void test_notes_notes__can_remove_a_note(void) create_note(¬e_oid, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 4a20\n"); - cl_git_pass(git_oid__fromstr(&target_oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); cl_git_pass(git_note_remove(_repo, "refs/notes/i-can-see-dead-notes", _sig, _sig, &target_oid)); cl_git_fail(git_note_read(¬e, _repo, "refs/notes/i-can-see-dead-notes", &target_oid)); @@ -501,7 +501,7 @@ void test_notes_notes__can_remove_a_note_from_commit(void) git_commit *existing_notes_commit; git_reference *ref; - cl_git_pass(git_oid__fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1)); cl_git_pass(git_note_commit_create(¬es_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 0)); @@ -528,7 +528,7 @@ void test_notes_notes__can_remove_a_note_in_an_existing_fanout(void) git_oid target_oid; git_note *note; - cl_git_pass(git_oid__fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); cl_git_pass(git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid)); cl_git_fail(git_note_read(¬e, _repo, "refs/notes/fanout", &target_oid)); @@ -539,7 +539,7 @@ void test_notes_notes__removing_a_note_which_doesnt_exists_returns_ENOTFOUND(voi int error; git_oid target_oid; - cl_git_pass(git_oid__fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); cl_git_pass(git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid)); error = git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid); @@ -628,8 +628,8 @@ void test_notes_notes__iterate_from_commit(void) }; int i, err; - cl_git_pass(git_oid__fromstr(&(oids[0]), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&(oids[1]), "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&(oids[0]), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&(oids[1]), "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); cl_git_pass(git_note_commit_create(¬es_commit_oids[0], NULL, _repo, NULL, _sig, _sig, &(oids[0]), note_message[0], 0)); diff --git a/tests/libgit2/notes/notesref.c b/tests/libgit2/notes/notesref.c index 8696ff66a60..13def68e5b0 100644 --- a/tests/libgit2/notes/notesref.c +++ b/tests/libgit2/notes/notesref.c @@ -36,7 +36,7 @@ void test_notes_notesref__config_corenotesref(void) git_buf default_ref = GIT_BUF_INIT; cl_git_pass(git_signature_now(&_sig, "alice", "alice@example.com")); - cl_git_pass(git_oid__fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1)); cl_git_pass(git_repository_config(&_cfg, _repo)); diff --git a/tests/libgit2/object/blob/fromstream.c b/tests/libgit2/object/blob/fromstream.c index dad0b52e155..52eb2967959 100644 --- a/tests/libgit2/object/blob/fromstream.c +++ b/tests/libgit2/object/blob/fromstream.c @@ -23,7 +23,7 @@ void test_object_blob_fromstream__multiple_write(void) git_writestream *stream; int i, howmany = 6; - cl_git_pass(git_oid__fromstr(&expected_id, "321cbdf08803c744082332332838df6bd160f8f9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, "321cbdf08803c744082332332838df6bd160f8f9", GIT_OID_SHA1)); cl_git_fail_with(GIT_ENOTFOUND, git_object_lookup(&blob, repo, &expected_id, GIT_OBJECT_ANY)); @@ -64,7 +64,7 @@ static void assert_named_chunked_blob(const char *expected_sha, const char *fake git_writestream *stream; int i, howmany = 6; - cl_git_pass(git_oid__fromstr(&expected_id, expected_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, expected_sha, GIT_OID_SHA1)); cl_git_pass(git_blob_create_from_stream(&stream, repo, fake_name)); diff --git a/tests/libgit2/object/cache.c b/tests/libgit2/object/cache.c index bf8c6fb53cb..b10c97cd034 100644 --- a/tests/libgit2/object/cache.c +++ b/tests/libgit2/object/cache.c @@ -91,7 +91,7 @@ void test_object_cache__cache_counts(void) for (i = 0; g_data[i].sha != NULL; ++i) { int count = (int)git_cache_size(&g_repo->objects); - cl_git_pass(git_oid__fromstr(&oid, g_data[i].sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, g_data[i].sha, GIT_OID_SHA1)); /* alternate between loading raw and parsed objects */ if ((i & 1) == 0) { @@ -118,7 +118,7 @@ void test_object_cache__cache_counts(void) for (i = 0; g_data[i].sha != NULL; ++i) { int count = (int)git_cache_size(&g_repo->objects); - cl_git_pass(git_oid__fromstr(&oid, g_data[i].sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, g_data[i].sha, GIT_OID_SHA1)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); @@ -136,14 +136,14 @@ static void *cache_parsed(void *arg) git_object *obj; for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { - cl_git_pass(git_oid__fromstr(&oid, g_data[i].sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, g_data[i].sha, GIT_OID_SHA1)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); } for (i = 0; i < ((int *)arg)[1]; i += 2) { - cl_git_pass(git_oid__fromstr(&oid, g_data[i].sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, g_data[i].sha, GIT_OID_SHA1)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); @@ -162,14 +162,14 @@ static void *cache_raw(void *arg) cl_git_pass(git_repository_odb(&odb, g_repo)); for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { - cl_git_pass(git_oid__fromstr(&oid, g_data[i].sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, g_data[i].sha, GIT_OID_SHA1)); cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); git_odb_object_free(odb_obj); } for (i = 0; i < ((int *)arg)[1]; i += 2) { - cl_git_pass(git_oid__fromstr(&oid, g_data[i].sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, g_data[i].sha, GIT_OID_SHA1)); cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); git_odb_object_free(odb_obj); @@ -234,7 +234,7 @@ static void *cache_quick(void *arg) git_oid oid; git_object *obj; - cl_git_pass(git_oid__fromstr(&oid, g_data[4].sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, g_data[4].sha, GIT_OID_SHA1)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); cl_assert(g_data[4].type == git_object_type(obj)); git_object_free(obj); diff --git a/tests/libgit2/object/commit/commitstagedfile.c b/tests/libgit2/object/commit/commitstagedfile.c index 61f50b2af60..565c888e468 100644 --- a/tests/libgit2/object/commit/commitstagedfile.c +++ b/tests/libgit2/object/commit/commitstagedfile.c @@ -64,9 +64,9 @@ void test_object_commit_commitstagedfile__generate_predictable_object_ids(void) * 100644 blob 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 test.txt */ - cl_git_pass(git_oid__fromstr(&expected_commit_oid, "1fe3126578fc4eca68c193e4a3a0a14a0704624d", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected_tree_oid, "2b297e643c551e76cfa1f93810c50811382f9117", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected_blob_oid, "9daeafb9864cf43055ae93beb0afd6c7d144bfa4", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_commit_oid, "1fe3126578fc4eca68c193e4a3a0a14a0704624d", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_tree_oid, "2b297e643c551e76cfa1f93810c50811382f9117", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_blob_oid, "9daeafb9864cf43055ae93beb0afd6c7d144bfa4", GIT_OID_SHA1)); /* * Add a new file to the index diff --git a/tests/libgit2/object/commit/parse.c b/tests/libgit2/object/commit/parse.c index 6f9a6550789..78413fb4982 100644 --- a/tests/libgit2/object/commit/parse.c +++ b/tests/libgit2/object/commit/parse.c @@ -54,7 +54,7 @@ static void assert_commit_parses( if (expected_treeid) { git_oid tree_oid; - cl_git_pass(git_oid__fromstr(&tree_oid, expected_treeid, oid_type)); + cl_git_pass(git_oid_from_string(&tree_oid, expected_treeid, oid_type)); cl_assert_equal_oid(&tree_oid, &commit->tree_id); } diff --git a/tests/libgit2/object/lookup.c b/tests/libgit2/object/lookup.c index 7ef1dbd1c96..2285a488126 100644 --- a/tests/libgit2/object/lookup.c +++ b/tests/libgit2/object/lookup.c @@ -20,7 +20,7 @@ void test_object_lookup__lookup_wrong_type_returns_enotfound(void) git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA1)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_TAG)); } @@ -31,7 +31,7 @@ void test_object_lookup__lookup_nonexisting_returns_enotfound(void) git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstr(&oid, unknown, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, unknown, GIT_OID_SHA1)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_ANY)); } @@ -42,7 +42,7 @@ void test_object_lookup__lookup_wrong_type_by_abbreviated_id_returns_enotfound(v git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstrn(&oid, commit, strlen(commit), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, commit, strlen(commit), GIT_OID_SHA1)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup_prefix(&object, g_repo, &oid, strlen(commit), GIT_OBJECT_TAG)); } @@ -53,7 +53,7 @@ void test_object_lookup__lookup_wrong_type_eventually_returns_enotfound(void) git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA1)); cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT)); git_object_free(object); @@ -71,7 +71,7 @@ void test_object_lookup__lookup_corrupt_object_returns_error(void) git_object *object; size_t i; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA1)); cl_git_pass(git_str_joinpath(&path, git_repository_path(g_repo), file)); cl_git_pass(git_futils_readbuffer(&contents, path.ptr)); @@ -101,7 +101,7 @@ void test_object_lookup__lookup_object_with_wrong_hash_returns_error(void) git_object *object; git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA1)); /* Copy object to another location with wrong hash */ cl_git_pass(git_str_joinpath(&oldpath, git_repository_path(g_repo), oldloose)); diff --git a/tests/libgit2/object/lookup256.c b/tests/libgit2/object/lookup256.c index 3e1dab6610a..cd1aa648926 100644 --- a/tests/libgit2/object/lookup256.c +++ b/tests/libgit2/object/lookup256.c @@ -29,7 +29,7 @@ void test_object_lookup256__lookup_wrong_type_returns_enotfound(void) git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA256)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_TAG)); #endif @@ -44,7 +44,7 @@ void test_object_lookup256__lookup_nonexisting_returns_enotfound(void) git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstr(&oid, unknown, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&oid, unknown, GIT_OID_SHA256)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_ANY)); #endif @@ -59,7 +59,7 @@ void test_object_lookup256__lookup_wrong_type_by_abbreviated_id_returns_enotfoun git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstrn(&oid, commit, strlen(commit), GIT_OID_SHA256)); + cl_git_pass(git_oid_from_prefix(&oid, commit, strlen(commit), GIT_OID_SHA256)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup_prefix(&object, g_repo, &oid, strlen(commit), GIT_OBJECT_TAG)); #endif @@ -74,7 +74,7 @@ void test_object_lookup256__lookup_wrong_type_eventually_returns_enotfound(void) git_oid oid; git_object *object; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA256)); cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT)); git_object_free(object); @@ -96,7 +96,7 @@ void test_object_lookup256__lookup_corrupt_object_returns_error(void) git_object *object; size_t i; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA256)); cl_git_pass(git_str_joinpath(&path, git_repository_path(g_repo), file)); cl_git_pass(git_futils_readbuffer(&contents, path.ptr)); @@ -131,7 +131,7 @@ void test_object_lookup256__lookup_object_with_wrong_hash_returns_error(void) git_object *object; git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&oid, commit, GIT_OID_SHA256)); /* Copy object to another location with wrong hash */ cl_git_pass(git_str_joinpath(&oldpath, git_repository_path(g_repo), oldloose)); diff --git a/tests/libgit2/object/peel.c b/tests/libgit2/object/peel.c index da3ef17e2dc..7071628974b 100644 --- a/tests/libgit2/object/peel.c +++ b/tests/libgit2/object/peel.c @@ -23,12 +23,12 @@ static void assert_peel( git_object *obj; git_object *peeled; - cl_git_pass(git_oid__fromstr(&oid, sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, sha, GIT_OID_SHA1)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); cl_git_pass(git_object_peel(&peeled, obj, requested_type)); - cl_git_pass(git_oid__fromstr(&expected_oid, expected_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, expected_sha, GIT_OID_SHA1)); cl_assert_equal_oid(&expected_oid, git_object_id(peeled)); cl_assert_equal_i(expected_type, git_object_type(peeled)); @@ -43,7 +43,7 @@ static void assert_peel_error(int error, const char *sha, git_object_t requested git_object *obj; git_object *peeled; - cl_git_pass(git_oid__fromstr(&oid, sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, sha, GIT_OID_SHA1)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY)); cl_assert_equal_i(error, git_object_peel(&peeled, obj, requested_type)); diff --git a/tests/libgit2/object/raw/chars.c b/tests/libgit2/object/raw/chars.c index cb159e9ac4a..24d630d3861 100644 --- a/tests/libgit2/object/raw/chars.c +++ b/tests/libgit2/object/raw/chars.c @@ -19,10 +19,10 @@ void test_object_raw_chars__find_invalid_chars_in_oid(void) in[38] = (char)i; if (git__fromhex(i) >= 0) { exp[19] = (unsigned char)(git__fromhex(i) << 4); - cl_git_pass(git_oid__fromstr(&out, in, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&out, in, GIT_OID_SHA1)); cl_assert(memcmp(out.id, exp, GIT_OID_SHA1_SIZE) == 0); } else { - cl_git_fail(git_oid__fromstr(&out, in, GIT_OID_SHA1)); + cl_git_fail(git_oid_from_string(&out, in, GIT_OID_SHA1)); } } } @@ -36,6 +36,6 @@ void test_object_raw_chars__build_valid_oid_from_raw_bytes(void) 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; - git_oid__fromraw(&out, exp, GIT_OID_SHA1); + git_oid_from_raw(&out, exp, GIT_OID_SHA1); cl_git_pass(memcmp(out.id, exp, GIT_OID_SHA1_SIZE)); } diff --git a/tests/libgit2/object/raw/compare.c b/tests/libgit2/object/raw/compare.c index 9258eef41fe..ace751d75c1 100644 --- a/tests/libgit2/object/raw/compare.c +++ b/tests/libgit2/object/raw/compare.c @@ -13,7 +13,7 @@ void test_object_raw_compare__succeed_on_copy_oid(void) 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; memset(&b, 0, sizeof(b)); - git_oid__fromraw(&a, exp, GIT_OID_SHA1); + git_oid_from_raw(&a, exp, GIT_OID_SHA1); git_oid_cpy(&b, &a); cl_git_pass(memcmp(a.id, exp, GIT_OID_SHA1_SIZE)); } @@ -33,8 +33,8 @@ void test_object_raw_compare__succeed_on_oid_comparison_lesser(void) 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xf0, }; - git_oid__fromraw(&a, a_in, GIT_OID_SHA1); - git_oid__fromraw(&b, b_in, GIT_OID_SHA1); + git_oid_from_raw(&a, a_in, GIT_OID_SHA1); + git_oid_from_raw(&b, b_in, GIT_OID_SHA1); cl_assert(git_oid_cmp(&a, &b) < 0); } @@ -47,8 +47,8 @@ void test_object_raw_compare__succeed_on_oid_comparison_equal(void) 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; - git_oid__fromraw(&a, a_in, GIT_OID_SHA1); - git_oid__fromraw(&b, a_in, GIT_OID_SHA1); + git_oid_from_raw(&a, a_in, GIT_OID_SHA1); + git_oid_from_raw(&b, a_in, GIT_OID_SHA1); cl_assert(git_oid_cmp(&a, &b) == 0); } @@ -67,8 +67,8 @@ void test_object_raw_compare__succeed_on_oid_comparison_greater(void) 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xd0, }; - git_oid__fromraw(&a, a_in, GIT_OID_SHA1); - git_oid__fromraw(&b, b_in, GIT_OID_SHA1); + git_oid_from_raw(&a, a_in, GIT_OID_SHA1); + git_oid_from_raw(&b, b_in, GIT_OID_SHA1); cl_assert(git_oid_cmp(&a, &b) > 0); } @@ -78,7 +78,7 @@ void test_object_raw_compare__compare_fmt_oids(void) git_oid in; char out[GIT_OID_SHA1_HEXSIZE + 1]; - cl_git_pass(git_oid__fromstr(&in, exp, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&in, exp, GIT_OID_SHA1)); /* Format doesn't touch the last byte */ out[GIT_OID_SHA1_HEXSIZE] = 'Z'; @@ -96,7 +96,7 @@ void test_object_raw_compare__compare_static_oids(void) git_oid in; char *out; - cl_git_pass(git_oid__fromstr(&in, exp, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&in, exp, GIT_OID_SHA1)); out = git_oid_tostr_s(&in); cl_assert(out); @@ -110,7 +110,7 @@ void test_object_raw_compare__compare_pathfmt_oids(void) git_oid in; char out[GIT_OID_SHA1_HEXSIZE + 2]; - cl_git_pass(git_oid__fromstr(&in, exp1, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&in, exp1, GIT_OID_SHA1)); /* Format doesn't touch the last byte */ out[GIT_OID_SHA1_HEXSIZE + 1] = 'Z'; diff --git a/tests/libgit2/object/raw/convert.c b/tests/libgit2/object/raw/convert.c index 962476b97e1..ac2d9710db4 100644 --- a/tests/libgit2/object/raw/convert.c +++ b/tests/libgit2/object/raw/convert.c @@ -11,7 +11,7 @@ void test_object_raw_convert__succeed_on_oid_to_string_conversion(void) char *str; int i; - cl_git_pass(git_oid__fromstr(&in, exp, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&in, exp, GIT_OID_SHA1)); /* NULL buffer pointer, returns static empty string */ str = git_oid_tostr(NULL, sizeof(out), &in); @@ -55,7 +55,7 @@ void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void) char big[GIT_OID_SHA1_HEXSIZE + 1 + 3]; /* note + 4 => big buffer */ char *str; - cl_git_pass(git_oid__fromstr(&in, exp, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&in, exp, GIT_OID_SHA1)); /* place some tail material */ big[GIT_OID_SHA1_HEXSIZE+0] = 'W'; /* should be '\0' afterwards */ @@ -88,7 +88,7 @@ void test_object_raw_convert__convert_oid_partially(void) git_oid in; char big[GIT_OID_SHA1_HEXSIZE + 1 + 3]; /* note + 4 => big buffer */ - cl_git_pass(git_oid__fromstr(&in, exp, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&in, exp, GIT_OID_SHA1)); git_oid_nfmt(big, sizeof(big), &in); cl_assert_equal_s(exp, big); diff --git a/tests/libgit2/object/raw/fromstr.c b/tests/libgit2/object/raw/fromstr.c index 302d362d714..9eba6dca72f 100644 --- a/tests/libgit2/object/raw/fromstr.c +++ b/tests/libgit2/object/raw/fromstr.c @@ -6,9 +6,9 @@ void test_object_raw_fromstr__fail_on_invalid_oid_string(void) { git_oid out; - cl_git_fail(git_oid__fromstr(&out, "", GIT_OID_SHA1)); - cl_git_fail(git_oid__fromstr(&out, "moo", GIT_OID_SHA1)); - cl_git_fail(git_oid__fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5ez", GIT_OID_SHA1)); + cl_git_fail(git_oid_from_string(&out, "", GIT_OID_SHA1)); + cl_git_fail(git_oid_from_string(&out, "moo", GIT_OID_SHA1)); + cl_git_fail(git_oid_from_string(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5ez", GIT_OID_SHA1)); } void test_object_raw_fromstr__succeed_on_valid_oid_string(void) @@ -21,9 +21,9 @@ void test_object_raw_fromstr__succeed_on_valid_oid_string(void) 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; - cl_git_pass(git_oid__fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5e0", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5e0", GIT_OID_SHA1)); cl_git_pass(memcmp(out.id, exp, GIT_OID_SHA1_SIZE)); - cl_git_pass(git_oid__fromstr(&out, "16A67770B7D8D72317C4b775213C23A8BD74F5E0", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&out, "16A67770B7D8D72317C4b775213C23A8BD74F5E0", GIT_OID_SHA1)); cl_git_pass(memcmp(out.id, exp, GIT_OID_SHA1_SIZE)); } diff --git a/tests/libgit2/object/raw/hash.c b/tests/libgit2/object/raw/hash.c index 0df1afc3a5c..3bfaddaa23c 100644 --- a/tests/libgit2/object/raw/hash.c +++ b/tests/libgit2/object/raw/hash.c @@ -32,16 +32,16 @@ void test_object_raw_hash__hash_by_blocks(void) /* should already be init'd */ cl_git_pass(git_hash_update(&ctx, hello_text, strlen(hello_text))); cl_git_pass(git_hash_final(hash, &ctx)); - cl_git_pass(git_oid__fromraw(&id2, hash, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&id1, hello_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_raw(&id2, hash, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, hello_id, GIT_OID_SHA1)); cl_assert(git_oid_cmp(&id1, &id2) == 0); /* reinit should permit reuse */ cl_git_pass(git_hash_init(&ctx)); cl_git_pass(git_hash_update(&ctx, bye_text, strlen(bye_text))); cl_git_pass(git_hash_final(hash, &ctx)); - cl_git_pass(git_oid__fromraw(&id2, hash, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&id1, bye_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_raw(&id2, hash, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, bye_id, GIT_OID_SHA1)); cl_assert(git_oid_cmp(&id1, &id2) == 0); git_hash_ctx_cleanup(&ctx); @@ -52,9 +52,9 @@ void test_object_raw_hash__hash_buffer_in_single_call(void) git_oid id1, id2; unsigned char hash[GIT_HASH_SHA1_SIZE]; - cl_git_pass(git_oid__fromstr(&id1, hello_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, hello_id, GIT_OID_SHA1)); cl_git_pass(git_hash_buf(hash, hello_text, strlen(hello_text), GIT_HASH_ALGORITHM_SHA1)); - cl_git_pass(git_oid__fromraw(&id2, hash, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_raw(&id2, hash, GIT_OID_SHA1)); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -64,7 +64,7 @@ void test_object_raw_hash__hash_vector(void) git_str_vec vec[2]; unsigned char hash[GIT_HASH_SHA1_SIZE]; - cl_git_pass(git_oid__fromstr(&id1, hello_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, hello_id, GIT_OID_SHA1)); vec[0].data = hello_text; vec[0].len = 4; @@ -72,7 +72,7 @@ void test_object_raw_hash__hash_vector(void) vec[1].len = strlen(hello_text)-4; git_hash_vec(hash, vec, 2, GIT_HASH_ALGORITHM_SHA1); - git_oid__fromraw(&id2, hash, GIT_OID_SHA1); + git_oid_from_raw(&id2, hash, GIT_OID_SHA1); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -81,7 +81,7 @@ void test_object_raw_hash__hash_junk_data(void) { git_oid id, id_zero; - cl_git_pass(git_oid__fromstr(&id_zero, zero_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id_zero, zero_id, GIT_OID_SHA1)); /* invalid types: */ junk_obj.data = some_data; @@ -116,7 +116,7 @@ void test_object_raw_hash__hash_commit_object(void) { git_oid id1, id2; - cl_git_pass(git_oid__fromstr(&id1, commit_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, commit_id, GIT_OID_SHA1)); hash_object_pass(&id2, &commit_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -125,7 +125,7 @@ void test_object_raw_hash__hash_tree_object(void) { git_oid id1, id2; - cl_git_pass(git_oid__fromstr(&id1, tree_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, tree_id, GIT_OID_SHA1)); hash_object_pass(&id2, &tree_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -134,7 +134,7 @@ void test_object_raw_hash__hash_tag_object(void) { git_oid id1, id2; - cl_git_pass(git_oid__fromstr(&id1, tag_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, tag_id, GIT_OID_SHA1)); hash_object_pass(&id2, &tag_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -143,7 +143,7 @@ void test_object_raw_hash__hash_zero_length_object(void) { git_oid id1, id2; - cl_git_pass(git_oid__fromstr(&id1, zero_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, zero_id, GIT_OID_SHA1)); hash_object_pass(&id2, &zero_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -152,7 +152,7 @@ void test_object_raw_hash__hash_one_byte_object(void) { git_oid id1, id2; - cl_git_pass(git_oid__fromstr(&id1, one_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, one_id, GIT_OID_SHA1)); hash_object_pass(&id2, &one_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -161,7 +161,7 @@ void test_object_raw_hash__hash_two_byte_object(void) { git_oid id1, id2; - cl_git_pass(git_oid__fromstr(&id1, two_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, two_id, GIT_OID_SHA1)); hash_object_pass(&id2, &two_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } @@ -170,7 +170,7 @@ void test_object_raw_hash__hash_multi_byte_object(void) { git_oid id1, id2; - cl_git_pass(git_oid__fromstr(&id1, some_id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, some_id, GIT_OID_SHA1)); hash_object_pass(&id2, &some_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } diff --git a/tests/libgit2/object/raw/short.c b/tests/libgit2/object/raw/short.c index f867e6ba173..c6d1a4fc1aa 100644 --- a/tests/libgit2/object/raw/short.c +++ b/tests/libgit2/object/raw/short.c @@ -36,7 +36,7 @@ static int insert_sequential_oids( p_snprintf(numbuf, sizeof(numbuf), "%u", (unsigned int)i); git_hash_buf(hashbuf, numbuf, strlen(numbuf), GIT_HASH_ALGORITHM_SHA1); - git_oid__fromraw(&oid, hashbuf, GIT_OID_SHA1); + git_oid_from_raw(&oid, hashbuf, GIT_OID_SHA1); oids[i] = git__malloc(GIT_OID_SHA1_HEXSIZE + 1); cl_assert(oids[i]); diff --git a/tests/libgit2/object/raw/write.c b/tests/libgit2/object/raw/write.c index b95deffdbfe..dd6fca08f7d 100644 --- a/tests/libgit2/object/raw/write.c +++ b/tests/libgit2/object/raw/write.c @@ -67,7 +67,7 @@ void test_body(object_data *d, git_rawobj *o) make_odb_dir(); cl_git_pass(git_odb_open_ext(&db, odb_dir, NULL)); - cl_git_pass(git_oid__fromstr(&id1, d->id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id1, d->id, GIT_OID_SHA1)); streaming_write(&id2, db, o); cl_assert(git_oid_cmp(&id1, &id2) == 0); diff --git a/tests/libgit2/object/shortid.c b/tests/libgit2/object/shortid.c index 3657a419884..4af9b45aeaf 100644 --- a/tests/libgit2/object/shortid.c +++ b/tests/libgit2/object/shortid.c @@ -18,28 +18,28 @@ void test_object_shortid__select(void) git_object *obj; git_buf shorty = {0}; - git_oid__fromstr(&full, "ce013625030ba8dba906f756967f9e9ca394464a", GIT_OID_SHA1); + git_oid_from_string(&full, "ce013625030ba8dba906f756967f9e9ca394464a", GIT_OID_SHA1); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJECT_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(7, shorty.size); cl_assert_equal_s("ce01362", shorty.ptr); git_object_free(obj); - git_oid__fromstr(&full, "038d718da6a1ebbc6a7780a96ed75a70cc2ad6e2", GIT_OID_SHA1); + git_oid_from_string(&full, "038d718da6a1ebbc6a7780a96ed75a70cc2ad6e2", GIT_OID_SHA1); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJECT_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(7, shorty.size); cl_assert_equal_s("038d718", shorty.ptr); git_object_free(obj); - git_oid__fromstr(&full, "dea509d097ce692e167dfc6a48a7a280cc5e877e", GIT_OID_SHA1); + git_oid_from_string(&full, "dea509d097ce692e167dfc6a48a7a280cc5e877e", GIT_OID_SHA1); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJECT_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(9, shorty.size); cl_assert_equal_s("dea509d09", shorty.ptr); git_object_free(obj); - git_oid__fromstr(&full, "dea509d0b3cb8ee0650f6ca210bc83f4678851ba", GIT_OID_SHA1); + git_oid_from_string(&full, "dea509d0b3cb8ee0650f6ca210bc83f4678851ba", GIT_OID_SHA1); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJECT_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(9, shorty.size); @@ -57,7 +57,7 @@ void test_object_shortid__core_abbrev(void) git_config *cfg; cl_git_pass(git_repository_config(&cfg, _repo)); - git_oid__fromstr(&full, "ce013625030ba8dba906f756967f9e9ca394464a", GIT_OID_SHA1); + git_oid_from_string(&full, "ce013625030ba8dba906f756967f9e9ca394464a", GIT_OID_SHA1); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJECT_ANY)); cl_git_pass(git_config_set_string(cfg, "core.abbrev", "auto")); diff --git a/tests/libgit2/object/tag/parse.c b/tests/libgit2/object/tag/parse.c index d7a4d85bfda..a5dec1889f1 100644 --- a/tests/libgit2/object/tag/parse.c +++ b/tests/libgit2/object/tag/parse.c @@ -19,7 +19,7 @@ static void assert_tag_parses(const char *data, size_t datalen, if (expected_oid) { git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, expected_oid, GIT_OID_SHA1)); cl_assert_equal_oid(&oid, &tag->target); } diff --git a/tests/libgit2/object/tag/peel.c b/tests/libgit2/object/tag/peel.c index db81c5aee2b..0ee8d50428f 100644 --- a/tests/libgit2/object/tag/peel.c +++ b/tests/libgit2/object/tag/peel.c @@ -29,7 +29,7 @@ static void retrieve_tag_from_oid(git_tag **tag_out, git_repository *repo, const { git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, sha, GIT_OID_SHA1)); cl_git_pass(git_tag_lookup(tag_out, repo, &oid)); } diff --git a/tests/libgit2/object/tag/read.c b/tests/libgit2/object/tag/read.c index 6270b567ae3..3bb559ae204 100644 --- a/tests/libgit2/object/tag/read.c +++ b/tests/libgit2/object/tag/read.c @@ -32,9 +32,9 @@ void test_object_tag_read__parse(void) git_commit *commit; git_oid id1, id2, id_commit; - git_oid__fromstr(&id1, tag1_id, GIT_OID_SHA1); - git_oid__fromstr(&id2, tag2_id, GIT_OID_SHA1); - git_oid__fromstr(&id_commit, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&id1, tag1_id, GIT_OID_SHA1); + git_oid_from_string(&id2, tag2_id, GIT_OID_SHA1); + git_oid_from_string(&id_commit, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_tag_lookup(&tag1, g_repo, &id1)); @@ -67,8 +67,8 @@ void test_object_tag_read__parse_without_tagger(void) /* TODO: This is a little messy */ cl_git_pass(git_repository_open(&bad_tag_repo, cl_fixture("bad_tag.git"))); - git_oid__fromstr(&id, bad_tag_id, GIT_OID_SHA1); - git_oid__fromstr(&id_commit, badly_tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&id, bad_tag_id, GIT_OID_SHA1); + git_oid_from_string(&id_commit, badly_tagged_commit, GIT_OID_SHA1); cl_git_pass(git_tag_lookup(&bad_tag, bad_tag_repo, &id)); cl_assert(bad_tag != NULL); @@ -99,8 +99,8 @@ void test_object_tag_read__parse_without_message(void) /* TODO: This is a little messy */ cl_git_pass(git_repository_open(&short_tag_repo, cl_fixture("short_tag.git"))); - git_oid__fromstr(&id, short_tag_id, GIT_OID_SHA1); - git_oid__fromstr(&id_commit, short_tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&id, short_tag_id, GIT_OID_SHA1); + git_oid_from_string(&id_commit, short_tagged_commit, GIT_OID_SHA1); cl_git_pass(git_tag_lookup(&short_tag, short_tag_repo, &id)); cl_assert(short_tag != NULL); @@ -127,7 +127,7 @@ void test_object_tag_read__without_tagger_nor_message(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); - cl_git_pass(git_oid__fromstr(&id, taggerless, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, taggerless, GIT_OID_SHA1)); cl_git_pass(git_tag_lookup(&tag, repo, &id)); diff --git a/tests/libgit2/object/tag/write.c b/tests/libgit2/object/tag/write.c index 79e01452a3a..f3090efc9fc 100644 --- a/tests/libgit2/object/tag/write.c +++ b/tests/libgit2/object/tag/write.c @@ -30,7 +30,7 @@ void test_object_tag_write__basic(void) git_reference *ref_tag; git_object *target; - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); /* create signature */ @@ -72,7 +72,7 @@ void test_object_tag_write__overwrite(void) git_signature *tagger; git_object *target; - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); /* create signature */ @@ -99,7 +99,7 @@ void test_object_tag_write__replace(void) git_reference *ref_tag; git_object *target; - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); cl_git_pass(git_reference_lookup(&ref_tag, g_repo, "refs/tags/e90810b")); @@ -135,7 +135,7 @@ void test_object_tag_write__lightweight(void) git_reference *ref_tag; git_object *target; - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); cl_git_pass(git_tag_create_lightweight( @@ -163,7 +163,7 @@ void test_object_tag_write__lightweight_over_existing(void) git_oid target_id, object_id, existing_object_id; git_object *target; - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); cl_assert_equal_i(GIT_EEXISTS, git_tag_create_lightweight( @@ -173,7 +173,7 @@ void test_object_tag_write__lightweight_over_existing(void) target, 0)); - git_oid__fromstr(&existing_object_id, tag2_id, GIT_OID_SHA1); + git_oid_from_string(&existing_object_id, tag2_id, GIT_OID_SHA1); cl_assert(git_oid_cmp(&object_id, &existing_object_id) == 0); git_object_free(target); @@ -197,7 +197,7 @@ void test_object_tag_write__creating_with_an_invalid_name_returns_EINVALIDSPEC(v git_signature *tagger; git_object *target; - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); @@ -229,7 +229,7 @@ static void create_annotation(git_oid *tag_id, const char *name) cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); cl_git_pass(git_tag_annotation_create(tag_id, g_repo, name, target, tagger, "boom!")); @@ -265,7 +265,7 @@ void test_object_tag_write__error_when_create_tag_with_invalid_name(void) git_signature *tagger; git_object *target; - git_oid__fromstr(&target_id, tagged_commit, GIT_OID_SHA1); + git_oid_from_string(&target_id, tagged_commit, GIT_OID_SHA1); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT)); cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); diff --git a/tests/libgit2/object/tree/attributes.c b/tests/libgit2/object/tree/attributes.c index 285d19804f5..516ab6e58fe 100644 --- a/tests/libgit2/object/tree/attributes.c +++ b/tests/libgit2/object/tree/attributes.c @@ -21,7 +21,7 @@ void test_object_tree_attributes__ensure_correctness_of_attributes_on_insertion( git_treebuilder *builder; git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, blob_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, blob_oid, GIT_OID_SHA1)); cl_git_pass(git_treebuilder_new(&builder, repo, NULL)); @@ -39,7 +39,7 @@ void test_object_tree_attributes__group_writable_tree_entries_created_with_an_an const git_tree_entry *entry; - cl_git_pass(git_oid__fromstr(&tid, tree_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tid, tree_oid, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, repo, &tid)); entry = git_tree_entry_byname(tree, "old_mode.txt"); @@ -56,7 +56,7 @@ void test_object_tree_attributes__treebuilder_reject_invalid_filemode(void) git_oid bid; const git_tree_entry *entry; - cl_git_pass(git_oid__fromstr(&bid, blob_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&bid, blob_oid, GIT_OID_SHA1)); cl_git_pass(git_treebuilder_new(&builder, repo, NULL)); cl_git_fail(git_treebuilder_insert( @@ -76,7 +76,7 @@ void test_object_tree_attributes__normalize_attributes_when_creating_a_tree_from git_tree *tree; const git_tree_entry *entry; - cl_git_pass(git_oid__fromstr(&tid, tree_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tid, tree_oid, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, repo, &tid)); cl_git_pass(git_treebuilder_new(&builder, repo, tree)); @@ -107,7 +107,7 @@ void test_object_tree_attributes__normalize_600(void) git_tree *tree; const git_tree_entry *entry; - git_oid__fromstr(&id, "0810fb7818088ff5ac41ee49199b51473b1bd6c7", GIT_OID_SHA1); + git_oid_from_string(&id, "0810fb7818088ff5ac41ee49199b51473b1bd6c7", GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, repo, &id)); entry = git_tree_entry_byname(tree, "ListaTeste.xml"); diff --git a/tests/libgit2/object/tree/duplicateentries.c b/tests/libgit2/object/tree/duplicateentries.c index e9774cac378..b137339c818 100644 --- a/tests/libgit2/object/tree/duplicateentries.c +++ b/tests/libgit2/object/tree/duplicateentries.c @@ -45,7 +45,7 @@ static void tree_checker( cl_assert_equal_i(1, (int)git_tree_entrycount(tree)); entry = git_tree_entry_byindex(tree, 0); - cl_git_pass(git_oid__fromstr(&oid, expected_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, expected_sha, GIT_OID_SHA1)); cl_assert_equal_i(0, git_oid_cmp(&oid, git_tree_entry_id(entry))); cl_assert_equal_i(expected_filemode, git_tree_entry_filemode(entry)); @@ -70,7 +70,7 @@ static void two_blobs(git_treebuilder *bld) git_oid oid; const git_tree_entry *entry; - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); /* blob oid (README) */ @@ -78,7 +78,7 @@ static void two_blobs(git_treebuilder *bld) &entry, bld, "duplicate", &oid, GIT_FILEMODE_BLOB)); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_OID_SHA1)); /* blob oid (new.txt) */ @@ -92,7 +92,7 @@ static void one_blob_and_one_tree(git_treebuilder *bld) git_oid oid; const git_tree_entry *entry; - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1)); /* blob oid (README) */ @@ -100,7 +100,7 @@ static void one_blob_and_one_tree(git_treebuilder *bld) &entry, bld, "duplicate", &oid, GIT_FILEMODE_BLOB)); - cl_git_pass(git_oid__fromstr(&oid, + cl_git_pass(git_oid_from_string(&oid, "4e0883eeeeebc1fb1735161cea82f7cb5fab7e63", GIT_OID_SHA1)); /* tree oid (a) */ @@ -131,17 +131,17 @@ static void add_fake_conflicts(git_index *index) ancestor_entry.path = "duplicate"; ancestor_entry.mode = GIT_FILEMODE_BLOB; GIT_INDEX_ENTRY_STAGE_SET(&ancestor_entry, 1); - git_oid__fromstr(&ancestor_entry.id, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1); + git_oid_from_string(&ancestor_entry.id, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", GIT_OID_SHA1); our_entry.path = "duplicate"; our_entry.mode = GIT_FILEMODE_BLOB; GIT_INDEX_ENTRY_STAGE_SET(&our_entry, 2); - git_oid__fromstr(&our_entry.id, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", GIT_OID_SHA1); + git_oid_from_string(&our_entry.id, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", GIT_OID_SHA1); their_entry.path = "duplicate"; their_entry.mode = GIT_FILEMODE_BLOB; GIT_INDEX_ENTRY_STAGE_SET(&their_entry, 3); - git_oid__fromstr(&their_entry.id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_OID_SHA1); + git_oid_from_string(&their_entry.id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_OID_SHA1); cl_git_pass(git_index_conflict_add(index, &ancestor_entry, &our_entry, &their_entry)); } diff --git a/tests/libgit2/object/tree/frompath.c b/tests/libgit2/object/tree/frompath.c index 147e53e9311..1563f71b92d 100644 --- a/tests/libgit2/object/tree/frompath.c +++ b/tests/libgit2/object/tree/frompath.c @@ -11,7 +11,7 @@ void test_object_tree_frompath__initialize(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_assert(repo != NULL); - cl_git_pass(git_oid__fromstr(&id, tree_with_subtrees_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, tree_with_subtrees_oid, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, repo, &id)); cl_assert(tree != NULL); } diff --git a/tests/libgit2/object/tree/parse.c b/tests/libgit2/object/tree/parse.c index fc985d672d8..11433c4307f 100644 --- a/tests/libgit2/object/tree/parse.c +++ b/tests/libgit2/object/tree/parse.c @@ -35,7 +35,7 @@ static void assert_tree_parses(const char *data, size_t datalen, const git_tree_entry *entry; git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, expected->oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, expected->oid, GIT_OID_SHA1)); cl_assert(entry = git_tree_entry_byname(tree, expected->filename)); cl_assert_equal_s(expected->filename, entry->filename); diff --git a/tests/libgit2/object/tree/read.c b/tests/libgit2/object/tree/read.c index e18637f035e..cea66e165f9 100644 --- a/tests/libgit2/object/tree/read.c +++ b/tests/libgit2/object/tree/read.c @@ -25,7 +25,7 @@ void test_object_tree_read__loaded(void) git_oid id; git_tree *tree; - git_oid__fromstr(&id, tree_oid, GIT_OID_SHA1); + git_oid_from_string(&id, tree_oid, GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); @@ -48,7 +48,7 @@ void test_object_tree_read__two(void) const git_tree_entry *entry; git_object *obj; - git_oid__fromstr(&id, tree_oid, GIT_OID_SHA1); + git_oid_from_string(&id, tree_oid, GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); diff --git a/tests/libgit2/object/tree/update.c b/tests/libgit2/object/tree/update.c index 13373b6c4f7..8fb99b95826 100644 --- a/tests/libgit2/object/tree/update.c +++ b/tests/libgit2/object/tree/update.c @@ -25,7 +25,7 @@ void test_object_tree_update__remove_blob(void) { GIT_TREE_UPDATE_REMOVE, GIT_OID_SHA1_ZERO, GIT_FILEMODE_BLOB /* ignored */, path}, }; - cl_git_pass(git_oid__fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ @@ -54,7 +54,7 @@ void test_object_tree_update__remove_blob_deeper(void) { GIT_TREE_UPDATE_REMOVE, GIT_OID_SHA1_ZERO, GIT_FILEMODE_BLOB /* ignored */, path}, }; - cl_git_pass(git_oid__fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ @@ -85,7 +85,7 @@ void test_object_tree_update__remove_all_entries(void) { GIT_TREE_UPDATE_REMOVE, GIT_OID_SHA1_ZERO, GIT_FILEMODE_BLOB /* ignored */, path2}, }; - cl_git_pass(git_oid__fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ @@ -116,7 +116,7 @@ void test_object_tree_update__replace_blob(void) { GIT_TREE_UPDATE_UPSERT, GIT_OID_SHA1_ZERO, GIT_FILEMODE_BLOB, path}, }; - cl_git_pass(git_oid__fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id)); /* Create it with an index */ @@ -124,7 +124,7 @@ void test_object_tree_update__replace_blob(void) cl_git_pass(git_index_read_tree(idx, base_tree)); entry.path = path; - cl_git_pass(git_oid__fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); entry.mode = GIT_FILEMODE_BLOB; cl_git_pass(git_index_add(idx, &entry)); @@ -132,7 +132,7 @@ void test_object_tree_update__replace_blob(void) git_index_free(idx); /* Perform the same operation via the tree updater */ - cl_git_pass(git_oid__fromstr(&updates[0].id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&updates[0].id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 1, updates)); cl_assert_equal_oid(&tree_index_id, &tree_updater_id); @@ -159,13 +159,13 @@ void test_object_tree_update__add_blobs(void) { GIT_TREE_UPDATE_UPSERT, GIT_OID_SHA1_ZERO, GIT_FILEMODE_BLOB, paths[2]}, }; - cl_git_pass(git_oid__fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); for (i = 0; i < 3; i++) { - cl_git_pass(git_oid__fromstr(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); } for (i = 0; i < 2; i++) { @@ -216,13 +216,13 @@ void test_object_tree_update__add_blobs_unsorted(void) { GIT_TREE_UPDATE_UPSERT, GIT_OID_SHA1_ZERO, GIT_FILEMODE_BLOB, paths[2]}, }; - cl_git_pass(git_oid__fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b", GIT_OID_SHA1)); entry.mode = GIT_FILEMODE_BLOB; - cl_git_pass(git_oid__fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); for (i = 0; i < 3; i++) { - cl_git_pass(git_oid__fromstr(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); } for (i = 0; i < 2; i++) { @@ -264,7 +264,7 @@ void test_object_tree_update__add_conflict(void) }; for (i = 0; i < 2; i++) { - cl_git_pass(git_oid__fromstr(&updates[i].id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&updates[i].id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_OID_SHA1)); } cl_git_fail(git_tree_create_updated(&tree_updater_id, g_repo, NULL, 2, updates)); @@ -280,7 +280,7 @@ void test_object_tree_update__add_conflict2(void) }; for (i = 0; i < 2; i++) { - cl_git_pass(git_oid__fromstr(&updates[i].id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&updates[i].id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_OID_SHA1)); } cl_git_fail(git_tree_create_updated(&tree_updater_id, g_repo, NULL, 2, updates)); @@ -295,7 +295,7 @@ void test_object_tree_update__remove_invalid_submodule(void) }; /* This tree contains a submodule with an all-zero commit for a submodule named 'submodule' */ - cl_git_pass(git_oid__fromstr(&baseline_id, "396c7f1adb7925f51ba13a75f48252f44c5a14a2", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&baseline_id, "396c7f1adb7925f51ba13a75f48252f44c5a14a2", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&baseline, g_repo, &baseline_id)); cl_git_pass(git_tree_create_updated(&updated_tree_id, g_repo, baseline, 1, updates)); diff --git a/tests/libgit2/object/tree/walk.c b/tests/libgit2/object/tree/walk.c index 573a278493a..ee93b7c9a48 100644 --- a/tests/libgit2/object/tree/walk.c +++ b/tests/libgit2/object/tree/walk.c @@ -33,7 +33,7 @@ void test_object_tree_walk__0(void) git_tree *tree; int ct; - git_oid__fromstr(&id, tree_oid, GIT_OID_SHA1); + git_oid_from_string(&id, tree_oid, GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); @@ -77,7 +77,7 @@ void test_object_tree_walk__1(void) git_tree *tree; int ct; - git_oid__fromstr(&id, tree_oid, GIT_OID_SHA1); + git_oid_from_string(&id, tree_oid, GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); @@ -138,7 +138,7 @@ void test_object_tree_walk__2(void) struct treewalk_skip_data data; /* look up a deep tree */ - git_oid__fromstr(&id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1); + git_oid_from_string(&id, "ae90f12eea699729ed24555e40b9fd669da12a12", GIT_OID_SHA1); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); memset(&data, 0, sizeof(data)); diff --git a/tests/libgit2/object/tree/write.c b/tests/libgit2/object/tree/write.c index 71a4c54f60d..ed74aca4aae 100644 --- a/tests/libgit2/object/tree/write.c +++ b/tests/libgit2/object/tree/write.c @@ -29,9 +29,9 @@ void test_object_tree_write__from_memory(void) git_tree *tree; git_oid id, bid, rid, id2; - git_oid__fromstr(&id, first_tree, GIT_OID_SHA1); - git_oid__fromstr(&id2, second_tree, GIT_OID_SHA1); - git_oid__fromstr(&bid, blob_oid, GIT_OID_SHA1); + git_oid_from_string(&id, first_tree, GIT_OID_SHA1); + git_oid_from_string(&id2, second_tree, GIT_OID_SHA1); + git_oid_from_string(&bid, blob_oid, GIT_OID_SHA1); /* create a second tree from first tree using `git_treebuilder_insert` * on REPOSITORY_FOLDER. @@ -71,10 +71,10 @@ void test_object_tree_write__subtree(void) git_oid id, bid, subtree_id, id2, id3; git_oid id_hiearar; - git_oid__fromstr(&id, first_tree, GIT_OID_SHA1); - git_oid__fromstr(&id2, second_tree, GIT_OID_SHA1); - git_oid__fromstr(&id3, third_tree, GIT_OID_SHA1); - git_oid__fromstr(&bid, blob_oid, GIT_OID_SHA1); + git_oid_from_string(&id, first_tree, GIT_OID_SHA1); + git_oid_from_string(&id2, second_tree, GIT_OID_SHA1); + git_oid_from_string(&id3, third_tree, GIT_OID_SHA1); + git_oid_from_string(&bid, blob_oid, GIT_OID_SHA1); /* create subtree */ cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL)); @@ -135,8 +135,8 @@ void test_object_tree_write__sorted_subtrees(void) git_oid bid, tid, tree_oid; - cl_git_pass(git_oid__fromstr(&bid, blob_oid, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&tid, first_tree, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&bid, blob_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tid, first_tree, GIT_OID_SHA1)); cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL)); @@ -195,7 +195,7 @@ void test_object_tree_write__removing_and_re_adding_in_treebuilder(void) git_oid entry_oid, tree_oid; git_tree *tree; - cl_git_pass(git_oid__fromstr(&entry_oid, blob_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry_oid, blob_oid, GIT_OID_SHA1)); cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL)); @@ -286,7 +286,7 @@ void test_object_tree_write__filtering(void) git_oid entry_oid, tree_oid; git_tree *tree; - git_oid__fromstr(&entry_oid, blob_oid, GIT_OID_SHA1); + git_oid_from_string(&entry_oid, blob_oid, GIT_OID_SHA1); cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL)); @@ -348,7 +348,7 @@ void test_object_tree_write__cruel_paths(void) int count = 0, i, j; git_tree_entry *te; - git_oid__fromstr(&bid, blob_oid, GIT_OID_SHA1); + git_oid_from_string(&bid, blob_oid, GIT_OID_SHA1); /* create tree */ cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL)); @@ -411,7 +411,7 @@ void test_object_tree_write__protect_filesystems(void) git_treebuilder *builder; git_oid bid; - cl_git_pass(git_oid__fromstr(&bid, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&bid, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); /* Ensure that (by default) we can write objects with funny names on * platforms that are not affected. @@ -460,12 +460,12 @@ static void test_invalid_objects(bool should_allow_invalid) "Expected function call to fail: " #expr), \ NULL, 1) - cl_git_pass(git_oid__fromstr(&valid_blob_id, blob_oid, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&invalid_blob_id, + cl_git_pass(git_oid_from_string(&valid_blob_id, blob_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&invalid_blob_id, "1234567890123456789012345678901234567890", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&valid_tree_id, first_tree, GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&invalid_tree_id, + cl_git_pass(git_oid_from_string(&valid_tree_id, first_tree, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&invalid_tree_id, "0000000000111111111122222222223333333333", GIT_OID_SHA1)); @@ -497,7 +497,7 @@ static void test_inserting_submodule(void) git_treebuilder *bld; git_oid sm_id; - cl_git_pass(git_oid__fromstr(&sm_id, "da39a3ee5e6b4b0d3255bfef95601890afd80709", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&sm_id, "da39a3ee5e6b4b0d3255bfef95601890afd80709", GIT_OID_SHA1)); cl_git_pass(git_treebuilder_new(&bld, g_repo, NULL)); cl_git_pass(git_treebuilder_insert(NULL, bld, "sm", &sm_id, GIT_FILEMODE_COMMIT)); git_treebuilder_free(bld); diff --git a/tests/libgit2/odb/alternates.c b/tests/libgit2/odb/alternates.c index 4d2da6b1f39..aeadcc9d2e4 100644 --- a/tests/libgit2/odb/alternates.c +++ b/tests/libgit2/odb/alternates.c @@ -52,7 +52,7 @@ void test_odb_alternates__chained(void) /* Now load B and see if we can find an object from testrepo.git */ cl_git_pass(git_repository_open(&repo, paths[1])); - git_oid__fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); git_commit_free(commit); git_repository_free(repo); @@ -74,7 +74,7 @@ void test_odb_alternates__long_chain(void) /* Now load the last one and see if we can find an object from testrepo.git */ cl_git_pass(git_repository_open(&repo, paths[ARRAY_SIZE(paths)-1])); - git_oid__fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_fail(git_commit_lookup(&commit, repo, &oid)); git_repository_free(repo); } diff --git a/tests/libgit2/odb/backend/backend_helpers.c b/tests/libgit2/odb/backend/backend_helpers.c index c1a0070d6b3..d4d04b22c52 100644 --- a/tests/libgit2/odb/backend/backend_helpers.c +++ b/tests/libgit2/odb/backend/backend_helpers.c @@ -9,7 +9,7 @@ static int search_object(const fake_object **out, fake_backend *fake, const git_ while (obj && obj->oid) { git_oid current_oid; - git_oid__fromstr(¤t_oid, obj->oid, GIT_OID_SHA1); + git_oid_from_string(¤t_oid, obj->oid, GIT_OID_SHA1); if (git_oid_ncmp(¤t_oid, oid, len) == 0) { if (found) @@ -52,7 +52,7 @@ static int fake_backend__exists_prefix( return error; if (out) - git_oid__fromstr(out, obj->oid, GIT_OID_SHA1); + git_oid_from_string(out, obj->oid, GIT_OID_SHA1); return 0; } @@ -115,7 +115,7 @@ static int fake_backend__read_prefix( if ((error = search_object(&obj, fake, short_oid, len)) < 0) return error; - git_oid__fromstr(out_oid, obj->oid, GIT_OID_SHA1); + git_oid_from_string(out_oid, obj->oid, GIT_OID_SHA1); *len_p = strlen(obj->content); *buffer_p = git__strdup(obj->content); *type_p = GIT_OBJECT_BLOB; diff --git a/tests/libgit2/odb/backend/loose.c b/tests/libgit2/odb/backend/loose.c index 4e17bb96fe8..d917ca8ae4b 100644 --- a/tests/libgit2/odb/backend/loose.c +++ b/tests/libgit2/odb/backend/loose.c @@ -37,11 +37,11 @@ void test_odb_backend_loose__read_from_odb(void) git_oid oid; git_odb_object *obj; - cl_git_pass(git_oid__fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); cl_git_pass(git_odb_read(&obj, _odb, &oid)); git_odb_object_free(obj); - cl_git_pass(git_oid__fromstr(&oid, "fd093bff70906175335656e6ce6ae05783708765", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "fd093bff70906175335656e6ce6ae05783708765", GIT_OID_SHA1)); cl_git_pass(git_odb_read(&obj, _odb, &oid)); git_odb_object_free(obj); } @@ -52,11 +52,11 @@ void test_odb_backend_loose__read_from_repo(void) git_blob *blob; git_tree *tree; - cl_git_pass(git_oid__fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); cl_git_pass(git_blob_lookup(&blob, _repo, &oid)); git_blob_free(blob); - cl_git_pass(git_oid__fromstr(&oid, "fd093bff70906175335656e6ce6ae05783708765", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "fd093bff70906175335656e6ce6ae05783708765", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, _repo, &oid)); git_tree_free(tree); } diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c index 036b13a5170..89e09577c1e 100644 --- a/tests/libgit2/odb/backend/mempack.c +++ b/tests/libgit2/odb/backend/mempack.c @@ -34,13 +34,13 @@ void test_odb_backend_mempack__write_succeeds(void) void test_odb_backend_mempack__read_of_missing_object_fails(void) { - cl_git_pass(git_oid__fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid)); } void test_odb_backend_mempack__exists_of_missing_object_fails(void) { - cl_git_pass(git_oid__fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); cl_assert(git_odb_exists(_odb, &_oid) == 0); } diff --git a/tests/libgit2/odb/backend/multiple.c b/tests/libgit2/odb/backend/multiple.c index 97588164db9..689fbc2140a 100644 --- a/tests/libgit2/odb/backend/multiple.c +++ b/tests/libgit2/odb/backend/multiple.c @@ -24,7 +24,7 @@ void test_odb_backend_multiple__initialize(void) { git_odb_backend *backend; - git_oid__fromstr(&_existing_oid, EXISTING_HASH, GIT_OID_SHA1); + git_oid_from_string(&_existing_oid, EXISTING_HASH, GIT_OID_SHA1); _obj = NULL; _repo = cl_git_sandbox_init("testrepo.git"); diff --git a/tests/libgit2/odb/backend/nonrefreshing.c b/tests/libgit2/odb/backend/nonrefreshing.c index 5084eb7f746..82e0ab05352 100644 --- a/tests/libgit2/odb/backend/nonrefreshing.c +++ b/tests/libgit2/odb/backend/nonrefreshing.c @@ -33,8 +33,8 @@ static void setup_repository_and_backend(void) void test_odb_backend_nonrefreshing__initialize(void) { - git_oid__fromstr(&_nonexisting_oid, NONEXISTING_HASH, GIT_OID_SHA1); - git_oid__fromstr(&_existing_oid, EXISTING_HASH, GIT_OID_SHA1); + git_oid_from_string(&_nonexisting_oid, NONEXISTING_HASH, GIT_OID_SHA1); + git_oid_from_string(&_existing_oid, EXISTING_HASH, GIT_OID_SHA1); setup_repository_and_backend(); } diff --git a/tests/libgit2/odb/backend/refreshing.c b/tests/libgit2/odb/backend/refreshing.c index fcba748ee0d..cf82630df26 100644 --- a/tests/libgit2/odb/backend/refreshing.c +++ b/tests/libgit2/odb/backend/refreshing.c @@ -33,8 +33,8 @@ static void setup_repository_and_backend(void) void test_odb_backend_refreshing__initialize(void) { - git_oid__fromstr(&_nonexisting_oid, NONEXISTING_HASH, GIT_OID_SHA1); - git_oid__fromstr(&_existing_oid, EXISTING_HASH, GIT_OID_SHA1); + git_oid_from_string(&_nonexisting_oid, NONEXISTING_HASH, GIT_OID_SHA1); + git_oid_from_string(&_existing_oid, EXISTING_HASH, GIT_OID_SHA1); setup_repository_and_backend(); } diff --git a/tests/libgit2/odb/backend/simple.c b/tests/libgit2/odb/backend/simple.c index 25dfd90a2e2..da52d307f06 100644 --- a/tests/libgit2/odb/backend/simple.c +++ b/tests/libgit2/odb/backend/simple.c @@ -49,7 +49,7 @@ void test_odb_backend_simple__read_of_object_succeeds(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); assert_object_contains(_obj, objs[0].content); @@ -64,7 +64,7 @@ void test_odb_backend_simple__read_of_nonexisting_object_fails(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid)); } @@ -77,7 +77,7 @@ void test_odb_backend_simple__read_with_hash_mismatch_fails(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_fail_with(GIT_EMISMATCH, git_odb_read(&_obj, _odb, &_oid)); } @@ -89,7 +89,7 @@ void test_odb_backend_simple__read_with_hash_mismatch_succeeds_without_verificat }; setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); @@ -106,7 +106,7 @@ void test_odb_backend_simple__read_prefix_succeeds(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4632", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4632", GIT_OID_SHA1)); cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); assert_object_contains(_obj, objs[0].content); @@ -122,7 +122,7 @@ void test_odb_backend_simple__read_prefix_of_nonexisting_object_fails(void) setup_backend(objs); - cl_git_pass(git_oid__fromstrn(&_oid, hash, strlen(hash), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&_oid, hash, strlen(hash), GIT_OID_SHA1)); cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid)); } @@ -136,7 +136,7 @@ void test_odb_backend_simple__read_with_ambiguous_prefix_fails(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 7)); } @@ -150,7 +150,7 @@ void test_odb_backend_simple__read_with_highly_ambiguous_prefix(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 39)); cl_git_pass(git_odb_read_prefix(&_obj, _odb, &_oid, 40)); @@ -166,7 +166,7 @@ void test_odb_backend_simple__exists_succeeds(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_assert(git_odb_exists(_odb, &_oid)); } @@ -179,7 +179,7 @@ void test_odb_backend_simple__exists_fails_for_nonexisting_object(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633", GIT_OID_SHA1)); cl_assert(git_odb_exists(_odb, &_oid) == 0); } @@ -194,7 +194,7 @@ void test_odb_backend_simple__exists_prefix_succeeds(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 12)); cl_assert(git_oid_equal(&found, &_oid)); } @@ -209,7 +209,7 @@ void test_odb_backend_simple__exists_with_ambiguous_prefix_fails(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(NULL, _odb, &_oid, 7)); } @@ -224,7 +224,7 @@ void test_odb_backend_simple__exists_with_highly_ambiguous_prefix(void) setup_backend(objs); - cl_git_pass(git_oid__fromstr(&_oid, objs[0].oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_oid, objs[0].oid, GIT_OID_SHA1)); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &_oid, 39)); cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 40)); diff --git a/tests/libgit2/odb/emptyobjects.c b/tests/libgit2/odb/emptyobjects.c index e7cc668d16c..baa6330b6be 100644 --- a/tests/libgit2/odb/emptyobjects.c +++ b/tests/libgit2/odb/emptyobjects.c @@ -24,7 +24,7 @@ void test_odb_emptyobjects__blob_notfound(void) git_oid id, written_id; git_blob *blob; - cl_git_pass(git_oid__fromstr(&id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", GIT_OID_SHA1)); cl_git_fail_with(GIT_ENOTFOUND, git_blob_lookup(&blob, g_repo, &id)); cl_git_pass(git_odb_write(&written_id, g_odb, "", 0, GIT_OBJECT_BLOB)); @@ -36,7 +36,7 @@ void test_odb_emptyobjects__read_tree(void) git_oid id; git_tree *tree; - cl_git_pass(git_oid__fromstr(&id, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_assert_equal_i(GIT_OBJECT_TREE, git_object_type((git_object *) tree)); cl_assert_equal_i(0, git_tree_entrycount(tree)); @@ -49,7 +49,7 @@ void test_odb_emptyobjects__read_tree_odb(void) git_oid id; git_odb_object *tree_odb; - cl_git_pass(git_oid__fromstr(&id, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", GIT_OID_SHA1)); cl_git_pass(git_odb_read(&tree_odb, g_odb, &id)); cl_assert(git_odb_object_data(tree_odb)); cl_assert_equal_s("", git_odb_object_data(tree_odb)); diff --git a/tests/libgit2/odb/freshen.c b/tests/libgit2/odb/freshen.c index e337c82b773..b425abad259 100644 --- a/tests/libgit2/odb/freshen.c +++ b/tests/libgit2/odb/freshen.c @@ -43,7 +43,7 @@ void test_odb_freshen__loose_blob(void) git_oid expected_id, id; struct stat before, after; - cl_git_pass(git_oid__fromstr(&expected_id, LOOSE_BLOB_ID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, LOOSE_BLOB_ID, GIT_OID_SHA1)); set_time_wayback(&before, LOOSE_BLOB_FN); /* make sure we freshen a blob */ @@ -64,7 +64,7 @@ void test_odb_freshen__readonly_object(void) git_oid expected_id, id; struct stat before, after; - cl_git_pass(git_oid__fromstr(&expected_id, UNIQUE_BLOB_ID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, UNIQUE_BLOB_ID, GIT_OID_SHA1)); cl_git_pass(git_blob_create_from_buffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR))); cl_assert_equal_oid(&expected_id, &id); @@ -89,7 +89,7 @@ void test_odb_freshen__loose_tree(void) git_tree *tree; struct stat before, after; - cl_git_pass(git_oid__fromstr(&expected_id, LOOSE_TREE_ID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, LOOSE_TREE_ID, GIT_OID_SHA1)); set_time_wayback(&before, LOOSE_TREE_FN); cl_git_pass(git_tree_lookup(&tree, repo, &expected_id)); @@ -113,11 +113,11 @@ void test_odb_freshen__tree_during_commit(void) git_signature *signature; struct stat before, after; - cl_git_pass(git_oid__fromstr(&tree_id, LOOSE_TREE_ID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&tree_id, LOOSE_TREE_ID, GIT_OID_SHA1)); cl_git_pass(git_tree_lookup(&tree, repo, &tree_id)); set_time_wayback(&before, LOOSE_TREE_FN); - cl_git_pass(git_oid__fromstr(&parent_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&parent_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&parent, repo, &parent_id)); cl_git_pass(git_signature_new(&signature, @@ -147,7 +147,7 @@ void test_odb_freshen__packed_object(void) struct stat before, after; struct p_timeval old_times[2]; - cl_git_pass(git_oid__fromstr(&expected_id, PACKED_ID, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_id, PACKED_ID, GIT_OID_SHA1)); old_times[0].tv_sec = 1234567890; old_times[0].tv_usec = 0; diff --git a/tests/libgit2/odb/largefiles.c b/tests/libgit2/odb/largefiles.c index 2ec48102b38..0f53e477bc2 100644 --- a/tests/libgit2/odb/largefiles.c +++ b/tests/libgit2/odb/largefiles.c @@ -57,7 +57,7 @@ void test_odb_largefiles__write_from_memory(void) for (i = 0; i < (3041*126103); i++) cl_git_pass(git_str_puts(&buf, "Hello, world.\n")); - git_oid__fromstr(&expected, "3fb56989cca483b21ba7cb0a6edb229d10e1c26c", GIT_OID_SHA1); + git_oid_from_string(&expected, "3fb56989cca483b21ba7cb0a6edb229d10e1c26c", GIT_OID_SHA1); cl_git_pass(git_odb_write(&oid, odb, buf.ptr, buf.size, GIT_OBJECT_BLOB)); cl_assert_equal_oid(&expected, &oid); @@ -75,7 +75,7 @@ void test_odb_largefiles__streamwrite(void) !cl_is_env_set("GITTEST_SLOW")) cl_skip(); - git_oid__fromstr(&expected, "3fb56989cca483b21ba7cb0a6edb229d10e1c26c", GIT_OID_SHA1); + git_oid_from_string(&expected, "3fb56989cca483b21ba7cb0a6edb229d10e1c26c", GIT_OID_SHA1); writefile(&oid); cl_assert_equal_oid(&expected, &oid); diff --git a/tests/libgit2/odb/loose.c b/tests/libgit2/odb/loose.c index 4ad47772c23..e68d5d13b4d 100644 --- a/tests/libgit2/odb/loose.c +++ b/tests/libgit2/odb/loose.c @@ -45,7 +45,7 @@ static void test_read_object(object_data *data) write_object_files(data); cl_git_pass(git_odb_open_ext(&odb, "test-objects", &opts)); - cl_git_pass(git_oid__fromstr(&id, data->id, data->id_type)); + cl_git_pass(git_oid_from_string(&id, data->id, data->id_type)); cl_git_pass(git_odb_read(&obj, odb, &id)); tmp.data = obj->buffer; @@ -71,7 +71,7 @@ static void test_read_header(object_data *data) write_object_files(data); cl_git_pass(git_odb_open_ext(&odb, "test-objects", &opts)); - cl_git_pass(git_oid__fromstr(&id, data->id, data->id_type)); + cl_git_pass(git_oid_from_string(&id, data->id, data->id_type)); cl_git_pass(git_odb_read_header(&len, &type, odb, &id)); cl_assert_equal_sz(data->dlen, len); @@ -96,7 +96,7 @@ static void test_readstream_object(object_data *data, size_t blocksize) write_object_files(data); cl_git_pass(git_odb_open_ext(&odb, "test-objects", &opts)); - cl_git_pass(git_oid__fromstr(&id, data->id, data->id_type)); + cl_git_pass(git_oid_from_string(&id, data->id, data->id_type)); cl_git_pass(git_odb_open_rstream(&stream, &tmp.len, &tmp.type, odb, &id)); remain = tmp.len; @@ -141,18 +141,18 @@ void test_odb_loose__exists_sha1(void) write_object_files(&one); cl_git_pass(git_odb_open(&odb, "test-objects")); - cl_git_pass(git_oid__fromstr(&id, one.id, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, one.id, GIT_OID_SHA1)); cl_assert(git_odb_exists(odb, &id)); - cl_git_pass(git_oid__fromstrp(&id, "8b137891", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&id, "8b137891", 8, GIT_OID_SHA1)); cl_git_pass(git_odb_exists_prefix(&id2, odb, &id, 8)); cl_assert_equal_i(0, git_oid_streq(&id2, one.id)); /* Test for a missing object */ - cl_git_pass(git_oid__fromstr(&id, "8b137891791fe96927ad78e64b0aad7bded08baa", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "8b137891791fe96927ad78e64b0aad7bded08baa", GIT_OID_SHA1)); cl_assert(!git_odb_exists(odb, &id)); - cl_git_pass(git_oid__fromstrp(&id, "8b13789a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&id, "8b13789a", 8, GIT_OID_SHA1)); cl_assert_equal_i(GIT_ENOTFOUND, git_odb_exists_prefix(&id2, odb, &id, 8)); git_odb_free(odb); @@ -172,18 +172,18 @@ void test_odb_loose__exists_sha256(void) write_object_files(&one_sha256); cl_git_pass(git_odb_open_ext(&odb, "test-objects", &odb_opts)); - cl_git_pass(git_oid__fromstr(&id, one_sha256.id, GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id, one_sha256.id, GIT_OID_SHA256)); cl_assert(git_odb_exists(odb, &id)); - cl_git_pass(git_oid__fromstrp(&id, "4c0d52d1", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_prefix(&id, "4c0d52d1", 8, GIT_OID_SHA256)); cl_git_pass(git_odb_exists_prefix(&id2, odb, &id, 8)); cl_assert_equal_i(0, git_oid_streq(&id2, one_sha256.id)); /* Test for a missing object */ - cl_git_pass(git_oid__fromstr(&id, "4c0d52d180c61d01ce1a91dec5ee58f0cbe65fd59433aea803ab927965493faa", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id, "4c0d52d180c61d01ce1a91dec5ee58f0cbe65fd59433aea803ab927965493faa", GIT_OID_SHA256)); cl_assert(!git_odb_exists(odb, &id)); - cl_git_pass(git_oid__fromstrp(&id, "4c0d52da", GIT_OID_SHA256)); + cl_git_pass(git_oid_from_prefix(&id, "4c0d52da", 8, GIT_OID_SHA256)); cl_assert_equal_i(GIT_ENOTFOUND, git_odb_exists_prefix(&id2, odb, &id, 8)); git_odb_free(odb); diff --git a/tests/libgit2/odb/mixed.c b/tests/libgit2/odb/mixed.c index 2cba8cb1479..2c66afe4cac 100644 --- a/tests/libgit2/odb/mixed.c +++ b/tests/libgit2/odb/mixed.c @@ -20,13 +20,13 @@ void test_odb_mixed__dup_oid(void) { git_oid oid; git_odb_object *obj; - cl_git_pass(git_oid__fromstr(&oid, hex, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, hex, GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, GIT_OID_SHA1_HEXSIZE)); git_odb_object_free(obj); cl_git_pass(git_odb_exists_prefix(NULL, _odb, &oid, GIT_OID_SHA1_HEXSIZE)); - cl_git_pass(git_oid__fromstrn(&oid, short_hex, sizeof(short_hex) - 1, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, short_hex, sizeof(short_hex) - 1, GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, sizeof(short_hex) - 1)); git_odb_object_free(obj); @@ -48,63 +48,63 @@ void test_odb_mixed__dup_oid_prefix_0(void) { /* ambiguous in the same pack file */ strncpy(hex, "dea509d0", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); strncpy(hex, "dea509d09", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); cl_assert_equal_oid(&found, git_odb_object_id(obj)); git_odb_object_free(obj); strncpy(hex, "dea509d0b", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); git_odb_object_free(obj); /* ambiguous in different pack files */ strncpy(hex, "81b5bff5", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); strncpy(hex, "81b5bff5b", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); cl_assert_equal_oid(&found, git_odb_object_id(obj)); git_odb_object_free(obj); strncpy(hex, "81b5bff5f", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); git_odb_object_free(obj); /* ambiguous in pack file and loose */ strncpy(hex, "0ddeaded", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); strncpy(hex, "0ddeaded9", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); cl_assert_equal_oid(&found, git_odb_object_id(obj)); git_odb_object_free(obj); strncpy(hex, "0ddeadede", sizeof(hex)); - cl_git_pass(git_oid__fromstrn(&oid, hex, strlen(hex), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, hex, strlen(hex), GIT_OID_SHA1)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); git_odb_object_free(obj); } @@ -170,7 +170,7 @@ static void setup_prefix_query( size_t len = strlen(expand_id_test_data[i].lookup_id); - git_oid__fromstrn(&id->id, expand_id_test_data[i].lookup_id, len, GIT_OID_SHA1); + git_oid_from_prefix(&id->id, expand_id_test_data[i].lookup_id, len, GIT_OID_SHA1); id->length = (unsigned short)len; id->type = expand_id_test_data[i].expected_type; } @@ -191,7 +191,7 @@ static void assert_found_objects(git_odb_expand_id *ids) git_object_t expected_type = 0; if (expand_id_test_data[i].expected_id) { - git_oid__fromstr(&expected_id, expand_id_test_data[i].expected_id, GIT_OID_SHA1); + git_oid_from_string(&expected_id, expand_id_test_data[i].expected_id, GIT_OID_SHA1); expected_len = GIT_OID_SHA1_HEXSIZE; expected_type = expand_id_test_data[i].expected_type; } diff --git a/tests/libgit2/odb/open.c b/tests/libgit2/odb/open.c index 05e65d2c0eb..1a178e0c1f4 100644 --- a/tests/libgit2/odb/open.c +++ b/tests/libgit2/odb/open.c @@ -20,8 +20,8 @@ void test_odb_open__exists(void) cl_git_pass(git_odb_open_ext(&odb, "testrepo.git/objects", &opts)); #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_oid_fromstr(&one, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); - cl_git_pass(git_oid_fromstr(&two, "00112233445566778899aabbccddeeff00112233", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "00112233445566778899aabbccddeeff00112233", GIT_OID_SHA1)); #else cl_git_pass(git_oid_fromstr(&one, "1385f264afb75a56a5bec74243be9b367ba4ca08")); cl_git_pass(git_oid_fromstr(&two, "00112233445566778899aabbccddeeff00112233")); diff --git a/tests/libgit2/odb/packed.c b/tests/libgit2/odb/packed.c index 6fbe0a46dab..f33df1054fe 100644 --- a/tests/libgit2/odb/packed.c +++ b/tests/libgit2/odb/packed.c @@ -23,7 +23,7 @@ void test_odb_packed__mass_read(void) git_oid id; git_odb_object *obj; - cl_git_pass(git_oid__fromstr(&id, packed_objects[i], GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, packed_objects[i], GIT_OID_SHA1)); cl_assert(git_odb_exists(_odb, &id) == 1); cl_git_pass(git_odb_read(&obj, _odb, &id)); @@ -41,7 +41,7 @@ void test_odb_packed__read_header_0(void) size_t len; git_object_t type; - cl_git_pass(git_oid__fromstr(&id, packed_objects[i], GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, packed_objects[i], GIT_OID_SHA1)); cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); @@ -63,7 +63,7 @@ void test_odb_packed__read_header_1(void) size_t len; git_object_t type; - cl_git_pass(git_oid__fromstr(&id, loose_objects[i], GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, loose_objects[i], GIT_OID_SHA1)); cl_assert(git_odb_exists(_odb, &id) == 1); diff --git a/tests/libgit2/odb/packed256.c b/tests/libgit2/odb/packed256.c index 3b04e88b558..c6ca56ae354 100644 --- a/tests/libgit2/odb/packed256.c +++ b/tests/libgit2/odb/packed256.c @@ -37,7 +37,7 @@ void test_odb_packed256__mass_read(void) git_oid id; git_odb_object *obj; - cl_git_pass(git_oid__fromstr(&id, packed_objects_256[i], GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id, packed_objects_256[i], GIT_OID_SHA256)); cl_assert(git_odb_exists(_odb, &id) == 1); cl_git_pass(git_odb_read(&obj, _odb, &id)); @@ -57,7 +57,7 @@ void test_odb_packed256__read_header_0(void) size_t len; git_object_t type; - cl_git_pass(git_oid__fromstr(&id, packed_objects_256[i], GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id, packed_objects_256[i], GIT_OID_SHA256)); cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); @@ -81,7 +81,7 @@ void test_odb_packed256__read_header_1(void) size_t len; git_object_t type; - cl_git_pass(git_oid__fromstr(&id, loose_objects_256[i], GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id, loose_objects_256[i], GIT_OID_SHA256)); cl_assert(git_odb_exists(_odb, &id) == 1); diff --git a/tests/libgit2/odb/packedone.c b/tests/libgit2/odb/packedone.c index 4dea474f95c..c564f57d4d4 100644 --- a/tests/libgit2/odb/packedone.c +++ b/tests/libgit2/odb/packedone.c @@ -37,7 +37,7 @@ void test_odb_packedone__mass_read(void) git_oid id; git_odb_object *obj; - cl_git_pass(git_oid__fromstr(&id, packed_objects_one[i], GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, packed_objects_one[i], GIT_OID_SHA1)); cl_assert(git_odb_exists(_odb, &id) == 1); cl_git_pass(git_odb_read(&obj, _odb, &id)); @@ -55,7 +55,7 @@ void test_odb_packedone__read_header_0(void) size_t len; git_object_t type; - cl_git_pass(git_oid__fromstr(&id, packed_objects_one[i], GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, packed_objects_one[i], GIT_OID_SHA1)); cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); diff --git a/tests/libgit2/odb/packedone256.c b/tests/libgit2/odb/packedone256.c index 6fc6a80814a..4152145fb0e 100644 --- a/tests/libgit2/odb/packedone256.c +++ b/tests/libgit2/odb/packedone256.c @@ -44,7 +44,7 @@ void test_odb_packedone256__mass_read(void) git_oid id; git_odb_object *obj; - cl_git_pass(git_oid__fromstr(&id, packed_objects_one256[i], GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id, packed_objects_one256[i], GIT_OID_SHA256)); cl_assert(git_odb_exists(_odb, &id) == 1); cl_git_pass(git_odb_read(&obj, _odb, &id)); @@ -64,7 +64,7 @@ void test_odb_packedone256__read_header_0(void) size_t len; git_object_t type; - cl_git_pass(git_oid__fromstr(&id, packed_objects_one256[i], GIT_OID_SHA256)); + cl_git_pass(git_oid_from_string(&id, packed_objects_one256[i], GIT_OID_SHA256)); cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 6e9c8ea5051..e36dfac9d32 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -859,7 +859,7 @@ static int ssh_certificate_check(git_cert *cert, int valid, const char *host, vo cl_assert(_remote_ssh_fingerprint); - cl_git_pass(git_oid__fromstrp(&expected, _remote_ssh_fingerprint, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&expected, _remote_ssh_fingerprint, strlen(_remote_ssh_fingerprint), GIT_OID_SHA1)); cl_assert_equal_i(GIT_CERT_HOSTKEY_LIBSSH2, cert->cert_type); key = (git_cert_hostkey *) cert; diff --git a/tests/libgit2/online/fetch.c b/tests/libgit2/online/fetch.c index 75ec0cde5d4..9c2d3d75ad0 100644 --- a/tests/libgit2/online/fetch.c +++ b/tests/libgit2/online/fetch.c @@ -371,7 +371,7 @@ void test_online_fetch__reachable_commit(void) refspecs.strings = &refspec; refspecs.count = 1; - git_oid__fromstr(&expected_id, "2c349335b7f797072cf729c4f3bb0914ecb6dec9", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "2c349335b7f797072cf729c4f3bb0914ecb6dec9", GIT_OID_SHA1); cl_git_pass(git_remote_create(&remote, _repo, "test", "https://github.com/libgit2/TestGitRepository")); @@ -401,7 +401,7 @@ void test_online_fetch__reachable_commit_without_destination(void) refspecs.strings = &refspec; refspecs.count = 1; - git_oid__fromstr(&expected_id, "2c349335b7f797072cf729c4f3bb0914ecb6dec9", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "2c349335b7f797072cf729c4f3bb0914ecb6dec9", GIT_OID_SHA1); cl_git_pass(git_remote_create(&remote, _repo, "test", "https://github.com/libgit2/TestGitRepository")); diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index dd221f44443..969ecaff631 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -350,18 +350,18 @@ void test_online_push__initialize(void) * * a78705c3b2725f931d3ee05348d83cc26700f247 (b2, b1) added fold and fold/b.txt * * 5c0bb3d1b9449d1cc69d7519fd05166f01840915 added a.txt */ - git_oid__fromstr(&_oid_b6, "951bbbb90e2259a4c8950db78946784fb53fcbce", GIT_OID_SHA1); - git_oid__fromstr(&_oid_b5, "fa38b91f199934685819bea316186d8b008c52a2", GIT_OID_SHA1); - git_oid__fromstr(&_oid_b4, "27b7ce66243eb1403862d05f958c002312df173d", GIT_OID_SHA1); - git_oid__fromstr(&_oid_b3, "d9b63a88223d8367516f50bd131a5f7349b7f3e4", GIT_OID_SHA1); - git_oid__fromstr(&_oid_b2, "a78705c3b2725f931d3ee05348d83cc26700f247", GIT_OID_SHA1); - git_oid__fromstr(&_oid_b1, "a78705c3b2725f931d3ee05348d83cc26700f247", GIT_OID_SHA1); - - git_oid__fromstr(&_tag_commit, "805c54522e614f29f70d2413a0470247d8b424ac", GIT_OID_SHA1); - git_oid__fromstr(&_tag_tree, "ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e", GIT_OID_SHA1); - git_oid__fromstr(&_tag_blob, "b483ae7ba66decee9aee971f501221dea84b1498", GIT_OID_SHA1); - git_oid__fromstr(&_tag_lightweight, "951bbbb90e2259a4c8950db78946784fb53fcbce", GIT_OID_SHA1); - git_oid__fromstr(&_tag_tag, "eea4f2705eeec2db3813f2430829afce99cd00b5", GIT_OID_SHA1); + git_oid_from_string(&_oid_b6, "951bbbb90e2259a4c8950db78946784fb53fcbce", GIT_OID_SHA1); + git_oid_from_string(&_oid_b5, "fa38b91f199934685819bea316186d8b008c52a2", GIT_OID_SHA1); + git_oid_from_string(&_oid_b4, "27b7ce66243eb1403862d05f958c002312df173d", GIT_OID_SHA1); + git_oid_from_string(&_oid_b3, "d9b63a88223d8367516f50bd131a5f7349b7f3e4", GIT_OID_SHA1); + git_oid_from_string(&_oid_b2, "a78705c3b2725f931d3ee05348d83cc26700f247", GIT_OID_SHA1); + git_oid_from_string(&_oid_b1, "a78705c3b2725f931d3ee05348d83cc26700f247", GIT_OID_SHA1); + + git_oid_from_string(&_tag_commit, "805c54522e614f29f70d2413a0470247d8b424ac", GIT_OID_SHA1); + git_oid_from_string(&_tag_tree, "ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e", GIT_OID_SHA1); + git_oid_from_string(&_tag_blob, "b483ae7ba66decee9aee971f501221dea84b1498", GIT_OID_SHA1); + git_oid_from_string(&_tag_lightweight, "951bbbb90e2259a4c8950db78946784fb53fcbce", GIT_OID_SHA1); + git_oid_from_string(&_tag_tag, "eea4f2705eeec2db3813f2430829afce99cd00b5", GIT_OID_SHA1); /* Remote URL environment variable must be set. User and password are optional. */ @@ -1011,7 +1011,7 @@ void test_online_push__notes(void) expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; const char *specs_del[] = { ":refs/notes/commits" }; - git_oid__fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb", GIT_OID_SHA1); + git_oid_from_string(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb", GIT_OID_SHA1); target_oid = &_oid_b6; @@ -1046,7 +1046,7 @@ void test_online_push__configured(void) expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; const char *specs_del[] = { ":refs/notes/commits" }; - git_oid__fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb", GIT_OID_SHA1); + git_oid_from_string(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb", GIT_OID_SHA1); target_oid = &_oid_b6; diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c index a5508c16d45..8d71c6be507 100644 --- a/tests/libgit2/online/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -336,9 +336,9 @@ void test_online_shallow__preserve_unrelated_roots(void) char *third_commit = "7f822839a2fe9760f386cbbbcb3f92c5fe81def7"; #ifdef GIT_EXPERIMENTAL_SHA256 - cl_git_pass(git_oid_fromstr(&first_oid, first_commit, GIT_OID_SHA1)); - cl_git_pass(git_oid_fromstr(&second_oid, second_commit, GIT_OID_SHA1)); - cl_git_pass(git_oid_fromstr(&third_oid, third_commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&first_oid, first_commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&second_oid, second_commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&third_oid, third_commit, GIT_OID_SHA1)); #else cl_git_pass(git_oid_fromstr(&first_oid, first_commit)); cl_git_pass(git_oid_fromstr(&second_oid, second_commit)); diff --git a/tests/libgit2/pack/indexer.c b/tests/libgit2/pack/indexer.c index 023eb5da795..2d1a9d3f273 100644 --- a/tests/libgit2/pack/indexer.c +++ b/tests/libgit2/pack/indexer.c @@ -173,7 +173,7 @@ void test_pack_indexer__fix_thin(void) /* Store the missing base into your ODB so the indexer can fix the pack */ cl_git_pass(git_odb_write(&id, odb, base_obj, base_obj_len, GIT_OBJECT_BLOB)); - git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1); + git_oid_from_string(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1); cl_assert_equal_oid(&should_id, &id); #ifdef GIT_EXPERIMENTAL_SHA256 @@ -250,7 +250,7 @@ void test_pack_indexer__corrupt_length(void) /* Store the missing base into your ODB so the indexer can fix the pack */ cl_git_pass(git_odb_write(&id, odb, base_obj, base_obj_len, GIT_OBJECT_BLOB)); - git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1); + git_oid_from_string(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1); cl_assert_equal_oid(&should_id, &id); #ifdef GIT_EXPERIMENTAL_SHA256 diff --git a/tests/libgit2/pack/midx.c b/tests/libgit2/pack/midx.c index d7180c47898..6384e97be67 100644 --- a/tests/libgit2/pack/midx.c +++ b/tests/libgit2/pack/midx.c @@ -19,7 +19,7 @@ void test_pack_midx__parse(void) cl_git_pass(git_midx_open(&idx, git_str_cstr(&midx_path), GIT_OID_SHA1)); cl_assert_equal_i(git_midx_needs_refresh(idx, git_str_cstr(&midx_path)), 0); - cl_git_pass(git_oid__fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); cl_git_pass(git_midx_entry_find(&e, idx, &id, GIT_OID_SHA1_HEXSIZE)); cl_assert_equal_oid(&e.sha1, &id); cl_assert_equal_s( @@ -39,7 +39,7 @@ void test_pack_midx__lookup(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); - cl_git_pass(git_oid__fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup_prefix(&commit, repo, &id, GIT_OID_SHA1_HEXSIZE)); cl_assert_equal_s(git_commit_message(commit), "packed commit one\n"); diff --git a/tests/libgit2/pack/sharing.c b/tests/libgit2/pack/sharing.c index dd7aee8ba1e..6524a5356fd 100644 --- a/tests/libgit2/pack/sharing.c +++ b/tests/libgit2/pack/sharing.c @@ -17,7 +17,7 @@ void test_pack_sharing__open_two_repos(void) cl_git_pass(git_repository_open(&repo1, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_open(&repo2, cl_fixture("testrepo.git"))); - git_oid__fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_object_lookup(&obj1, repo1, &id, GIT_OBJECT_ANY)); cl_git_pass(git_object_lookup(&obj2, repo2, &id, GIT_OBJECT_ANY)); diff --git a/tests/libgit2/perf/helper__perf__do_merge.c b/tests/libgit2/perf/helper__perf__do_merge.c index 6f53af63cde..ce36a95aad4 100644 --- a/tests/libgit2/perf/helper__perf__do_merge.c +++ b/tests/libgit2/perf/helper__perf__do_merge.c @@ -32,7 +32,7 @@ void perf__do_merge(const char *fixture, cl_git_pass(git_clone(&g_repo, fixture, test_name, &clone_opts)); perf__timer__stop(&t_clone); - git_oid__fromstr(&oid_a, id_a, GIT_OID_SHA1); + git_oid_from_string(&oid_a, id_a, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit_a, g_repo, &oid_a)); cl_git_pass(git_branch_create(&ref_branch_a, g_repo, "A", commit_a, @@ -44,7 +44,7 @@ void perf__do_merge(const char *fixture, cl_git_pass(git_repository_set_head(g_repo, git_reference_name(ref_branch_a))); - git_oid__fromstr(&oid_b, id_b, GIT_OID_SHA1); + git_oid_from_string(&oid_b, id_b, GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit_b, g_repo, &oid_b)); cl_git_pass(git_branch_create(&ref_branch_b, g_repo, "B", commit_b, diff --git a/tests/libgit2/rebase/abort.c b/tests/libgit2/rebase/abort.c index da0dfe893a1..3bd4060ecce 100644 --- a/tests/libgit2/rebase/abort.c +++ b/tests/libgit2/rebase/abort.c @@ -128,8 +128,8 @@ void test_rebase_abort__merge_by_id(void) git_oid branch_id, onto_id; git_annotated_commit *branch_head, *onto_head; - cl_git_pass(git_oid__fromstr(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); cl_git_pass(git_annotated_commit_lookup(&onto_head, repo, &onto_id)); @@ -170,8 +170,8 @@ void test_rebase_abort__merge_by_id_immediately_after_init(void) git_oid branch_id, onto_id; git_annotated_commit *branch_head, *onto_head; - cl_git_pass(git_oid__fromstr(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); cl_git_pass(git_annotated_commit_lookup(&onto_head, repo, &onto_id)); @@ -195,8 +195,8 @@ void test_rebase_abort__detached_head(void) git_signature *signature; git_annotated_commit *branch_head, *onto_head; - git_oid__fromstr(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1); - git_oid__fromstr(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1); + git_oid_from_string(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); cl_git_pass(git_annotated_commit_lookup(&onto_head, repo, &onto_id)); diff --git a/tests/libgit2/rebase/inmemory.c b/tests/libgit2/rebase/inmemory.c index 287dd991119..9646be10323 100644 --- a/tests/libgit2/rebase/inmemory.c +++ b/tests/libgit2/rebase/inmemory.c @@ -74,7 +74,7 @@ void test_rebase_inmemory__can_resolve_conflicts(void) cl_git_pass(git_rebase_next(&rebase_operation, rebase)); - git_oid__fromstr(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500", GIT_OID_SHA1); + git_oid_from_string(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500", GIT_OID_SHA1); cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation->type); cl_assert_equal_oid(&pick_id, &rebase_operation->id); @@ -95,14 +95,14 @@ void test_rebase_inmemory__can_resolve_conflicts(void) /* ensure that we can work with the in-memory index to resolve the conflict */ resolution.path = "asparagus.txt"; resolution.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&resolution.id, "414dfc71ead79c07acd4ea47fecf91f289afc4b9", GIT_OID_SHA1); + git_oid_from_string(&resolution.id, "414dfc71ead79c07acd4ea47fecf91f289afc4b9", GIT_OID_SHA1); cl_git_pass(git_index_conflict_remove(rebase_index, "asparagus.txt")); cl_git_pass(git_index_add(rebase_index, &resolution)); /* and finally create a commit for the resolved rebase operation */ cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_pass(git_oid__fromstr(&expected_commit_id, "db7af47222181e548810da2ab5fec0e9357c5637", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_commit_id, "db7af47222181e548810da2ab5fec0e9357c5637", GIT_OID_SHA1)); cl_assert_equal_oid(&commit_id, &expected_commit_id); git_status_list_free(status_list); @@ -156,7 +156,7 @@ void test_rebase_inmemory__no_common_ancestor(void) cl_git_pass(git_rebase_finish(rebase, signature)); - git_oid__fromstr(&expected_final_id, "71e7ee8d4fe7d8bf0d107355197e0a953dfdb7f3", GIT_OID_SHA1); + git_oid_from_string(&expected_final_id, "71e7ee8d4fe7d8bf0d107355197e0a953dfdb7f3", GIT_OID_SHA1); cl_assert_equal_oid(&expected_final_id, &commit_id); git_annotated_commit_free(branch_head); @@ -178,7 +178,7 @@ void test_rebase_inmemory__with_directories(void) opts.inmemory = true; - git_oid__fromstr(&tree_id, "a4d6d9c3d57308fd8e320cf2525bae8f1adafa57", GIT_OID_SHA1); + git_oid_from_string(&tree_id, "a4d6d9c3d57308fd8e320cf2525bae8f1adafa57", GIT_OID_SHA1); cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/deep_gravy")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal")); diff --git a/tests/libgit2/rebase/iterator.c b/tests/libgit2/rebase/iterator.c index 79e9f3e58b9..ab930bde063 100644 --- a/tests/libgit2/rebase/iterator.c +++ b/tests/libgit2/rebase/iterator.c @@ -30,11 +30,11 @@ static void test_operations(git_rebase *rebase, size_t expected_current) git_oid expected_oid[5]; git_rebase_operation *operation; - git_oid__fromstr(&expected_oid[0], "da9c51a23d02d931a486f45ad18cda05cf5d2b94", GIT_OID_SHA1); - git_oid__fromstr(&expected_oid[1], "8d1f13f93c4995760ac07d129246ac1ff64c0be9", GIT_OID_SHA1); - git_oid__fromstr(&expected_oid[2], "3069cc907e6294623e5917ef6de663928c1febfb", GIT_OID_SHA1); - git_oid__fromstr(&expected_oid[3], "588e5d2f04d49707fe4aab865e1deacaf7ef6787", GIT_OID_SHA1); - git_oid__fromstr(&expected_oid[4], "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1); + git_oid_from_string(&expected_oid[0], "da9c51a23d02d931a486f45ad18cda05cf5d2b94", GIT_OID_SHA1); + git_oid_from_string(&expected_oid[1], "8d1f13f93c4995760ac07d129246ac1ff64c0be9", GIT_OID_SHA1); + git_oid_from_string(&expected_oid[2], "3069cc907e6294623e5917ef6de663928c1febfb", GIT_OID_SHA1); + git_oid_from_string(&expected_oid[3], "588e5d2f04d49707fe4aab865e1deacaf7ef6787", GIT_OID_SHA1); + git_oid_from_string(&expected_oid[4], "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1); cl_assert_equal_i(expected_count, git_rebase_operation_entrycount(rebase)); cl_assert_equal_i(expected_current, git_rebase_operation_current(rebase)); @@ -78,7 +78,7 @@ static void test_iterator(bool inmemory) NULL, NULL)); test_operations(rebase, 0); - git_oid__fromstr(&expected_id, "776e4c48922799f903f03f5f6e51da8b01e4cce0", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "776e4c48922799f903f03f5f6e51da8b01e4cce0", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_rebase_next(&rebase_operation, rebase)); @@ -86,7 +86,7 @@ static void test_iterator(bool inmemory) NULL, NULL)); test_operations(rebase, 1); - git_oid__fromstr(&expected_id, "ba1f9b4fd5cf8151f7818be2111cc0869f1eb95a", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "ba1f9b4fd5cf8151f7818be2111cc0869f1eb95a", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_rebase_next(&rebase_operation, rebase)); @@ -94,7 +94,7 @@ static void test_iterator(bool inmemory) NULL, NULL)); test_operations(rebase, 2); - git_oid__fromstr(&expected_id, "948b12fe18b84f756223a61bece4c307787cd5d4", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "948b12fe18b84f756223a61bece4c307787cd5d4", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); if (!inmemory) { @@ -107,7 +107,7 @@ static void test_iterator(bool inmemory) NULL, NULL)); test_operations(rebase, 3); - git_oid__fromstr(&expected_id, "d9d5d59d72c9968687f9462578d79878cd80e781", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "d9d5d59d72c9968687f9462578d79878cd80e781", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_rebase_next(&rebase_operation, rebase)); @@ -115,7 +115,7 @@ static void test_iterator(bool inmemory) NULL, NULL)); test_operations(rebase, 4); - git_oid__fromstr(&expected_id, "9cf383c0a125d89e742c5dec58ed277dd07588b3", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "9cf383c0a125d89e742c5dec58ed277dd07588b3", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_fail(error = git_rebase_next(&rebase_operation, rebase)); diff --git a/tests/libgit2/rebase/merge.c b/tests/libgit2/rebase/merge.c index 870c3ea2fd6..615b986b971 100644 --- a/tests/libgit2/rebase/merge.c +++ b/tests/libgit2/rebase/merge.c @@ -46,8 +46,8 @@ void test_rebase_merge__next(void) git_oid pick_id, file1_id; git_oid master_id, beef_id; - git_oid__fromstr(&master_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); - git_oid__fromstr(&beef_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1); + git_oid_from_string(&master_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&beef_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1); cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); @@ -65,7 +65,7 @@ void test_rebase_merge__next(void) cl_git_pass(git_rebase_next(&rebase_operation, rebase)); - git_oid__fromstr(&pick_id, "da9c51a23d02d931a486f45ad18cda05cf5d2b94", GIT_OID_SHA1); + git_oid_from_string(&pick_id, "da9c51a23d02d931a486f45ad18cda05cf5d2b94", GIT_OID_SHA1); cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation->type); cl_assert_equal_oid(&pick_id, &rebase_operation->id); @@ -78,7 +78,7 @@ void test_rebase_merge__next(void) cl_assert_equal_s("beef.txt", status_entry->head_to_index->new_file.path); - git_oid__fromstr(&file1_id, "8d95ea62e621f1d38d230d9e7d206e41096d76af", GIT_OID_SHA1); + git_oid_from_string(&file1_id, "8d95ea62e621f1d38d230d9e7d206e41096d76af", GIT_OID_SHA1); cl_assert_equal_oid(&file1_id, &status_entry->head_to_index->new_file.id); git_status_list_free(status_list); @@ -129,7 +129,7 @@ void test_rebase_merge__next_with_conflicts(void) cl_git_pass(git_rebase_next(&rebase_operation, rebase)); - git_oid__fromstr(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500", GIT_OID_SHA1); + git_oid_from_string(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500", GIT_OID_SHA1); cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation->type); cl_assert_equal_oid(&pick_id, &rebase_operation->id); @@ -230,11 +230,11 @@ void test_rebase_merge__commit(void) cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); - git_oid__fromstr(&parent_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&parent_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_assert_equal_i(1, git_commit_parentcount(commit)); cl_assert_equal_oid(&parent_id, git_commit_parent_id(commit, 0)); - git_oid__fromstr(&tree_id, "4461379789c777d2a6c1f2ee0e9d6c86731b9992", GIT_OID_SHA1); + git_oid_from_string(&tree_id, "4461379789c777d2a6c1f2ee0e9d6c86731b9992", GIT_OID_SHA1); cl_assert_equal_oid(&tree_id, git_commit_tree_id(commit)); cl_assert_equal_s(NULL, git_commit_message_encoding(commit)); @@ -275,8 +275,8 @@ void test_rebase_merge__commit_with_id(void) git_reflog *reflog; const git_reflog_entry *reflog_entry; - cl_git_pass(git_oid__fromstr(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&upstream_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&upstream_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); cl_git_pass(git_annotated_commit_lookup(&upstream_head, repo, &upstream_id)); @@ -289,11 +289,11 @@ void test_rebase_merge__commit_with_id(void) cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); - git_oid__fromstr(&parent_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&parent_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_assert_equal_i(1, git_commit_parentcount(commit)); cl_assert_equal_oid(&parent_id, git_commit_parent_id(commit, 0)); - git_oid__fromstr(&tree_id, "4461379789c777d2a6c1f2ee0e9d6c86731b9992", GIT_OID_SHA1); + git_oid_from_string(&tree_id, "4461379789c777d2a6c1f2ee0e9d6c86731b9992", GIT_OID_SHA1); cl_assert_equal_oid(&tree_id, git_commit_tree_id(commit)); cl_assert_equal_s(NULL, git_commit_message_encoding(commit)); @@ -551,8 +551,8 @@ void test_rebase_merge__finish_with_ids(void) const git_reflog_entry *reflog_entry; int error; - cl_git_pass(git_oid__fromstr(&branch_id, "d616d97082eb7bb2dc6f180a7cca940993b7a56f", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&upstream_id, "f87d14a4a236582a0278a916340a793714256864", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&branch_id, "d616d97082eb7bb2dc6f180a7cca940993b7a56f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&upstream_id, "f87d14a4a236582a0278a916340a793714256864", GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); cl_git_pass(git_annotated_commit_lookup(&upstream_head, repo, &upstream_id)); @@ -627,7 +627,7 @@ void test_rebase_merge__no_common_ancestor(void) cl_git_pass(git_rebase_finish(rebase, signature)); - git_oid__fromstr(&expected_final_id, "71e7ee8d4fe7d8bf0d107355197e0a953dfdb7f3", GIT_OID_SHA1); + git_oid_from_string(&expected_final_id, "71e7ee8d4fe7d8bf0d107355197e0a953dfdb7f3", GIT_OID_SHA1); cl_assert_equal_oid(&expected_final_id, &commit_id); git_annotated_commit_free(branch_head); @@ -823,7 +823,7 @@ void test_rebase_merge__with_directories(void) git_oid commit_id, tree_id; git_commit *commit; - git_oid__fromstr(&tree_id, "a4d6d9c3d57308fd8e320cf2525bae8f1adafa57", GIT_OID_SHA1); + git_oid_from_string(&tree_id, "a4d6d9c3d57308fd8e320cf2525bae8f1adafa57", GIT_OID_SHA1); cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/deep_gravy")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal")); diff --git a/tests/libgit2/rebase/setup.c b/tests/libgit2/rebase/setup.c index ac0d087ea6e..10cc306de34 100644 --- a/tests/libgit2/rebase/setup.c +++ b/tests/libgit2/rebase/setup.c @@ -74,7 +74,7 @@ void test_rebase_setup__merge(void) cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -120,7 +120,7 @@ void test_rebase_setup__merge_root(void) cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -170,7 +170,7 @@ void test_rebase_setup__merge_onto_and_upstream(void) cl_git_pass(git_rebase_init(&rebase, repo, branch1_head, branch2_head, onto_head, NULL)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -224,7 +224,7 @@ void test_rebase_setup__merge_onto_upstream_and_branch(void) cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, onto_head, NULL)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -272,9 +272,9 @@ void test_rebase_setup__merge_onto_upstream_and_branch_by_id(void) cl_git_pass(git_repository_set_head(repo, "refs/heads/beef")); cl_git_pass(git_checkout_head(repo, &checkout_opts)); - cl_git_pass(git_oid__fromstr(&upstream_id, "f87d14a4a236582a0278a916340a793714256864", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&branch_id, "d616d97082eb7bb2dc6f180a7cca940993b7a56f", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&upstream_id, "f87d14a4a236582a0278a916340a793714256864", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&branch_id, "d616d97082eb7bb2dc6f180a7cca940993b7a56f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&onto_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&upstream_head, repo, &upstream_id)); cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); @@ -282,7 +282,7 @@ void test_rebase_setup__merge_onto_upstream_and_branch_by_id(void) cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, onto_head, NULL)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -328,7 +328,7 @@ void test_rebase_setup__branch_with_merges(void) cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -376,7 +376,7 @@ void test_rebase_setup__orphan_branch(void) cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -427,7 +427,7 @@ void test_rebase_setup__merge_null_branch_uses_HEAD(void) cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -465,7 +465,7 @@ void test_rebase_setup__merge_from_detached(void) cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); - cl_git_pass(git_oid__fromstr(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&branch_id, "b146bd7608eac53d9bf9e1a6963543588b555c64", GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_lookup(&branch_head, repo, &branch_id)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); @@ -474,7 +474,7 @@ void test_rebase_setup__merge_from_detached(void) cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); @@ -513,7 +513,7 @@ void test_rebase_setup__merge_branch_by_id(void) cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); - cl_git_pass(git_oid__fromstr(&upstream_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&upstream_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1)); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_lookup(&upstream_head, repo, &upstream_id)); @@ -522,7 +522,7 @@ void test_rebase_setup__merge_branch_by_id(void) cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - git_oid__fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); + git_oid_from_string(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJECT_COMMIT)); cl_assert_equal_oid(&head_id, git_commit_id(head_commit)); diff --git a/tests/libgit2/rebase/sign.c b/tests/libgit2/rebase/sign.c index 69bb1c6f998..869f5674a61 100644 --- a/tests/libgit2/rebase/sign.c +++ b/tests/libgit2/rebase/sign.c @@ -70,7 +70,7 @@ committer Rebaser 1405694510 +0000\n"; cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - git_oid__fromstr(&expected_id, "129183968a65abd6c52da35bff43325001bfc630", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "129183968a65abd6c52da35bff43325001bfc630", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); @@ -178,7 +178,7 @@ gpgsig -----BEGIN PGP SIGNATURE-----\n\ cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - git_oid__fromstr(&expected_id, "bf78348e45c8286f52b760f1db15cb6da030f2ef", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "bf78348e45c8286f52b760f1db15cb6da030f2ef", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); @@ -300,7 +300,7 @@ committer Rebaser 1405694510 +0000\n"; cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - git_oid__fromstr(&expected_id, "129183968a65abd6c52da35bff43325001bfc630", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "129183968a65abd6c52da35bff43325001bfc630", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); @@ -398,7 +398,7 @@ gpgsig -----BEGIN PGP SIGNATURE-----\n\ cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - git_oid__fromstr(&expected_id, "bf78348e45c8286f52b760f1db15cb6da030f2ef", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "bf78348e45c8286f52b760f1db15cb6da030f2ef", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); @@ -473,7 +473,7 @@ magicsig magic word: pretty please\n"; cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - git_oid__fromstr(&expected_id, "f46a4a8d26ae411b02aa61b7d69576627f4a1e1c", GIT_OID_SHA1); + git_oid_from_string(&expected_id, "f46a4a8d26ae411b02aa61b7d69576627f4a1e1c", GIT_OID_SHA1); cl_assert_equal_oid(&expected_id, &commit_id); cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); diff --git a/tests/libgit2/refs/basic.c b/tests/libgit2/refs/basic.c index 5e41ca07443..b1f770b99a8 100644 --- a/tests/libgit2/refs/basic.c +++ b/tests/libgit2/refs/basic.c @@ -53,7 +53,7 @@ void test_refs_basic__longpaths(void) git_reference *one = NULL, *two = NULL; git_oid id; - cl_git_pass(git_oid__fromstr(&id, "099fabac3a9ea935598528c27f866e34089c2eff", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "099fabac3a9ea935598528c27f866e34089c2eff", GIT_OID_SHA1)); base = git_repository_path(g_repo); base_len = git_utf8_char_length(base, strlen(base)); diff --git a/tests/libgit2/refs/branches/delete.c b/tests/libgit2/refs/branches/delete.c index 63f8c5d95c7..2c28dd294fa 100644 --- a/tests/libgit2/refs/branches/delete.c +++ b/tests/libgit2/refs/branches/delete.c @@ -14,7 +14,7 @@ void test_refs_branches_delete__initialize(void) repo = cl_git_sandbox_init("testrepo.git"); - cl_git_pass(git_oid__fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0, NULL)); } @@ -172,7 +172,7 @@ void test_refs_branches_delete__removes_empty_folders(void) git_str reflog_folder = GIT_STR_INIT; /* Create a new branch with a nested name */ - cl_git_pass(git_oid__fromstr(&commit_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&commit_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); cl_git_pass(git_branch_create(&branch, repo, "some/deep/ref", commit, 0)); git_commit_free(commit); diff --git a/tests/libgit2/refs/branches/iterator.c b/tests/libgit2/refs/branches/iterator.c index a295d553b80..e4913642888 100644 --- a/tests/libgit2/refs/branches/iterator.c +++ b/tests/libgit2/refs/branches/iterator.c @@ -11,7 +11,7 @@ void test_refs_branches_iterator__initialize(void) cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); - cl_git_pass(git_oid__fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0, NULL)); } diff --git a/tests/libgit2/refs/create.c b/tests/libgit2/refs/create.c index 1dafcf61a8f..aca6ecd63b5 100644 --- a/tests/libgit2/refs/create.c +++ b/tests/libgit2/refs/create.c @@ -34,7 +34,7 @@ void test_refs_create__symbolic(void) const char *new_head_tracker = "ANOTHER_HEAD_TRACKER"; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); /* Create and write the new symbolic reference */ cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL)); @@ -77,7 +77,7 @@ void test_refs_create__symbolic_with_arbitrary_content(void) const char *new_head_tracker = "ANOTHER_HEAD_TRACKER"; const char *arbitrary_target = "ARBITRARY DATA"; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); /* Attempt to create symbolic ref with arbitrary data in target * fails by default @@ -124,7 +124,7 @@ void test_refs_create__deep_symbolic(void) const char *new_head_tracker = "deep/rooted/tracker"; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL)); cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); @@ -145,7 +145,7 @@ void test_refs_create__oid(void) const char *new_head = "refs/heads/new-head"; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); /* Create and write the new object id reference */ cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL)); @@ -180,7 +180,7 @@ void test_refs_create__oid_unknown_succeeds_without_strict(void) const char *new_head = "refs/heads/new-head"; - git_oid__fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); + git_oid_from_string(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0)); @@ -201,7 +201,7 @@ void test_refs_create__oid_unknown_fails_by_default(void) const char *new_head = "refs/heads/new-head"; - git_oid__fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); + git_oid_from_string(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); /* Create and write the new object id reference */ cl_git_fail(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL)); @@ -215,7 +215,7 @@ void test_refs_create__propagate_eexists(void) git_oid oid; /* Make sure it works for oid and for symbolic both */ - cl_git_pass(git_oid__fromstr(&oid, current_master_tip, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, current_master_tip, GIT_OID_SHA1)); cl_git_fail_with(GIT_EEXISTS, git_reference_create(NULL, g_repo, current_head_target, &oid, false, NULL)); cl_git_fail_with(GIT_EEXISTS, git_reference_symbolic_create(NULL, g_repo, "HEAD", current_head_target, false, NULL)); } @@ -227,7 +227,7 @@ void test_refs_create__existing_dir_propagates_edirectory(void) const char *dir_head = "refs/heads/new-dir/new-head", *fail_head = "refs/heads/new-dir"; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); /* Create and write the new object id reference */ cl_git_pass(git_reference_create(&new_reference, g_repo, dir_head, &id, 1, NULL)); @@ -242,7 +242,7 @@ static void test_invalid_name(const char *name) git_reference *new_reference; git_oid id; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_create( &new_reference, g_repo, name, &id, 0, NULL)); @@ -272,7 +272,7 @@ static void test_win32_name(const char *name) git_oid id; int ret; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); ret = git_reference_create(&new_reference, g_repo, name, &id, 0, NULL); @@ -314,7 +314,7 @@ static void count_fsyncs(size_t *create_count, size_t *compress_count) p_fsync__cnt = 0; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/fsync_test", &id, 0, "log message")); git_reference_free(ref); diff --git a/tests/libgit2/refs/delete.c b/tests/libgit2/refs/delete.c index edb521f4a2f..b420bb157a9 100644 --- a/tests/libgit2/refs/delete.c +++ b/tests/libgit2/refs/delete.c @@ -63,7 +63,7 @@ void test_refs_delete__packed_only(void) git_oid id; const char *new_ref = "refs/heads/new_ref"; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); /* Create and write the new object id reference */ cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &id, 0, NULL)); diff --git a/tests/libgit2/refs/foreachglob.c b/tests/libgit2/refs/foreachglob.c index a586ca08c30..4f0b91325f1 100644 --- a/tests/libgit2/refs/foreachglob.c +++ b/tests/libgit2/refs/foreachglob.c @@ -11,7 +11,7 @@ void test_refs_foreachglob__initialize(void) cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); - cl_git_pass(git_oid__fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0, NULL)); } diff --git a/tests/libgit2/refs/lookup.c b/tests/libgit2/refs/lookup.c index 2b8be77f830..16684ce60ca 100644 --- a/tests/libgit2/refs/lookup.c +++ b/tests/libgit2/refs/lookup.c @@ -43,7 +43,7 @@ void test_refs_lookup__oid(void) git_oid tag, expected; cl_git_pass(git_reference_name_to_id(&tag, g_repo, "refs/tags/point_to_blob")); - cl_git_pass(git_oid__fromstr(&expected, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); cl_assert_equal_oid(&expected, &tag); } diff --git a/tests/libgit2/refs/peel.c b/tests/libgit2/refs/peel.c index fefd2d26030..7de0508f02f 100644 --- a/tests/libgit2/refs/peel.c +++ b/tests/libgit2/refs/peel.c @@ -32,7 +32,7 @@ static void assert_peel_generic( cl_git_pass(git_reference_peel(&peeled, ref, requested_type)); - cl_git_pass(git_oid__fromstr(&expected_oid, expected_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected_oid, expected_sha, GIT_OID_SHA1)); cl_assert_equal_oid(&expected_oid, git_object_id(peeled)); cl_assert_equal_i(expected_type, git_object_type(peeled)); diff --git a/tests/libgit2/refs/races.c b/tests/libgit2/refs/races.c index bf46b760eac..243e04f65c8 100644 --- a/tests/libgit2/refs/races.c +++ b/tests/libgit2/refs/races.c @@ -27,8 +27,8 @@ void test_refs_races__create_matching_zero_old(void) git_reference *ref; git_oid id, zero_id; - git_oid__fromstr(&id, commit_id, GIT_OID_SHA1); - git_oid__fromstr(&zero_id, "0000000000000000000000000000000000000000", GIT_OID_SHA1); + git_oid_from_string(&id, commit_id, GIT_OID_SHA1); + git_oid_from_string(&zero_id, "0000000000000000000000000000000000000000", GIT_OID_SHA1); cl_git_fail(git_reference_create_matching(&ref, g_repo, refname, &id, 1, &zero_id, NULL)); git_reference_free(ref); @@ -45,8 +45,8 @@ void test_refs_races__create_matching(void) git_reference *ref, *ref2, *ref3; git_oid id, other_id; - git_oid__fromstr(&id, commit_id, GIT_OID_SHA1); - git_oid__fromstr(&other_id, other_commit_id, GIT_OID_SHA1); + git_oid_from_string(&id, commit_id, GIT_OID_SHA1); + git_oid_from_string(&other_id, other_commit_id, GIT_OID_SHA1); cl_git_fail_with(GIT_EMODIFIED, git_reference_create_matching(&ref, g_repo, refname, &other_id, 1, &other_id, NULL)); @@ -64,8 +64,8 @@ void test_refs_races__symbolic_create_matching(void) git_reference *ref, *ref2, *ref3; git_oid id, other_id; - git_oid__fromstr(&id, commit_id, GIT_OID_SHA1); - git_oid__fromstr(&other_id, other_commit_id, GIT_OID_SHA1); + git_oid_from_string(&id, commit_id, GIT_OID_SHA1); + git_oid_from_string(&other_id, other_commit_id, GIT_OID_SHA1); cl_git_fail_with(GIT_EMODIFIED, git_reference_symbolic_create_matching(&ref, g_repo, "HEAD", other_refname, 1, other_refname, NULL)); @@ -83,8 +83,8 @@ void test_refs_races__delete(void) git_reference *ref, *ref2; git_oid id, other_id; - git_oid__fromstr(&id, commit_id, GIT_OID_SHA1); - git_oid__fromstr(&other_id, other_commit_id, GIT_OID_SHA1); + git_oid_from_string(&id, commit_id, GIT_OID_SHA1); + git_oid_from_string(&other_id, other_commit_id, GIT_OID_SHA1); /* We can delete a value that matches */ cl_git_pass(git_reference_lookup(&ref, g_repo, refname)); @@ -116,8 +116,8 @@ void test_refs_races__switch_oid_to_symbolic(void) git_reference *ref, *ref2, *ref3; git_oid id, other_id; - git_oid__fromstr(&id, commit_id, GIT_OID_SHA1); - git_oid__fromstr(&other_id, other_commit_id, GIT_OID_SHA1); + git_oid_from_string(&id, commit_id, GIT_OID_SHA1); + git_oid_from_string(&other_id, other_commit_id, GIT_OID_SHA1); /* Removing a direct ref when it's currently symbolic should fail */ cl_git_pass(git_reference_lookup(&ref, g_repo, refname)); @@ -145,8 +145,8 @@ void test_refs_races__switch_symbolic_to_oid(void) git_reference *ref, *ref2, *ref3; git_oid id, other_id; - git_oid__fromstr(&id, commit_id, GIT_OID_SHA1); - git_oid__fromstr(&other_id, other_commit_id, GIT_OID_SHA1); + git_oid_from_string(&id, commit_id, GIT_OID_SHA1); + git_oid_from_string(&other_id, other_commit_id, GIT_OID_SHA1); /* Removing a symbolic ref when it's currently direct should fail */ cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/symref")); diff --git a/tests/libgit2/refs/read.c b/tests/libgit2/refs/read.c index 7253cf1373c..5bfe781e3aa 100644 --- a/tests/libgit2/refs/read.c +++ b/tests/libgit2/refs/read.c @@ -82,7 +82,7 @@ void test_refs_read__symbolic(void) cl_assert(object != NULL); cl_assert(git_object_type(object) == GIT_OBJECT_COMMIT); - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_assert_equal_oid(&id, git_object_id(object)); git_object_free(object); @@ -110,7 +110,7 @@ void test_refs_read__nested_symbolic(void) cl_assert(object != NULL); cl_assert(git_object_type(object) == GIT_OBJECT_COMMIT); - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_assert_equal_oid(&id, git_object_id(object)); git_object_free(object); diff --git a/tests/libgit2/refs/reflog/messages.c b/tests/libgit2/refs/reflog/messages.c index 647c00d0dfd..b9a10f9b818 100644 --- a/tests/libgit2/refs/reflog/messages.c +++ b/tests/libgit2/refs/reflog/messages.c @@ -87,7 +87,7 @@ void test_refs_reflog_messages__detaching_writes_reflog(void) const char *msg; msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d"; - git_oid__fromstr(&id, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); + git_oid_from_string(&id, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); cl_git_pass(git_repository_set_head_detached(g_repo, &id)); cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", @@ -109,7 +109,7 @@ void test_refs_reflog_messages__orphan_branch_does_not_count(void) /* Have something known */ msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d"; - git_oid__fromstr(&id, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); + git_oid_from_string(&id, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); cl_git_pass(git_repository_set_head_detached(g_repo, &id)); cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", @@ -280,7 +280,7 @@ void test_refs_reflog_messages__newline_gets_replaced(void) git_oid oid; cl_git_pass(git_signature_now(&signature, "me", "foo@example.com")); - cl_git_pass(git_oid__fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); cl_git_pass(git_reflog_read(&reflog, g_repo, "HEAD")); cl_assert_equal_sz(7, git_reflog_entrycount(reflog)); diff --git a/tests/libgit2/refs/reflog/reflog.c b/tests/libgit2/refs/reflog/reflog.c index 774ec6c93b2..674b809a362 100644 --- a/tests/libgit2/refs/reflog/reflog.c +++ b/tests/libgit2/refs/reflog/reflog.c @@ -80,7 +80,7 @@ void test_refs_reflog_reflog__append_then_read(void) git_reflog *reflog; /* Create a new branch pointing at the HEAD */ - git_oid__fromstr(&oid, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&oid, current_master_tip, GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &oid, 0, NULL)); git_reference_free(ref); @@ -147,7 +147,7 @@ void test_refs_reflog_reflog__removes_empty_reflog_dir(void) git_oid id; /* Create a new branch pointing at the HEAD */ - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL)); git_str_joinpath(&log_path, git_repository_path(g_repo), GIT_REFLOG_DIR); @@ -159,7 +159,7 @@ void test_refs_reflog_reflog__removes_empty_reflog_dir(void) git_reference_free(ref); /* new ref creation should succeed since new-dir is empty */ - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL)); git_reference_free(ref); @@ -173,7 +173,7 @@ void test_refs_reflog_reflog__fails_gracefully_on_nonempty_reflog_dir(void) git_oid id; /* Create a new branch pointing at the HEAD */ - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL)); git_reference_free(ref); @@ -186,7 +186,7 @@ void test_refs_reflog_reflog__fails_gracefully_on_nonempty_reflog_dir(void) cl_must_pass(p_unlink("testrepo.git/refs/heads/new-dir/new-head")); /* new ref creation should fail since new-dir contains reflogs still */ - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_git_fail_with(GIT_EDIRECTORY, git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL)); git_reference_free(ref); @@ -235,7 +235,7 @@ void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_succeeds(void char *star; /* Create a new branch. */ - cl_git_pass(git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1)); cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, refmessage)); /* @@ -298,7 +298,7 @@ void test_refs_reflog_reflog__write_only_std_locations(void) git_reference *ref; git_oid id; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/foo", &id, 1, NULL)); git_reference_free(ref); @@ -318,7 +318,7 @@ void test_refs_reflog_reflog__write_when_explicitly_active(void) git_reference *ref; git_oid id; - git_oid__fromstr(&id, current_master_tip, GIT_OID_SHA1); + git_oid_from_string(&id, current_master_tip, GIT_OID_SHA1); git_reference_ensure_log(g_repo, "refs/tags/foo"); cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1, NULL)); @@ -338,7 +338,7 @@ void test_refs_reflog_reflog__append_to_HEAD_when_changing_current_branch(void) git_reflog_free(log); /* Move it back */ - git_oid__fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); + git_oid_from_string(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/master", &id, 1, NULL)); git_reference_free(ref); @@ -390,7 +390,7 @@ static void assert_no_reflog_update(void) git_reflog_free(log); /* Move it back */ - git_oid__fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); + git_oid_from_string(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/master", &id, 1, NULL)); git_reference_free(ref); @@ -431,7 +431,7 @@ void test_refs_reflog_reflog__logallrefupdates_bare_set_always(void) cl_git_pass(git_config_set_string(config, "core.logallrefupdates", "always")); git_config_free(config); - git_oid__fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); + git_oid_from_string(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1); cl_git_pass(git_reference_create(&ref, g_repo, "refs/bork", &id, 1, "message")); cl_git_pass(git_reflog_read(&log, g_repo, "refs/bork")); diff --git a/tests/libgit2/refs/reflog/reflog_helpers.c b/tests/libgit2/refs/reflog/reflog_helpers.c index 6a7e706d6c6..56051d256c6 100644 --- a/tests/libgit2/refs/reflog/reflog_helpers.c +++ b/tests/libgit2/refs/reflog/reflog_helpers.c @@ -53,7 +53,7 @@ void cl_reflog_check_entry_(git_repository *repo, const char *reflog, size_t idx git_object_free(obj); } else { git_oid *oid = git__calloc(1, sizeof(*oid)); - git_oid__fromstr(oid, old_spec, GIT_OID_SHA1); + git_oid_from_string(oid, old_spec, GIT_OID_SHA1); if (git_oid_cmp(oid, git_reflog_entry_id_old(entry)) != 0) { git_object__write_oid_header(&result, "\tOld OID: \"", oid); git_object__write_oid_header(&result, "\" != \"", git_reflog_entry_id_old(entry)); @@ -73,7 +73,7 @@ void cl_reflog_check_entry_(git_repository *repo, const char *reflog, size_t idx git_object_free(obj); } else { git_oid *oid = git__calloc(1, sizeof(*oid)); - git_oid__fromstr(oid, new_spec, GIT_OID_SHA1); + git_oid_from_string(oid, new_spec, GIT_OID_SHA1); if (git_oid_cmp(oid, git_reflog_entry_id_new(entry)) != 0) { git_object__write_oid_header(&result, "\tNew OID: \"", oid); git_object__write_oid_header(&result, "\" != \"", git_reflog_entry_id_new(entry)); diff --git a/tests/libgit2/refs/transactions.c b/tests/libgit2/refs/transactions.c index 98ae6f73ae2..17c0b22ed21 100644 --- a/tests/libgit2/refs/transactions.c +++ b/tests/libgit2/refs/transactions.c @@ -21,7 +21,7 @@ void test_refs_transactions__single_ref_oid(void) git_reference *ref; git_oid id; - git_oid__fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master")); cl_git_pass(git_transaction_set_target(g_tx, "refs/heads/master", &id, NULL, NULL)); @@ -52,7 +52,7 @@ void test_refs_transactions__single_ref_mix_types(void) git_reference *ref; git_oid id; - git_oid__fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master")); cl_git_pass(git_transaction_lock_ref(g_tx, "HEAD")); @@ -90,7 +90,7 @@ void test_refs_transactions__single_create(void) cl_git_pass(git_transaction_lock_ref(g_tx, name)); - git_oid__fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_pass(git_transaction_set_target(g_tx, name, &id, NULL, NULL)); cl_git_pass(git_transaction_commit(g_tx)); @@ -104,7 +104,7 @@ void test_refs_transactions__unlocked_set(void) git_oid id; cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master")); - git_oid__fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + git_oid_from_string(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); cl_git_fail_with(GIT_ENOTFOUND, git_transaction_set_target(g_tx, "refs/heads/foo", &id, NULL, NULL)); cl_git_pass(git_transaction_commit(g_tx)); } @@ -122,7 +122,7 @@ void test_refs_transactions__error_on_locking_locked_ref(void) cl_git_pass(git_transaction_lock_ref(g_tx_with_lock, "refs/heads/master")); /* lock reference for set_target */ - cl_git_pass(git_oid__fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); cl_git_fail_with(GIT_ELOCKED, git_transaction_lock_ref(g_tx, "refs/heads/master")); cl_git_fail_with(GIT_ENOTFOUND, git_transaction_set_target(g_tx, "refs/heads/master", &id, NULL, NULL)); diff --git a/tests/libgit2/repo/env.c b/tests/libgit2/repo/env.c index 0e6cc59d5e2..c9e60d901bf 100644 --- a/tests/libgit2/repo/env.c +++ b/tests/libgit2/repo/env.c @@ -99,9 +99,9 @@ static void env_check_objects_(bool a, bool t, bool p, const char *file, const c git_repository *repo; git_oid oid_a, oid_t, oid_p; git_object *object; - cl_git_pass(git_oid__fromstr(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07", GIT_OID_SHA1)); cl_git_expect(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, func, line); if (a) { diff --git a/tests/libgit2/repo/getters.c b/tests/libgit2/repo/getters.c index 8e21d35b512..b1b41690fc4 100644 --- a/tests/libgit2/repo/getters.c +++ b/tests/libgit2/repo/getters.c @@ -59,7 +59,7 @@ void test_repo_getters__commit_parents(void) git_oid first_parent; git_oid merge_parents[4]; - git_oid__fromstr(&first_parent, "099fabac3a9ea935598528c27f866e34089c2eff", GIT_OID_SHA1); + git_oid_from_string(&first_parent, "099fabac3a9ea935598528c27f866e34089c2eff", GIT_OID_SHA1); /* A commit on a new repository has no parents */ @@ -96,13 +96,13 @@ void test_repo_getters__commit_parents(void) cl_assert_equal_oid(&first_parent, git_commit_id(parents.commits[0])); - git_oid__fromstr(&merge_parents[0], "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1); + git_oid_from_string(&merge_parents[0], "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1); cl_assert_equal_oid(&merge_parents[0], git_commit_id(parents.commits[1])); - git_oid__fromstr(&merge_parents[1], "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); + git_oid_from_string(&merge_parents[1], "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); cl_assert_equal_oid(&merge_parents[1], git_commit_id(parents.commits[2])); - git_oid__fromstr(&merge_parents[2], "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1); + git_oid_from_string(&merge_parents[2], "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", GIT_OID_SHA1); cl_assert_equal_oid(&merge_parents[2], git_commit_id(parents.commits[3])); - git_oid__fromstr(&merge_parents[3], "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1); + git_oid_from_string(&merge_parents[3], "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1); cl_assert_equal_oid(&merge_parents[3], git_commit_id(parents.commits[4])); git_commitarray_dispose(&parents); diff --git a/tests/libgit2/repo/head.c b/tests/libgit2/repo/head.c index c886c3f79d0..7dea91efeb7 100644 --- a/tests/libgit2/repo/head.c +++ b/tests/libgit2/repo/head.c @@ -99,7 +99,7 @@ void test_repo_head__set_head_detached_Return_ENOTFOUND_when_the_object_doesnt_e { git_oid oid; - cl_git_pass(git_oid__fromstr(&oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", GIT_OID_SHA1)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head_detached(repo, &oid)); } diff --git a/tests/libgit2/reset/hard.c b/tests/libgit2/reset/hard.c index fa7c0b3e633..db1ea471352 100644 --- a/tests/libgit2/reset/hard.c +++ b/tests/libgit2/reset/hard.c @@ -123,9 +123,9 @@ static void unmerged_index_init(git_index *index, int entries) int write_theirs = 4; git_oid ancestor, ours, theirs; - git_oid__fromstr(&ancestor, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); - git_oid__fromstr(&ours, "32504b727382542f9f089e24fddac5e78533e96c", GIT_OID_SHA1); - git_oid__fromstr(&theirs, "061d42a44cacde5726057b67558821d95db96f19", GIT_OID_SHA1); + git_oid_from_string(&ancestor, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); + git_oid_from_string(&ours, "32504b727382542f9f089e24fddac5e78533e96c", GIT_OID_SHA1); + git_oid_from_string(&theirs, "061d42a44cacde5726057b67558821d95db96f19", GIT_OID_SHA1); cl_git_rewritefile("status/conflicting_file", "conflicting file\n"); diff --git a/tests/libgit2/revert/bare.c b/tests/libgit2/revert/bare.c index db443024ed6..eb811898796 100644 --- a/tests/libgit2/revert/bare.c +++ b/tests/libgit2/revert/bare.c @@ -34,10 +34,10 @@ void test_revert_bare__automerge(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; - git_oid__fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head_commit, repo, &head_oid)); - git_oid__fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_oid)); cl_git_pass(git_revert_commit(&index, repo, revert_commit, head_commit, 0, NULL)); @@ -64,7 +64,7 @@ void test_revert_bare__conflicts(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; - git_oid__fromstr(&revert_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head_ref, GIT_OBJECT_COMMIT)); @@ -91,10 +91,10 @@ void test_revert_bare__orphan(void) { 0100644, "296a6d3be1dff05c5d1f631d2459389fa7b619eb", 0, "file-mainline.txt" }, }; - git_oid__fromstr(&head_oid, "39467716290f6df775a91cdb9a4eb39295018145", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "39467716290f6df775a91cdb9a4eb39295018145", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head_commit, repo, &head_oid)); - git_oid__fromstr(&revert_oid, "ebb03002cee5d66c7732dd06241119fe72ab96a5", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "ebb03002cee5d66c7732dd06241119fe72ab96a5", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_oid)); cl_git_pass(git_revert_commit(&index, repo, revert_commit, head_commit, 0, NULL)); diff --git a/tests/libgit2/revert/rename.c b/tests/libgit2/revert/rename.c index be7a9804143..ab9303bc4eb 100644 --- a/tests/libgit2/revert/rename.c +++ b/tests/libgit2/revert/rename.c @@ -36,7 +36,7 @@ void test_revert_rename__automerge(void) cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&head_commit, head_ref, GIT_OBJECT_COMMIT)); - cl_git_pass(git_oid__fromstr(&revert_oid, "7b4d7c3789b3581973c04087cb774c3c3576de2f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&revert_oid, "7b4d7c3789b3581973c04087cb774c3c3576de2f", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_oid)); cl_git_pass(git_revert_commit(&index, repo, revert_commit, head_commit, 0, NULL)); diff --git a/tests/libgit2/revert/workdir.c b/tests/libgit2/revert/workdir.c index 8d1246efe0d..15bada85c1d 100644 --- a/tests/libgit2/revert/workdir.c +++ b/tests/libgit2/revert/workdir.c @@ -45,11 +45,11 @@ void test_revert_workdir__automerge(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; - git_oid__fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, NULL)); @@ -76,7 +76,7 @@ void test_revert_workdir__conflicts(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; - git_oid__fromstr(&revert_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&head, head_ref, GIT_OBJECT_COMMIT)); @@ -141,11 +141,11 @@ void test_revert_workdir__orphan(void) { 0100644, "296a6d3be1dff05c5d1f631d2459389fa7b619eb", 0, "file-mainline.txt" }, }; - git_oid__fromstr(&head_oid, "39467716290f6df775a91cdb9a4eb39295018145", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "39467716290f6df775a91cdb9a4eb39295018145", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&revert_oid, "ebb03002cee5d66c7732dd06241119fe72ab96a5", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "ebb03002cee5d66c7732dd06241119fe72ab96a5", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, NULL)); @@ -224,11 +224,11 @@ void test_revert_workdir__again_after_automerge(void) { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; - git_oid__fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, NULL)); @@ -272,11 +272,11 @@ void test_revert_workdir__again_after_edit(void) cl_git_pass(git_repository_head(&head_ref, repo)); - cl_git_pass(git_oid__fromstr(&orig_head_oid, "399fb3aba3d9d13f7d40a9254ce4402067ef3149", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&orig_head_oid, "399fb3aba3d9d13f7d40a9254ce4402067ef3149", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&orig_head, repo, &orig_head_oid)); cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD, NULL)); - cl_git_pass(git_oid__fromstr(&revert_oid, "2d440f2b3147d3dc7ad1085813478d6d869d5a4d", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&revert_oid, "2d440f2b3147d3dc7ad1085813478d6d869d5a4d", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, NULL)); @@ -321,11 +321,11 @@ void test_revert_workdir__again_after_edit_two(void) cl_git_pass(git_repository_config(&config, repo)); cl_git_pass(git_config_set_bool(config, "core.autocrlf", 0)); - cl_git_pass(git_oid__fromstr(&head_commit_oid, "75ec9929465623f17ff3ad68c0438ea56faba815", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&head_commit_oid, "75ec9929465623f17ff3ad68c0438ea56faba815", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_oid)); cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL)); - cl_git_pass(git_oid__fromstr(&revert_commit_oid, "97e52d5e81f541080cd6b92829fb85bc4d81d90b", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&revert_commit_oid, "97e52d5e81f541080cd6b92829fb85bc4d81d90b", GIT_OID_SHA1)); cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_commit_oid)); cl_git_pass(git_revert(repo, revert_commit, NULL)); @@ -376,11 +376,11 @@ void test_revert_workdir__conflict_use_ours(void) opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_USE_OURS; - git_oid__fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, &opts)); @@ -412,11 +412,11 @@ void test_revert_workdir__rename_1_of_2(void) opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; - git_oid__fromstr(&head_oid, "cef56612d71a6af8d8015691e4865f7fece905b5", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "cef56612d71a6af8d8015691e4865f7fece905b5", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&revert_oid, "55568c8de5322ff9a95d72747a239cdb64a19965", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "55568c8de5322ff9a95d72747a239cdb64a19965", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, &opts)); @@ -446,11 +446,11 @@ void test_revert_workdir__rename(void) opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES; opts.merge_opts.rename_threshold = 50; - git_oid__fromstr(&head_oid, "55568c8de5322ff9a95d72747a239cdb64a19965", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "55568c8de5322ff9a95d72747a239cdb64a19965", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); - git_oid__fromstr(&revert_oid, "0aa8c7e40d342fff78d60b29a4ba8e993ed79c51", GIT_OID_SHA1); + git_oid_from_string(&revert_oid, "0aa8c7e40d342fff78d60b29a4ba8e993ed79c51", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, &opts)); @@ -512,7 +512,7 @@ void test_revert_workdir__merge_fails_without_mainline_specified(void) git_commit *head; git_oid head_oid; - git_oid__fromstr(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); @@ -539,7 +539,7 @@ void test_revert_workdir__merge_first_parent(void) opts.mainline = 1; - git_oid__fromstr(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); @@ -564,7 +564,7 @@ void test_revert_workdir__merge_second_parent(void) opts.mainline = 2; - git_oid__fromstr(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579", GIT_OID_SHA1); + git_oid_from_string(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579", GIT_OID_SHA1); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); diff --git a/tests/libgit2/revwalk/basic.c b/tests/libgit2/revwalk/basic.c index 41090a1dac8..b4cf76d262e 100644 --- a/tests/libgit2/revwalk/basic.c +++ b/tests/libgit2/revwalk/basic.c @@ -139,7 +139,7 @@ void test_revwalk_basic__sorting_modes(void) revwalk_basic_setup_walk(NULL); - git_oid__fromstr(&id, commit_head, GIT_OID_SHA1); + git_oid_from_string(&id, commit_head, GIT_OID_SHA1); cl_git_pass(test_walk(_walk, &id, GIT_SORT_TIME, commit_sorting_time, 1)); cl_git_pass(test_walk(_walk, &id, GIT_SORT_TOPOLOGICAL, commit_sorting_topo, 2)); @@ -221,7 +221,7 @@ void test_revwalk_basic__sorted_after_reset(void) revwalk_basic_setup_walk(NULL); - git_oid__fromstr(&oid, commit_head, GIT_OID_SHA1); + git_oid_from_string(&oid, commit_head, GIT_OID_SHA1); /* push, sort, and test the walk */ cl_git_pass(git_revwalk_push(_walk, &oid)); @@ -299,7 +299,7 @@ void test_revwalk_basic__multiple_push_1(void) cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/packed-test")); - cl_git_pass(git_oid__fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); cl_git_pass(git_revwalk_push(_walk, &oid)); while (git_revwalk_next(&oid, _walk) == 0) @@ -333,7 +333,7 @@ void test_revwalk_basic__multiple_push_2(void) revwalk_basic_setup_walk(NULL); - cl_git_pass(git_oid__fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); cl_git_pass(git_revwalk_push(_walk, &oid)); cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/packed-test")); @@ -352,7 +352,7 @@ void test_revwalk_basic__disallow_non_commit(void) revwalk_basic_setup_walk(NULL); - cl_git_pass(git_oid__fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91", GIT_OID_SHA1)); cl_git_fail(git_revwalk_push(_walk, &oid)); } @@ -362,7 +362,7 @@ void test_revwalk_basic__hide_then_push(void) int i = 0; revwalk_basic_setup_walk(NULL); - cl_git_pass(git_oid__fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); cl_git_pass(git_revwalk_hide(_walk, &oid)); cl_git_pass(git_revwalk_push(_walk, &oid)); @@ -376,7 +376,7 @@ void test_revwalk_basic__hide_then_push(void) void test_revwalk_basic__topo_crash(void) { git_oid oid; - git_oid__fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); + git_oid_from_string(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); revwalk_basic_setup_walk(NULL); git_revwalk_sorting(_walk, GIT_SORT_TOPOLOGICAL); @@ -395,8 +395,8 @@ void test_revwalk_basic__from_new_to_old(void) revwalk_basic_setup_walk(NULL); git_revwalk_sorting(_walk, GIT_SORT_TIME); - cl_git_pass(git_oid__fromstr(&to_oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&from_oid, "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&to_oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&from_oid, "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); cl_git_pass(git_revwalk_push(_walk, &to_oid)); cl_git_pass(git_revwalk_hide(_walk, &from_oid)); @@ -496,7 +496,7 @@ void test_revwalk_basic__mimic_git_rev_list(void) cl_git_pass(git_revwalk_push_ref(_walk, "refs/heads/br2")); cl_git_pass(git_revwalk_push_ref(_walk, "refs/heads/master")); - cl_git_pass(git_oid__fromstr(&oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1)); cl_git_pass(git_revwalk_push(_walk, &oid)); cl_git_pass(git_revwalk_next(&oid, _walk)); @@ -580,10 +580,10 @@ void test_revwalk_basic__old_hidden_commit_one(void) revwalk_basic_setup_walk("testrepo.git"); - cl_git_pass(git_oid__fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&new_id, "bd758010071961f28336333bc41e9c64c9a64866", GIT_OID_SHA1)); cl_git_pass(git_revwalk_push(_walk, &new_id)); - cl_git_pass(git_oid__fromstr(&old_id, "8e73b769e97678d684b809b163bebdae2911720f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&old_id, "8e73b769e97678d684b809b163bebdae2911720f", GIT_OID_SHA1)); cl_git_pass(git_revwalk_hide(_walk, &old_id)); cl_git_pass(git_revwalk_next(&oid, _walk)); @@ -604,10 +604,10 @@ void test_revwalk_basic__old_hidden_commit_two(void) revwalk_basic_setup_walk("testrepo.git"); - cl_git_pass(git_oid__fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&new_id, "bd758010071961f28336333bc41e9c64c9a64866", GIT_OID_SHA1)); cl_git_pass(git_revwalk_push(_walk, &new_id)); - cl_git_pass(git_oid__fromstr(&old_id, "b91e763008b10db366442469339f90a2b8400d0a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&old_id, "b91e763008b10db366442469339f90a2b8400d0a", GIT_OID_SHA1)); cl_git_pass(git_revwalk_hide(_walk, &old_id)); cl_git_pass(git_revwalk_next(&oid, _walk)); diff --git a/tests/libgit2/revwalk/hidecb.c b/tests/libgit2/revwalk/hidecb.c index 2100a54f26c..132b6a837ba 100644 --- a/tests/libgit2/revwalk/hidecb.c +++ b/tests/libgit2/revwalk/hidecb.c @@ -32,10 +32,10 @@ void test_revwalk_hidecb__initialize(void) int i; cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); - cl_git_pass(git_oid__fromstr(&_head_id, commit_head, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&_head_id, commit_head, GIT_OID_SHA1)); for (i = 0; i < commit_count; i++) - cl_git_pass(git_oid__fromstr(&commit_ids[i], commit_strs[i], GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&commit_ids[i], commit_strs[i], GIT_OID_SHA1)); } diff --git a/tests/libgit2/revwalk/mergebase.c b/tests/libgit2/revwalk/mergebase.c index d413a1f6edb..1d7f6908a47 100644 --- a/tests/libgit2/revwalk/mergebase.c +++ b/tests/libgit2/revwalk/mergebase.c @@ -25,9 +25,9 @@ void test_revwalk_mergebase__single1(void) git_oid result, one, two, expected; size_t ahead, behind; - cl_git_pass(git_oid__fromstr(&one, "c47800c7266a2be04c571c04d5a6614691ea99bd ", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1)); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert_equal_oid(&expected, &result); @@ -46,9 +46,9 @@ void test_revwalk_mergebase__single2(void) git_oid result, one, two, expected; size_t ahead, behind; - cl_git_pass(git_oid__fromstr(&one, "763d71aadf09a7951596c9746c024e7eece7c7af", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "763d71aadf09a7951596c9746c024e7eece7c7af", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert_equal_oid(&expected, &result); @@ -67,9 +67,9 @@ void test_revwalk_mergebase__merged_branch(void) git_oid result, one, two, expected; size_t ahead, behind; - cl_git_pass(git_oid__fromstr(&one, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert_equal_oid(&expected, &result); @@ -91,8 +91,8 @@ void test_revwalk_mergebase__two_way_merge(void) git_oid one, two; size_t ahead, behind; - cl_git_pass(git_oid__fromstr(&one, "9b219343610c88a1187c996d0dc58330b55cee28", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "a953a018c5b10b20c86e69fef55ebc8ad4c5a417", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "9b219343610c88a1187c996d0dc58330b55cee28", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "a953a018c5b10b20c86e69fef55ebc8ad4c5a417", GIT_OID_SHA1)); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo2, &one, &two)); cl_assert_equal_sz(ahead, 8); @@ -110,8 +110,8 @@ void test_revwalk_mergebase__no_common_ancestor_returns_ENOTFOUND(void) size_t ahead, behind; int error; - cl_git_pass(git_oid__fromstr(&one, "763d71aadf09a7951596c9746c024e7eece7c7af", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "763d71aadf09a7951596c9746c024e7eece7c7af", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1)); error = git_merge_base(&result, _repo, &one, &two); cl_git_fail(error); @@ -127,9 +127,9 @@ void test_revwalk_mergebase__prefer_youngest_merge_base(void) { git_oid result, one, two, expected; - cl_git_pass(git_oid__fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert_equal_oid(&expected, &result); @@ -140,10 +140,10 @@ void test_revwalk_mergebase__multiple_merge_bases(void) git_oid one, two, expected1, expected2; git_oidarray result = {NULL, 0}; - cl_git_pass(git_oid__fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); cl_git_pass(git_merge_bases(&result, _repo, &one, &two)); cl_assert_equal_i(2, result.count); @@ -160,10 +160,10 @@ void test_revwalk_mergebase__multiple_merge_bases_many_commits(void) git_oid *input = git__malloc(sizeof(git_oid) * 2); - cl_git_pass(git_oid__fromstr(&input[0], "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&input[1], "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&input[0], "a4a7dce85cf63874e984719f4fdd239f5145052f", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&input[1], "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a", GIT_OID_SHA1)); cl_git_pass(git_merge_bases_many(&result, _repo, 2, input)); cl_assert_equal_i(2, result.count); @@ -178,8 +178,8 @@ void test_revwalk_mergebase__no_off_by_one_missing(void) { git_oid result, one, two; - cl_git_pass(git_oid__fromstr(&one, "1a443023183e3f2bfbef8ac923cd81c1018a18fd", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "9f13f7d0a9402c681f91dc590cf7b5470e6a77d2", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "1a443023183e3f2bfbef8ac923cd81c1018a18fd", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "9f13f7d0a9402c681f91dc590cf7b5470e6a77d2", GIT_OID_SHA1)); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); } @@ -201,7 +201,7 @@ static void assert_mergebase_many(const char *expected_sha, int count, ...) for (i = 0; i < count; ++i) { partial_oid = va_arg(ap, char *); - cl_git_pass(git_oid__fromstrn(&oid, partial_oid, strlen(partial_oid), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, partial_oid, strlen(partial_oid), GIT_OID_SHA1)); cl_git_pass(git_object_lookup_prefix(&object, _repo, &oid, strlen(partial_oid), GIT_OBJECT_COMMIT)); git_oid_cpy(&oids[i], git_object_id(object)); @@ -214,7 +214,7 @@ static void assert_mergebase_many(const char *expected_sha, int count, ...) cl_assert_equal_i(GIT_ENOTFOUND, git_merge_base_many(&oid, _repo, count, oids)); else { cl_git_pass(git_merge_base_many(&oid, _repo, count, oids)); - cl_git_pass(git_oid__fromstr(&expected, expected_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, expected_sha, GIT_OID_SHA1)); cl_assert_equal_oid(&expected, &oid); } @@ -265,7 +265,7 @@ static void assert_mergebase_octopus(const char *expected_sha, int count, ...) for (i = 0; i < count; ++i) { partial_oid = va_arg(ap, char *); - cl_git_pass(git_oid__fromstrn(&oid, partial_oid, strlen(partial_oid), GIT_OID_SHA1)); + cl_git_pass(git_oid_from_prefix(&oid, partial_oid, strlen(partial_oid), GIT_OID_SHA1)); cl_git_pass(git_object_lookup_prefix(&object, _repo, &oid, strlen(partial_oid), GIT_OBJECT_COMMIT)); git_oid_cpy(&oids[i], git_object_id(object)); @@ -278,7 +278,7 @@ static void assert_mergebase_octopus(const char *expected_sha, int count, ...) cl_assert_equal_i(GIT_ENOTFOUND, git_merge_base_octopus(&oid, _repo, count, oids)); else { cl_git_pass(git_merge_base_octopus(&oid, _repo, count, oids)); - cl_git_pass(git_oid__fromstr(&expected, expected_sha, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&expected, expected_sha, GIT_OID_SHA1)); cl_assert_equal_oid(&expected, &oid); } @@ -501,9 +501,9 @@ void test_revwalk_mergebase__remove_redundant(void) cl_git_pass(git_repository_open(&repo, cl_fixture("redundant.git"))); - cl_git_pass(git_oid__fromstr(&one, "d89137c93ba1ee749214ff4ce52ae9137bc833f9", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&two, "91f4b95df4a59504a9813ba66912562931d990e3", GIT_OID_SHA1)); - cl_git_pass(git_oid__fromstr(&base, "6cb1f2352d974e1c5a776093017e8772416ac97a", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&one, "d89137c93ba1ee749214ff4ce52ae9137bc833f9", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&two, "91f4b95df4a59504a9813ba66912562931d990e3", GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&base, "6cb1f2352d974e1c5a776093017e8772416ac97a", GIT_OID_SHA1)); cl_git_pass(git_merge_bases(&result, repo, &one, &two)); cl_assert_equal_i(1, result.count); diff --git a/tests/libgit2/revwalk/simplify.c b/tests/libgit2/revwalk/simplify.c index 824496d7eb9..70c1a666124 100644 --- a/tests/libgit2/revwalk/simplify.c +++ b/tests/libgit2/revwalk/simplify.c @@ -32,13 +32,13 @@ void test_revwalk_simplify__first_parent(void) int i, error; for (i = 0; i < 4; i++) { - git_oid__fromstr(&expected[i], expected_str[i], GIT_OID_SHA1); + git_oid_from_string(&expected[i], expected_str[i], GIT_OID_SHA1); } repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_revwalk_new(&walk, repo)); - git_oid__fromstr(&id, commit_head, GIT_OID_SHA1); + git_oid_from_string(&id, commit_head, GIT_OID_SHA1); cl_git_pass(git_revwalk_push(walk, &id)); git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL); git_revwalk_simplify_first_parent(walk); diff --git a/tests/libgit2/status/single.c b/tests/libgit2/status/single.c index b9659a0315d..d217064b582 100644 --- a/tests/libgit2/status/single.c +++ b/tests/libgit2/status/single.c @@ -18,7 +18,7 @@ void test_status_single__hash_single_file(void) git_oid expected_id, actual_id; /* initialization */ - git_oid__fromstr(&expected_id, file_hash, GIT_OID_SHA1); + git_oid_from_string(&expected_id, file_hash, GIT_OID_SHA1); cl_git_mkfile(file_name, file_contents); cl_set_cleanup(&cleanup__remove_file, (void *)file_name); @@ -36,7 +36,7 @@ void test_status_single__hash_single_empty_file(void) git_oid expected_id, actual_id; /* initialization */ - git_oid__fromstr(&expected_id, file_hash, GIT_OID_SHA1); + git_oid_from_string(&expected_id, file_hash, GIT_OID_SHA1); cl_git_mkfile(file_name, file_contents); cl_set_cleanup(&cleanup__remove_file, (void *)file_name); diff --git a/tests/libgit2/status/submodules.c b/tests/libgit2/status/submodules.c index 90d56d9cc8e..9c901144592 100644 --- a/tests/libgit2/status/submodules.c +++ b/tests/libgit2/status/submodules.c @@ -142,7 +142,7 @@ void test_status_submodules__moved_head(void) /* move submodule HEAD to c47800c7266a2be04c571c04d5a6614691ea99bd */ cl_git_pass( - git_oid__fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); + git_oid_from_string(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd", GIT_OID_SHA1)); cl_git_pass(git_repository_set_head_detached(smrepo, &oid)); /* first do a normal status, which should now include the submodule */ diff --git a/tests/libgit2/status/worktree.c b/tests/libgit2/status/worktree.c index 8a2ea9cb674..9e3623361bf 100644 --- a/tests/libgit2/status/worktree.c +++ b/tests/libgit2/status/worktree.c @@ -515,19 +515,19 @@ void test_status_worktree__conflict_with_diff3(void) ancestor_entry.path = "modified_file"; ancestor_entry.mode = 0100644; - git_oid__fromstr(&ancestor_entry.id, + git_oid_from_string(&ancestor_entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); our_entry.path = "modified_file"; our_entry.mode = 0100644; - git_oid__fromstr(&our_entry.id, + git_oid_from_string(&our_entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); their_entry.path = "modified_file"; their_entry.mode = 0100644; - git_oid__fromstr(&their_entry.id, + git_oid_from_string(&their_entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); @@ -714,19 +714,19 @@ void test_status_worktree__conflicted_item(void) ancestor_entry.mode = 0100644; ancestor_entry.path = "modified_file"; - git_oid__fromstr(&ancestor_entry.id, + git_oid_from_string(&ancestor_entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); our_entry.mode = 0100644; our_entry.path = "modified_file"; - git_oid__fromstr(&our_entry.id, + git_oid_from_string(&our_entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); their_entry.mode = 0100644; their_entry.path = "modified_file"; - git_oid__fromstr(&their_entry.id, + git_oid_from_string(&their_entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); @@ -754,7 +754,7 @@ void test_status_worktree__conflict_has_no_oid(void) entry.mode = 0100644; entry.path = "modified_file"; - git_oid__fromstr(&entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", GIT_OID_SHA1); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_conflict_add(index, &entry, &entry, &entry)); diff --git a/tests/libgit2/submodule/add.c b/tests/libgit2/submodule/add.c index 5208c7fcaa5..915ccf415dc 100644 --- a/tests/libgit2/submodule/add.c +++ b/tests/libgit2/submodule/add.c @@ -139,7 +139,7 @@ static void test_add_entry( { git_index_entry entry = {{0}}; - cl_git_pass(git_oid__fromstr(&entry.id, idstr, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&entry.id, idstr, GIT_OID_SHA1)); entry.path = path; entry.mode = mode; diff --git a/tests/libgit2/transports/smart/packet.c b/tests/libgit2/transports/smart/packet.c index a775a4cfab4..3fb0bf6b305 100644 --- a/tests/libgit2/transports/smart/packet.c +++ b/tests/libgit2/transports/smart/packet.c @@ -73,7 +73,7 @@ static void assert_ack_parses(const char *line, const char *expected_oid, enum g git_oid oid; git_pkt_parse_data pkt_parse_data = { 1, GIT_OID_SHA1 }; - cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, expected_oid, GIT_OID_SHA1)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_ACK); @@ -165,7 +165,7 @@ static void assert_ref_parses_(const char *line, size_t linelen, const char *exp git_oid oid; git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); + cl_git_pass(git_oid_from_string(&oid, expected_oid, GIT_OID_SHA1)); cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_REF); diff --git a/tests/libgit2/win32/forbidden.c b/tests/libgit2/win32/forbidden.c index c4e82e90deb..bcdcdc3a7c2 100644 --- a/tests/libgit2/win32/forbidden.c +++ b/tests/libgit2/win32/forbidden.c @@ -37,7 +37,7 @@ void test_win32_forbidden__can_add_forbidden_filename_with_entry(void) entry.path = "aux"; entry.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&entry.id, "da623abd956bb2fd8052c708c7ed43f05d192d37", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "da623abd956bb2fd8052c708c7ed43f05d192d37", GIT_OID_SHA1); cl_git_pass(git_index_add(index, &entry)); @@ -53,7 +53,7 @@ void test_win32_forbidden__cannot_add_dot_git_even_with_entry(void) entry.path = "foo/.git"; entry.mode = GIT_FILEMODE_BLOB; - git_oid__fromstr(&entry.id, "da623abd956bb2fd8052c708c7ed43f05d192d37", GIT_OID_SHA1); + git_oid_from_string(&entry.id, "da623abd956bb2fd8052c708c7ed43f05d192d37", GIT_OID_SHA1); cl_git_fail(git_index_add(index, &entry)); From 2fa13adf09c8dd1f334f57023390043ea3f71cb2 Mon Sep 17 00:00:00 2001 From: Florian Pircher Date: Thu, 2 Jan 2025 17:19:58 +0100 Subject: [PATCH 782/816] include: Fix code comment termination --- include/git2/stdint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/git2/stdint.h b/include/git2/stdint.h index 4b235c73f87..4f532e13c85 100644 --- a/include/git2/stdint.h +++ b/include/git2/stdint.h @@ -221,7 +221,7 @@ typedef uint64_t uintmax_t; #endif /* __STDC_LIMIT_MACROS ] */ -/* 7.18.4 Limits of other integer types +/* 7.18.4 Limits of other integer types */ #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) /* [ See footnote 224 at page 260 */ From 01c16e6aa7a2377f115375aa9fdebd30f0f9f797 Mon Sep 17 00:00:00 2001 From: peter15914 <48548636+peter15914@users.noreply.github.com> Date: Fri, 3 Jan 2025 01:22:53 +0500 Subject: [PATCH 783/816] =?UTF-8?q?transport:=20=D1=81heck=20a=20pointer?= =?UTF-8?q?=20allocation=20result?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GIT_ERROR_CHECK_ALLOC was added to check the return value of git__calloc(). --- tests/libgit2/transport/register.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/libgit2/transport/register.c b/tests/libgit2/transport/register.c index 4d3c09726da..1554afc23c2 100644 --- a/tests/libgit2/transport/register.c +++ b/tests/libgit2/transport/register.c @@ -144,6 +144,7 @@ static int custom_subtransport__action( git_remote_connect_options_dispose(&opts); *out = git__calloc(1, sizeof(git_smart_subtransport_stream)); + GIT_ERROR_CHECK_ALLOC(*out); (*out)->subtransport = transport; (*out)->read = custom_subtransport_stream__read; (*out)->write = custom_subtransport_stream__write; @@ -169,6 +170,7 @@ static void custom_subtransport__free(git_smart_subtransport *transport) static int custom_transport_callback(git_smart_subtransport **out, git_transport *owner, void *param) { struct custom_subtransport *subtransport = git__calloc(1, sizeof(struct custom_subtransport)); + GIT_ERROR_CHECK_ALLOC(subtransport); subtransport->called = (int *)param; subtransport->owner = owner; subtransport->subtransport.action = custom_subtransport__action; From a7c4c7d8c8e139073988daaa628d605b61435552 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jan 2025 21:13:11 +0000 Subject: [PATCH 784/816] deps: remove chromium-zlib Remove the ability to compile-in chromium zlib. If users want to supply their own zlib implementation, it should be external to our build environment. --- deps/chromium-zlib/CMakeLists.txt | 101 ------------------------------ 1 file changed, 101 deletions(-) delete mode 100644 deps/chromium-zlib/CMakeLists.txt diff --git a/deps/chromium-zlib/CMakeLists.txt b/deps/chromium-zlib/CMakeLists.txt deleted file mode 100644 index 55d67948dbe..00000000000 --- a/deps/chromium-zlib/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -# CMake build script for the bundled Chromium zlib implementation. So far, it -# is only supported for x86_64 processors with CLMUL, SSE3, SSE4.2. -# -# TODO: The Chromium build file (in deps/chromium-zlib/zlib/BUILD.gn) supports -# more platforms (like ARM with NEON), more can be enabled as needed. - -cmake_minimum_required(VERSION 3.11) - -include(FetchContent) -include(FindGit) - -# Ensure that the git binary is present to download the sources. -find_package(Git) -if(NOT Git_FOUND) - message(FATAL_ERROR "git is required to download the Chromium zlib sources") -endif() - -fetchcontent_populate(chromium_zlib_src - GIT_REPOSITORY https://chromium.googlesource.com/chromium/src/third_party/zlib.git - GIT_TAG 2c183c9f93a328bfb3121284da13cf89a0f7e64a - QUIET -) - -# The Chromium build globally disables some warnings. -disable_warnings(implicit-fallthrough) -disable_warnings(unused-function) -disable_warnings(unused-parameter) -disable_warnings(sign-compare) -disable_warnings(declaration-after-statement) -disable_warnings(missing-declarations) - -# -O3 is also set by the Chromium configuration and has been deemed safe enough -# for them. -set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG") -set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") - -# Common definitions. -add_definitions( - -DSTDC - -DNO_GZIP - -DZLIB_IMPLEMENTATION -) -list(APPEND SRC_ZLIB - "${chromium_zlib_src_SOURCE_DIR}/adler32.c" - "${chromium_zlib_src_SOURCE_DIR}/chromeconf.h" - "${chromium_zlib_src_SOURCE_DIR}/compress.c" - "${chromium_zlib_src_SOURCE_DIR}/contrib/optimizations/insert_string.h" - "${chromium_zlib_src_SOURCE_DIR}/cpu_features.c" - "${chromium_zlib_src_SOURCE_DIR}/cpu_features.h" - "${chromium_zlib_src_SOURCE_DIR}/crc32.c" - "${chromium_zlib_src_SOURCE_DIR}/crc32.h" - "${chromium_zlib_src_SOURCE_DIR}/deflate.c" - "${chromium_zlib_src_SOURCE_DIR}/deflate.h" - "${chromium_zlib_src_SOURCE_DIR}/gzclose.c" - "${chromium_zlib_src_SOURCE_DIR}/gzguts.h" - "${chromium_zlib_src_SOURCE_DIR}/gzlib.c" - "${chromium_zlib_src_SOURCE_DIR}/gzread.c" - "${chromium_zlib_src_SOURCE_DIR}/gzwrite.c" - "${chromium_zlib_src_SOURCE_DIR}/infback.c" - "${chromium_zlib_src_SOURCE_DIR}/inffast.c" - "${chromium_zlib_src_SOURCE_DIR}/inffast.h" - "${chromium_zlib_src_SOURCE_DIR}/inffixed.h" - "${chromium_zlib_src_SOURCE_DIR}/inflate.h" - "${chromium_zlib_src_SOURCE_DIR}/inftrees.c" - "${chromium_zlib_src_SOURCE_DIR}/inftrees.h" - "${chromium_zlib_src_SOURCE_DIR}/trees.c" - "${chromium_zlib_src_SOURCE_DIR}/trees.h" - "${chromium_zlib_src_SOURCE_DIR}/uncompr.c" - "${chromium_zlib_src_SOURCE_DIR}/zconf.h" - "${chromium_zlib_src_SOURCE_DIR}/zlib.h" - "${chromium_zlib_src_SOURCE_DIR}/zutil.c" - "${chromium_zlib_src_SOURCE_DIR}/zutil.h" -) - -# x86_64-specific optimizations -string(APPEND CMAKE_C_FLAGS " -mssse3 -msse4.2 -mpclmul") -add_definitions( - -DCHROMIUM_ZLIB_NO_CHROMECONF - -DX86_NOT_WINDOWS - -DADLER32_SIMD_SSSE3 - -DCRC32_SIMD_SSE42_PCLMUL - -DDEFLATE_FILL_WINDOW_SSE2 - -DINFLATE_CHUNK_READ_64LE - -DINFLATE_CHUNK_SIMD_SSE2 -) -list(APPEND SRC_ZLIB - "${chromium_zlib_src_SOURCE_DIR}/adler32_simd.c" - "${chromium_zlib_src_SOURCE_DIR}/adler32_simd.h" - "${chromium_zlib_src_SOURCE_DIR}/contrib/optimizations/chunkcopy.h" - "${chromium_zlib_src_SOURCE_DIR}/contrib/optimizations/inffast_chunk.c" - "${chromium_zlib_src_SOURCE_DIR}/contrib/optimizations/inffast_chunk.h" - "${chromium_zlib_src_SOURCE_DIR}/contrib/optimizations/inflate.c" - "${chromium_zlib_src_SOURCE_DIR}/crc32_simd.c" - "${chromium_zlib_src_SOURCE_DIR}/crc32_simd.h" - "${chromium_zlib_src_SOURCE_DIR}/crc_folding.c" - "${chromium_zlib_src_SOURCE_DIR}/fill_window_sse.c" -) - -list(SORT SRC_ZLIB) -include_directories("${chromium_zlib_src_SOURCE_DIR}") -add_library(chromium_zlib OBJECT ${SRC_ZLIB}) From 4802272f6801c74f03f0ae3f1ab1b4b946c34b5c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jan 2025 21:13:50 +0000 Subject: [PATCH 785/816] cmake: remove "embedded libssh2" Compiling libssh2 into libgit2 directly is madness. If users want to create a single library that contains libssh2, then they should link a static library. --- CMakeLists.txt | 4 ---- cmake/SelectSSH.cmake | 9 --------- 2 files changed, 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e884db5034..335901d1fb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,10 +74,6 @@ if(MSVC) # This option must match the settings used in your program, in particular if you # are linking statically option(STATIC_CRT "Link the static CRT libraries" ON) - - # If you want to embed a copy of libssh2 into libgit2, pass a - # path to libssh2 - option(EMBED_SSH_PATH "Path to libssh2 to embed (Windows)" OFF) endif() if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) diff --git a/cmake/SelectSSH.cmake b/cmake/SelectSSH.cmake index b0d747114da..35dfc901f47 100644 --- a/cmake/SelectSSH.cmake +++ b/cmake/SelectSSH.cmake @@ -27,15 +27,6 @@ elseif(USE_SSH STREQUAL ON OR USE_SSH STREQUAL "libssh2") set(GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1) endif() - if(WIN32 AND EMBED_SSH_PATH) - file(GLOB SSH_SRC "${EMBED_SSH_PATH}/src/*.c") - list(SORT SSH_SRC) - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS ${SSH_SRC}) - - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${EMBED_SSH_PATH}/include") - file(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"") - endif() - set(GIT_SSH 1) set(GIT_SSH_LIBSSH2 1) add_feature_info(SSH ON "using libssh2") From 2d5942571c9056213e1e370be5e8d6b24fe8b148 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 3 Jan 2025 09:21:16 +0000 Subject: [PATCH 786/816] object: introduce `type_is_valid` There's no such thing as a "loose object type" or a "packed object type". There are only object types. Introduce `type_is_valid` and deprecate `typeisloose`. --- include/git2/deprecated.h | 10 +++++++++ include/git2/object.h | 7 +++---- src/libgit2/object.c | 20 +++++++++--------- src/libgit2/odb.c | 4 ++-- src/libgit2/odb_loose.c | 10 ++++----- tests/libgit2/object/raw/type2string.c | 28 +++++++++++++------------- 6 files changed, 44 insertions(+), 35 deletions(-) diff --git a/include/git2/deprecated.h b/include/git2/deprecated.h index d10143a5cbb..994503c7da7 100644 --- a/include/git2/deprecated.h +++ b/include/git2/deprecated.h @@ -665,6 +665,16 @@ GIT_EXTERN(int) git_index_add_frombuffer( */ GIT_EXTERN(size_t) git_object__size(git_object_t type); +/** + * Determine if the given git_object_t is a valid object type. + * + * @deprecated use `git_object_type_is_valid` + * + * @param type object type to test. + * @return 1 if the type represents a valid object type, 0 otherwise + */ +GIT_EXTERN(int) git_object_typeisloose(git_object_t type); + /**@}*/ /** @name Deprecated Remote Functions diff --git a/include/git2/object.h b/include/git2/object.h index 8a50239fe8d..f923f81edfb 100644 --- a/include/git2/object.h +++ b/include/git2/object.h @@ -180,13 +180,12 @@ GIT_EXTERN(const char *) git_object_type2string(git_object_t type); GIT_EXTERN(git_object_t) git_object_string2type(const char *str); /** - * Determine if the given git_object_t is a valid loose object type. + * Determine if the given git_object_t is a valid object type. * * @param type object type to test. - * @return true if the type represents a valid loose object type, - * false otherwise. + * @return 1 if the type represents a valid loose object type, 0 otherwise */ -GIT_EXTERN(int) git_object_typeisloose(git_object_t type); +GIT_EXTERN(int) git_object_type_is_valid(git_object_t type); /** * Recursively peel an object until an object of the specified type is met. diff --git a/src/libgit2/object.c b/src/libgit2/object.c index 1fff9de2917..f20dbb6cf36 100644 --- a/src/libgit2/object.c +++ b/src/libgit2/object.c @@ -33,7 +33,7 @@ typedef struct { } git_object_def; static git_object_def git_objects_table[] = { - /* 0 = GIT_OBJECT__EXT1 */ + /* 0 = unused */ { "", 0, NULL, NULL, NULL }, /* 1 = GIT_OBJECT_COMMIT */ @@ -46,14 +46,7 @@ static git_object_def git_objects_table[] = { { "blob", sizeof(git_blob), git_blob__parse, git_blob__parse_raw, git_blob__free }, /* 4 = GIT_OBJECT_TAG */ - { "tag", sizeof(git_tag), git_tag__parse, git_tag__parse_raw, git_tag__free }, - - /* 5 = GIT_OBJECT__EXT2 */ - { "", 0, NULL, NULL, NULL }, - /* 6 = GIT_OBJECT_OFS_DELTA */ - { "OFS_DELTA", 0, NULL, NULL, NULL }, - /* 7 = GIT_OBJECT_REF_DELTA */ - { "REF_DELTA", 0, NULL, NULL, NULL }, + { "tag", sizeof(git_tag), git_tag__parse, git_tag__parse_raw, git_tag__free } }; int git_object__from_raw( @@ -342,7 +335,7 @@ git_object_t git_object_stringn2type(const char *str, size_t len) return GIT_OBJECT_INVALID; } -int git_object_typeisloose(git_object_t type) +int git_object_type_is_valid(git_object_t type) { if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) return 0; @@ -350,6 +343,13 @@ int git_object_typeisloose(git_object_t type) return (git_objects_table[type].size > 0) ? 1 : 0; } +#ifndef GIT_DEPRECATE_HARD +int git_object_typeisloose(git_object_t type) +{ + return git_object_type_is_valid(type); +} +#endif + size_t git_object__size(git_object_t type) { if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 5678524c4d0..6ed072b354d 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -116,7 +116,7 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj, git_oid_t oid_type) GIT_ASSERT_ARG(id); GIT_ASSERT_ARG(obj); - if (!git_object_typeisloose(obj->type)) { + if (!git_object_type_is_valid(obj->type)) { git_error_set(GIT_ERROR_INVALID, "invalid object type"); return -1; } @@ -219,7 +219,7 @@ int git_odb__hashfd( ssize_t read_len = 0; int error = 0; - if (!git_object_typeisloose(object_type)) { + if (!git_object_type_is_valid(object_type)) { git_error_set(GIT_ERROR_INVALID, "invalid object type for hash"); return -1; } diff --git a/src/libgit2/odb_loose.c b/src/libgit2/odb_loose.c index c772511a6ea..a91e296ae67 100644 --- a/src/libgit2/odb_loose.c +++ b/src/libgit2/odb_loose.c @@ -243,7 +243,7 @@ static int read_loose_packlike(git_rawobj *out, git_str *obj) if ((error = parse_header_packlike(&hdr, &head_len, obj_data, obj_len)) < 0) goto done; - if (!git_object_typeisloose(hdr.type) || head_len > obj_len) { + if (!git_object_type_is_valid(hdr.type) || head_len > obj_len) { git_error_set(GIT_ERROR_ODB, "failed to inflate loose object"); error = -1; goto done; @@ -296,7 +296,7 @@ static int read_loose_standard(git_rawobj *out, git_str *obj) (error = parse_header(&hdr, &head_len, head, decompressed)) < 0) goto done; - if (!git_object_typeisloose(hdr.type)) { + if (!git_object_type_is_valid(hdr.type)) { git_error_set(GIT_ERROR_ODB, "failed to inflate disk object"); error = -1; goto done; @@ -436,7 +436,7 @@ static int read_header_loose(git_rawobj *out, git_str *loc) else error = read_header_loose_standard(out, obj, (size_t)obj_len); - if (!error && !git_object_typeisloose(out->type)) { + if (!error && !git_object_type_is_valid(out->type)) { git_error_set(GIT_ERROR_ZLIB, "failed to read loose object header"); error = -1; goto done; @@ -954,7 +954,7 @@ static int loose_backend__readstream_packlike( if ((error = parse_header_packlike(hdr, &head_len, data, data_len)) < 0) return error; - if (!git_object_typeisloose(hdr->type)) { + if (!git_object_type_is_valid(hdr->type)) { git_error_set(GIT_ERROR_ODB, "failed to inflate loose object"); return -1; } @@ -986,7 +986,7 @@ static int loose_backend__readstream_standard( (error = parse_header(hdr, &head_len, head, init)) < 0) return error; - if (!git_object_typeisloose(hdr->type)) { + if (!git_object_type_is_valid(hdr->type)) { git_error_set(GIT_ERROR_ODB, "failed to inflate disk object"); return -1; } diff --git a/tests/libgit2/object/raw/type2string.c b/tests/libgit2/object/raw/type2string.c index ebd81f552ae..6f0b4760303 100644 --- a/tests/libgit2/object/raw/type2string.c +++ b/tests/libgit2/object/raw/type2string.c @@ -36,19 +36,19 @@ void test_object_raw_type2string__convert_string_to_type(void) cl_assert(git_object_string2type("hohoho") == GIT_OBJECT_INVALID); } -void test_object_raw_type2string__check_type_is_loose(void) +void test_object_raw_type2string__check_type_is_valid(void) { - cl_assert(git_object_typeisloose(GIT_OBJECT_INVALID) == 0); - cl_assert(git_object_typeisloose(0) == 0); /* EXT1 */ - cl_assert(git_object_typeisloose(GIT_OBJECT_COMMIT) == 1); - cl_assert(git_object_typeisloose(GIT_OBJECT_TREE) == 1); - cl_assert(git_object_typeisloose(GIT_OBJECT_BLOB) == 1); - cl_assert(git_object_typeisloose(GIT_OBJECT_TAG) == 1); - cl_assert(git_object_typeisloose(5) == 0); /* EXT2 */ - cl_assert(git_object_typeisloose(GIT_OBJECT_OFS_DELTA) == 0); - cl_assert(git_object_typeisloose(GIT_OBJECT_REF_DELTA) == 0); - - cl_assert(git_object_typeisloose(-2) == 0); - cl_assert(git_object_typeisloose(8) == 0); - cl_assert(git_object_typeisloose(1234) == 0); + cl_assert(git_object_type_is_valid(GIT_OBJECT_INVALID) == 0); + cl_assert(git_object_type_is_valid(0) == 0); /* EXT1 */ + cl_assert(git_object_type_is_valid(GIT_OBJECT_COMMIT) == 1); + cl_assert(git_object_type_is_valid(GIT_OBJECT_TREE) == 1); + cl_assert(git_object_type_is_valid(GIT_OBJECT_BLOB) == 1); + cl_assert(git_object_type_is_valid(GIT_OBJECT_TAG) == 1); + cl_assert(git_object_type_is_valid(5) == 0); /* EXT2 */ + cl_assert(git_object_type_is_valid(GIT_OBJECT_OFS_DELTA) == 0); + cl_assert(git_object_type_is_valid(GIT_OBJECT_REF_DELTA) == 0); + + cl_assert(git_object_type_is_valid(-2) == 0); + cl_assert(git_object_type_is_valid(8) == 0); + cl_assert(git_object_type_is_valid(1234) == 0); } From 23da3a8f3cc5594eae075f4fcf0d61f827236e7e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 3 Jan 2025 09:43:32 +0000 Subject: [PATCH 787/816] object: remove OFS_DELTA and REF_DELTA values Deltas are not objects, they're entries in a packfile. Remove them from the object enum. --- include/git2/types.h | 4 +--- src/libgit2/indexer.c | 8 ++++---- src/libgit2/pack-objects.c | 4 ++-- src/libgit2/pack.c | 20 ++++++++++---------- src/libgit2/pack.h | 4 ++++ tests/libgit2/object/raw/hash.c | 8 ++++---- tests/libgit2/object/raw/type2string.c | 20 ++++++++++---------- tests/libgit2/repo/hashfile.c | 2 +- 8 files changed, 36 insertions(+), 34 deletions(-) diff --git a/include/git2/types.h b/include/git2/types.h index a4afd18c3bc..fdccd9646d7 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -76,9 +76,7 @@ typedef enum { GIT_OBJECT_COMMIT = 1, /**< A commit object. */ GIT_OBJECT_TREE = 2, /**< A tree (directory listing) object. */ GIT_OBJECT_BLOB = 3, /**< A file revision object. */ - GIT_OBJECT_TAG = 4, /**< An annotated tag object. */ - GIT_OBJECT_OFS_DELTA = 6, /**< A delta, base is given by an offset. */ - GIT_OBJECT_REF_DELTA = 7 /**< A delta, base is given by object id. */ + GIT_OBJECT_TAG = 4 /**< An annotated tag object. */ } git_object_t; /** diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index f1c85cb88bf..cdd2b243134 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -319,9 +319,9 @@ static int advance_delta_offset(git_indexer *idx, git_object_t type) { git_mwindow *w = NULL; - GIT_ASSERT_ARG(type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA); + GIT_ASSERT_ARG(type == GIT_PACKFILE_REF_DELTA || type == GIT_PACKFILE_OFS_DELTA); - if (type == GIT_OBJECT_REF_DELTA) { + if (type == GIT_PACKFILE_REF_DELTA) { idx->off += git_oid_size(idx->oid_type); } else { off64_t base_off; @@ -813,7 +813,7 @@ static int read_stream_object(git_indexer *idx, git_indexer_progress *stats) git_hash_init(&idx->hash_ctx); git_str_clear(&idx->entry_data); - if (type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA) { + if (type == GIT_PACKFILE_REF_DELTA || type == GIT_PACKFILE_OFS_DELTA) { error = advance_delta_offset(idx, type); if (error == GIT_EBUFS) { idx->off = entry_start; @@ -1094,7 +1094,7 @@ static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats) if (error < 0) return error; - if (type == GIT_OBJECT_REF_DELTA) { + if (type == GIT_PACKFILE_REF_DELTA) { found_ref_delta = 1; break; } diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index ced98e8c86d..efdd68aea0c 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -338,7 +338,7 @@ static int write_object( goto done; data_len = po->delta_size; - type = GIT_OBJECT_REF_DELTA; + type = GIT_PACKFILE_REF_DELTA; } else { if ((error = git_odb_read(&obj, pb->odb, &po->id)) < 0) goto done; @@ -354,7 +354,7 @@ static int write_object( (error = git_hash_update(&pb->ctx, hdr, hdr_len)) < 0) goto done; - if (type == GIT_OBJECT_REF_DELTA) { + if (type == GIT_PACKFILE_REF_DELTA) { if ((error = write_cb(po->delta->id.id, oid_size, cb_data)) < 0 || (error = git_hash_update(&pb->ctx, po->delta->id.id, oid_size)) < 0) goto done; diff --git a/src/libgit2/pack.c b/src/libgit2/pack.c index cf63b204e31..a70975a75bf 100644 --- a/src/libgit2/pack.c +++ b/src/libgit2/pack.c @@ -390,7 +390,7 @@ int git_packfile__object_header(size_t *out, unsigned char *hdr, size_t size, gi unsigned char *hdr_base; unsigned char c; - GIT_ASSERT_ARG(type >= GIT_OBJECT_COMMIT && type <= GIT_OBJECT_REF_DELTA); + GIT_ASSERT_ARG(type >= GIT_OBJECT_COMMIT && type <= GIT_PACKFILE_REF_DELTA); /* TODO: add support for chunked objects; see git.git 6c0d19b1 */ @@ -532,7 +532,7 @@ int git_packfile_resolve_header( if (error < 0) return error; - if (type == GIT_OBJECT_OFS_DELTA || type == GIT_OBJECT_REF_DELTA) { + if (type == GIT_PACKFILE_OFS_DELTA || type == GIT_PACKFILE_REF_DELTA) { size_t base_size; git_packfile_stream stream; @@ -553,12 +553,12 @@ int git_packfile_resolve_header( base_offset = 0; } - while (type == GIT_OBJECT_OFS_DELTA || type == GIT_OBJECT_REF_DELTA) { + while (type == GIT_PACKFILE_OFS_DELTA || type == GIT_PACKFILE_REF_DELTA) { curpos = base_offset; error = git_packfile_unpack_header(&size, &type, p, &w_curs, &curpos); if (error < 0) return error; - if (type != GIT_OBJECT_OFS_DELTA && type != GIT_OBJECT_REF_DELTA) + if (type != GIT_PACKFILE_OFS_DELTA && type != GIT_PACKFILE_REF_DELTA) break; error = get_delta_base(&base_offset, p, &w_curs, &curpos, type, base_offset); @@ -635,7 +635,7 @@ static int pack_dependency_chain(git_dependency_chain *chain_out, elem->type = type; elem->base_key = obj_offset; - if (type != GIT_OBJECT_OFS_DELTA && type != GIT_OBJECT_REF_DELTA) + if (type != GIT_PACKFILE_OFS_DELTA && type != GIT_PACKFILE_REF_DELTA) break; error = get_delta_base(&base_offset, p, &w_curs, &curpos, type, obj_offset); @@ -675,7 +675,7 @@ int git_packfile_unpack( git_pack_cache_entry *cached = NULL; struct pack_chain_elem small_stack[SMALL_STACK_SIZE]; size_t stack_size = 0, elem_pos, alloclen; - git_object_t base_type; + int base_type; error = git_mutex_lock(&p->lock); if (error < 0) { @@ -735,8 +735,8 @@ int git_packfile_unpack( if (error < 0) goto cleanup; break; - case GIT_OBJECT_OFS_DELTA: - case GIT_OBJECT_REF_DELTA: + case GIT_PACKFILE_OFS_DELTA: + case GIT_PACKFILE_REF_DELTA: error = packfile_error("dependency chain ends in a delta"); goto cleanup; default: @@ -983,7 +983,7 @@ int get_delta_base( * than the hash size is stupid, as then a REF_DELTA would be * smaller to store. */ - if (type == GIT_OBJECT_OFS_DELTA) { + if (type == GIT_PACKFILE_OFS_DELTA) { unsigned used = 0; unsigned char c = base_info[used++]; size_t unsigned_base_offset = c & 127; @@ -1000,7 +1000,7 @@ int get_delta_base( return packfile_error("out of bounds"); base_offset = delta_obj_offset - unsigned_base_offset; *curpos += used; - } else if (type == GIT_OBJECT_REF_DELTA) { + } else if (type == GIT_PACKFILE_REF_DELTA) { git_oid base_oid; git_oid_from_raw(&base_oid, base_info, p->oid_type); diff --git a/src/libgit2/pack.h b/src/libgit2/pack.h index 4fd092149b3..e802d60747c 100644 --- a/src/libgit2/pack.h +++ b/src/libgit2/pack.h @@ -33,6 +33,10 @@ typedef int git_pack_foreach_entry_offset_cb( #define PACK_SIGNATURE 0x5041434b /* "PACK" */ #define PACK_VERSION 2 #define pack_version_ok(v) ((v) == htonl(2)) + +#define GIT_PACKFILE_OFS_DELTA 6 +#define GIT_PACKFILE_REF_DELTA 7 + struct git_pack_header { uint32_t hdr_signature; uint32_t hdr_version; diff --git a/tests/libgit2/object/raw/hash.c b/tests/libgit2/object/raw/hash.c index 3bfaddaa23c..914096f6a5e 100644 --- a/tests/libgit2/object/raw/hash.c +++ b/tests/libgit2/object/raw/hash.c @@ -87,16 +87,16 @@ void test_object_raw_hash__hash_junk_data(void) junk_obj.data = some_data; hash_object_fail(&id, &junk_obj); - junk_obj.type = 0; /* EXT1 */ + junk_obj.type = 0; /* unused */ hash_object_fail(&id, &junk_obj); - junk_obj.type = 5; /* EXT2 */ + junk_obj.type = 5; /* unused */ hash_object_fail(&id, &junk_obj); - junk_obj.type = GIT_OBJECT_OFS_DELTA; + junk_obj.type = 6; /* packfile offset delta */ hash_object_fail(&id, &junk_obj); - junk_obj.type = GIT_OBJECT_REF_DELTA; + junk_obj.type = 7; /* packfile ref delta */ hash_object_fail(&id, &junk_obj); junk_obj.type = 42; diff --git a/tests/libgit2/object/raw/type2string.c b/tests/libgit2/object/raw/type2string.c index 6f0b4760303..e3a0764e55a 100644 --- a/tests/libgit2/object/raw/type2string.c +++ b/tests/libgit2/object/raw/type2string.c @@ -7,14 +7,14 @@ void test_object_raw_type2string__convert_type_to_string(void) { cl_assert_equal_s(git_object_type2string(GIT_OBJECT_INVALID), ""); - cl_assert_equal_s(git_object_type2string(0), ""); /* EXT1 */ + cl_assert_equal_s(git_object_type2string(0), ""); /* unused */ cl_assert_equal_s(git_object_type2string(GIT_OBJECT_COMMIT), "commit"); cl_assert_equal_s(git_object_type2string(GIT_OBJECT_TREE), "tree"); cl_assert_equal_s(git_object_type2string(GIT_OBJECT_BLOB), "blob"); cl_assert_equal_s(git_object_type2string(GIT_OBJECT_TAG), "tag"); - cl_assert_equal_s(git_object_type2string(5), ""); /* EXT2 */ - cl_assert_equal_s(git_object_type2string(GIT_OBJECT_OFS_DELTA), "OFS_DELTA"); - cl_assert_equal_s(git_object_type2string(GIT_OBJECT_REF_DELTA), "REF_DELTA"); + cl_assert_equal_s(git_object_type2string(5), ""); /* unused */ + cl_assert_equal_s(git_object_type2string(6), ""); /* packfile offset delta */ + cl_assert_equal_s(git_object_type2string(7), ""); /* packfile ref delta */ cl_assert_equal_s(git_object_type2string(-2), ""); cl_assert_equal_s(git_object_type2string(8), ""); @@ -29,8 +29,8 @@ void test_object_raw_type2string__convert_string_to_type(void) cl_assert(git_object_string2type("tree") == GIT_OBJECT_TREE); cl_assert(git_object_string2type("blob") == GIT_OBJECT_BLOB); cl_assert(git_object_string2type("tag") == GIT_OBJECT_TAG); - cl_assert(git_object_string2type("OFS_DELTA") == GIT_OBJECT_OFS_DELTA); - cl_assert(git_object_string2type("REF_DELTA") == GIT_OBJECT_REF_DELTA); + cl_assert(git_object_string2type("OFS_DELTA") == GIT_OBJECT_INVALID); + cl_assert(git_object_string2type("REF_DELTA") == GIT_OBJECT_INVALID); cl_assert(git_object_string2type("CoMmIt") == GIT_OBJECT_INVALID); cl_assert(git_object_string2type("hohoho") == GIT_OBJECT_INVALID); @@ -39,14 +39,14 @@ void test_object_raw_type2string__convert_string_to_type(void) void test_object_raw_type2string__check_type_is_valid(void) { cl_assert(git_object_type_is_valid(GIT_OBJECT_INVALID) == 0); - cl_assert(git_object_type_is_valid(0) == 0); /* EXT1 */ + cl_assert(git_object_type_is_valid(0) == 0); /* unused */ cl_assert(git_object_type_is_valid(GIT_OBJECT_COMMIT) == 1); cl_assert(git_object_type_is_valid(GIT_OBJECT_TREE) == 1); cl_assert(git_object_type_is_valid(GIT_OBJECT_BLOB) == 1); cl_assert(git_object_type_is_valid(GIT_OBJECT_TAG) == 1); - cl_assert(git_object_type_is_valid(5) == 0); /* EXT2 */ - cl_assert(git_object_type_is_valid(GIT_OBJECT_OFS_DELTA) == 0); - cl_assert(git_object_type_is_valid(GIT_OBJECT_REF_DELTA) == 0); + cl_assert(git_object_type_is_valid(5) == 0); /* unused */ + cl_assert(git_object_type_is_valid(6) == 0); /* packfile offset delta */ + cl_assert(git_object_type_is_valid(7) == 0); /* packfile ref delta */ cl_assert(git_object_type_is_valid(-2) == 0); cl_assert(git_object_type_is_valid(8) == 0); diff --git a/tests/libgit2/repo/hashfile.c b/tests/libgit2/repo/hashfile.c index f053cb950d4..64b8dfa460c 100644 --- a/tests/libgit2/repo/hashfile.c +++ b/tests/libgit2/repo/hashfile.c @@ -34,7 +34,7 @@ void test_repo_hashfile__simple(void) /* hash with invalid type */ cl_git_fail(git_odb__hashfile(&a, full.ptr, GIT_OBJECT_ANY, GIT_OID_SHA1)); - cl_git_fail(git_repository_hashfile(&b, _repo, full.ptr, GIT_OBJECT_OFS_DELTA, NULL)); + cl_git_fail(git_repository_hashfile(&b, _repo, full.ptr, 6, NULL)); git_str_dispose(&full); } From 904c8f266db7cecfc4601ef05a31853c3c39f6ef Mon Sep 17 00:00:00 2001 From: Alexander Kanavin Date: Tue, 7 Jan 2025 18:56:19 +0100 Subject: [PATCH 788/816] src/libgit2/CMakeLists.txt: install cmake files into configured libdir libdir can be something else than /usr/lib, e.g. /usr/lib64 or similar. --- src/libgit2/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libgit2/CMakeLists.txt b/src/libgit2/CMakeLists.txt index a7d3c7ca400..16b3a23d9a8 100644 --- a/src/libgit2/CMakeLists.txt +++ b/src/libgit2/CMakeLists.txt @@ -119,11 +119,11 @@ configure_file(config.cmake.in install(FILES "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake" "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION "lib/cmake/${PROJECT_NAME}") + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") install( EXPORT ${LIBGIT2_TARGETS_EXPORT_NAME} NAMESPACE "${PROJECT_NAME}::" - DESTINATION "lib/cmake/${PROJECT_NAME}") + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") # Install From 1c6d51142d6873546f309c1362a1b6cddfd54147 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 7 Jan 2025 20:29:44 +0000 Subject: [PATCH 789/816] docs: add `update_refs` as ABI breaking change In v1.9, we failed to document that `update_refs` was a breaking change. Add information about this change to the ABI breaking changes section. --- docs/changelog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 9824d994bc7..591e515113a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -71,6 +71,13 @@ maintainers of bindings or FFI users, may want to be aware of. to provide a mechanism to nicely free the configuration entries that they provide. +* **`update_refs` callback for remotes** (ABI breaking change) + The `update_refs` callback was added to the `git_remote_callbacks` + structure to provide additional information about updated refs; + in particular, the `git_refspec` is included for more information + about the remote ref. The `update_refs` callback will be + preferred over the now deprecated `update_tips` callback. + ## What's Changed ### New features From 436f4e7d96f94caf7e4cc8103775f3d16fa35569 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 9 Jan 2025 21:45:11 +0000 Subject: [PATCH 790/816] benchmarks: update path to baseline cli The `fullpath` function takes the cli, but doesn't keep the cli. --- tests/benchmarks/benchmark.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/benchmarks/benchmark.sh b/tests/benchmarks/benchmark.sh index 6830064e776..944f26bc52a 100755 --- a/tests/benchmarks/benchmark.sh +++ b/tests/benchmarks/benchmark.sh @@ -100,11 +100,11 @@ SYSTEM_KERNEL=$(uname -v) fullpath() { if [[ "$(uname -s)" == "MINGW"* && $(cygpath -u "${TEST_CLI}") == "/"* ]]; then - echo "${TEST_CLI}" + echo "$1" elif [[ "${TEST_CLI}" == "/"* ]]; then - echo "${TEST_CLI}" + echo "$1" else - which "${TEST_CLI}" + which "$1" fi } From 343c2cbae87f119eaac5fc9d49699ad07f06e473 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 9 Jan 2025 23:44:23 +0000 Subject: [PATCH 791/816] benchmarks: report commit of build It can be useful to report the commit ID during benchmarks to track down regressions; leverage the addition of that in `git version` during benchmark runs. --- tests/benchmarks/benchmark.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/benchmarks/benchmark.sh b/tests/benchmarks/benchmark.sh index 944f26bc52a..2c18e50cef6 100755 --- a/tests/benchmarks/benchmark.sh +++ b/tests/benchmarks/benchmark.sh @@ -116,9 +116,20 @@ cli_version() { fi } +cli_commit() { + if [[ "$(uname -s)" == "MINGW"* ]]; then + BUILD_OPTIONS=$($(cygpath -u "$1") version --build-options) + else + BUILD_OPTIONS=$("$1" version --build-options) + fi + + echo "${BUILD_OPTIONS}" | grep '^built from commit: ' | sed -e 's/^built from commit: //' +} + TEST_CLI_NAME=$(basename "${TEST_CLI}") TEST_CLI_PATH=$(fullpath "${TEST_CLI}") TEST_CLI_VERSION=$(cli_version "${TEST_CLI}") +TEST_CLI_COMMIT=$(cli_commit "${TEST_CLI}") if [ "${BASELINE_CLI}" != "" ]; then if [[ "${BASELINE_CLI}" == "/"* ]]; then @@ -130,6 +141,7 @@ if [ "${BASELINE_CLI}" != "" ]; then BASELINE_CLI_NAME=$(basename "${BASELINE_CLI}") BASELINE_CLI_PATH=$(fullpath "${BASELINE_CLI}") BASELINE_CLI_VERSION=$(cli_version "${BASELINE_CLI}") + BASELINE_CLI_COMMIT=$(cli_commit "${BASELINE_CLI}") fi # @@ -281,8 +293,8 @@ if [ "${JSON_RESULT}" != "" ]; then SYSTEM_JSON="{ \"os\": \"${SYSTEM_OS}\", \"kernel\": \"${SYSTEM_KERNEL}\" }" TIME_JSON="{ \"start\": ${TIME_START}, \"end\": ${TIME_END} }" - TEST_CLI_JSON="{ \"name\": \"${TEST_CLI_NAME}\", \"path\": \"$(escape "${TEST_CLI_PATH}")\", \"version\": \"${TEST_CLI_VERSION}\" }" - BASELINE_CLI_JSON="{ \"name\": \"${BASELINE_CLI_NAME}\", \"path\": \"$(escape "${BASELINE_CLI_PATH}")\", \"version\": \"${BASELINE_CLI_VERSION}\" }" + TEST_CLI_JSON="{ \"name\": \"${TEST_CLI_NAME}\", \"path\": \"$(escape "${TEST_CLI_PATH}")\", \"version\": \"${TEST_CLI_VERSION}\", \"commit\": \"${TEST_CLI_COMMIT}\" }" + BASELINE_CLI_JSON="{ \"name\": \"${BASELINE_CLI_NAME}\", \"path\": \"$(escape "${BASELINE_CLI_PATH}")\", \"version\": \"${BASELINE_CLI_VERSION}\", \"commit\": \"${BASELINE_CLI_COMMIT}\" }" if [ "${BASELINE_CLI}" != "" ]; then EXECUTOR_JSON="{ \"baseline\": ${BASELINE_CLI_JSON}, \"cli\": ${TEST_CLI_JSON} }" From 6fedfd3237f4e9066bdb64f38b8366b40298d476 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 29 Oct 2024 15:23:39 -0400 Subject: [PATCH 792/816] Add benchmark for large-ish (250mb) index-pack --- .github/workflows/benchmark.yml | 14 ++++-- tests/benchmarks/benchmark_helpers.sh | 65 ++++++++++++++++++++++++--- tests/benchmarks/indexpack__250mb | 11 +++++ 3 files changed, 80 insertions(+), 10 deletions(-) create mode 100755 tests/benchmarks/indexpack__250mb diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 3fb912d40d0..8299c3e56e3 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -70,9 +70,14 @@ jobs: if: matrix.platform.setup-script != '' - name: Clone resource repositories run: | - mkdir resources + # we need a superior way to package the benchmark resources; lfs + # is too expensive + # git lfs install + # git clone https://github.com/libgit2/benchmark-resources resources git clone --bare https://github.com/git/git resources/git - git clone --bare https://github.com/torvalds/linux resources/linux + # avoid linux temporarily; the linux blame benchmarks are simply + # too slow to use + # git clone --bare https://github.com/torvalds/linux resources/linux - name: Build run: | mkdir build && cd build @@ -80,10 +85,11 @@ jobs: shell: bash - name: Benchmark run: | - export BENCHMARK_GIT_REPOSITORY="$(pwd)/resources/git" + export BENCHMARK_RESOURCES_PATH="$(pwd)/resources" + export BENCHMARK_GIT_PATH="$(pwd)/resources/git" # avoid linux temporarily; the linux blame benchmarks are simply # too slow to use - # export BENCHMARK_LINUX_REPOSITORY="$(pwd)/resources/linux" + # export BENCHMARK_LINUX_PATH="$(pwd)/resources/linux" if [[ "$(uname -s)" == MINGW* ]]; then GIT2_CLI="$(cygpath -w $(pwd))\\build\\Release\\git2" diff --git a/tests/benchmarks/benchmark_helpers.sh b/tests/benchmarks/benchmark_helpers.sh index 5143a01fcfd..0ff6b03ef35 100644 --- a/tests/benchmarks/benchmark_helpers.sh +++ b/tests/benchmarks/benchmark_helpers.sh @@ -23,6 +23,7 @@ fi HELP_GIT_REMOTE="https://github.com/git/git" HELP_LINUX_REMOTE="https://github.com/torvalds/linux" +HELP_RESOURCE_REPO="https://github.com/libgit2/benchmark-resources" # # parse the arguments to the outer script that's including us; these are arguments that @@ -205,6 +206,30 @@ create_preparescript() { cp -R "\${RESOURCES_DIR}/\${RESOURCE}" "\${SANDBOX_DIR}/" } + sandbox_resource() { + RESOURCE="\${1}" + + if [ "\${RESOURCE}" = "" ]; then + echo "usage: sandbox_resource " 1>&2 + exit 1 + fi + + RESOURCE_UPPER=\$(echo "\${RESOURCE}" | tr '[:lower:]' '[:upper:]' | sed -e "s/-/_/g") + RESOURCE_PATH=\$(eval echo "\\\${BENCHMARK_\${RESOURCE_UPPER}_PATH}") + + if [ "\${RESOURCE_PATH}" = "" -a "\${BENCHMARK_RESOURCES_PATH}" != "" ]; then + RESOURCE_PATH="\${BENCHMARK_RESOURCES_PATH}/\${RESOURCE}" + fi + + if [ ! -f "\${RESOURCE_PATH}" ]; then + echo "sandbox: the resource \"\${RESOURCE}\" does not exist" + exit 1 + fi + + rm -rf "\${SANDBOX_DIR:?}/\${RESOURCE}" + cp -R "\${RESOURCE_PATH}" "\${SANDBOX_DIR}/\${RESOURCE}" + } + sandbox_repo() { RESOURCE="\${1}" @@ -229,8 +254,8 @@ create_preparescript() { exit 1 fi - REPO_UPPER=\$(echo "\${1}" | tr '[:lower:]' '[:upper:]') - REPO_URL=\$(eval echo "\\\${BENCHMARK_\${REPO_UPPER}_REPOSITORY}") + REPO_UPPER=\$(echo "\${REPO}" | tr '[:lower:]' '[:upper:]') + REPO_URL=\$(eval echo "\\\${BENCHMARK_\${REPO_UPPER}_PATH}") if [ "\${REPO_URL}" = "" ]; then echo "\$0: unknown repository '\${REPO}'" 1>&2 @@ -397,17 +422,45 @@ needs_repo() { exit 1 fi - REPO_UPPER=$(echo "${1}" | tr '[:lower:]' '[:upper:]') - REPO_URL=$(eval echo "\${BENCHMARK_${REPO_UPPER}_REPOSITORY}") + REPO_UPPER=$(echo "${REPO}" | tr '[:lower:]' '[:upper:]') + REPO_PATH=$(eval echo "\${BENCHMARK_${REPO_UPPER}_PATH}") REPO_REMOTE_URL=$(eval echo "\${HELP_${REPO_UPPER}_REMOTE}") - if [ "${REPO_URL}" = "" ]; then + if [ "${REPO_PATH}" = "" ]; then echo "$0: '${REPO}' repository not configured" 1>&2 echo "" 1>&2 echo "This benchmark needs an on-disk '${REPO}' repository. First, clone the" 1>&2 - echo "remote repository ('${REPO_REMOTE_URL}') locally then set," 1>&2 + echo "remote repository ('${REPO_REMOTE_URL}') locally then set" 1>&2 echo "the 'BENCHMARK_${REPO_UPPER}_REPOSITORY' environment variable to the path that" 1>&2 echo "contains the repository locally, then run this benchmark again." 1>&2 exit 2 fi } + +# helper script to give useful error messages about configuration +needs_resource() { + RESOURCE="${1}" + + if [ "${RESOURCE}" = "" ]; then + echo "usage: needs_resource " 1>&2 + exit 1 + fi + + RESOURCE_UPPER=$(echo "${RESOURCE}" | tr '[:lower:]' '[:upper:]' | sed -e "s/-/_/g") + RESOURCE_PATH=$(eval echo "\${BENCHMARK_${RESOURCE_UPPER}_PATH}") + + if [ "${RESOURCE_PATH}" = "" -a "${BENCHMARK_RESOURCES_PATH}" != "" ]; then + RESOURCE_PATH="${BENCHMARK_RESOURCES_PATH}/${RESOURCE}" + fi + + if [ "${RESOURCE_PATH}" = "" ]; then + echo "$0: '${RESOURCE}' resource path not configured" 1>&2 + echo "" 1>&2 + echo "This benchmark needs an on-disk resource named '${RESOURCE}'." 1>&2 + echo "First, clone the additional benchmark resources locally (from" 1>&2 + echo "'${HELP_RESOURCE_REPO}'), then set the" 1>& 2 + echo "'BENCHMARK_RESOURCES_PATH' environment variable to the path that" 1>&2 + echo "contains the resources locally, then run this benchmark again." 1>&2 + exit 2 + fi +} diff --git a/tests/benchmarks/indexpack__250mb b/tests/benchmarks/indexpack__250mb new file mode 100755 index 00000000000..5bd964786ae --- /dev/null +++ b/tests/benchmarks/indexpack__250mb @@ -0,0 +1,11 @@ +#!/bin/bash -e + +. "$(dirname "$0")/benchmark_helpers.sh" + +needs_resource packfile-250mb + +gitbench --prepare "git init --bare dest.git && sandbox_resource packfile-250mb && mv packfile-250mb dest.git/packfile-250mb.pack" \ + --warmup 5 \ + --chdir "dest.git" \ + -- \ + index-pack packfile-250mb.pack From 1d2bdab7f808a3be46ad137187d80af3bb99395e Mon Sep 17 00:00:00 2001 From: Laurence McGlashan Date: Mon, 13 Jan 2025 12:16:44 +0000 Subject: [PATCH 793/816] Update SelectSSH.cmake --- cmake/SelectSSH.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/SelectSSH.cmake b/cmake/SelectSSH.cmake index 35dfc901f47..e655c3eccb4 100644 --- a/cmake/SelectSSH.cmake +++ b/cmake/SelectSSH.cmake @@ -33,5 +33,5 @@ elseif(USE_SSH STREQUAL ON OR USE_SSH STREQUAL "libssh2") elseif(USE_SSH STREQUAL OFF OR USE_SSH STREQUAL "") add_feature_info(SSH OFF "SSH transport support") else() - message(FATAL_ERROR "unknown SSH option: ${USE_HTTP_PARSER}") + message(FATAL_ERROR "unknown SSH option: ${USE_SSH}") endif() From dfbdaa28a545ad2374b9912f462ea9140e42b3f5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 31 Oct 2024 11:47:43 -0400 Subject: [PATCH 794/816] benchmark: introduce profiling support Introduce `--profile` support to the benchmark helper script, which will invoke `perf` on Linux. Additionally, add a `--flamegraph` output option based on that. --- tests/benchmarks/_script/flamegraph/README.md | 226 + .../benchmarks/_script/flamegraph/aix-perf.pl | 31 + .../_script/flamegraph/difffolded.pl | 115 + .../flamegraph/example-dtrace-stacks.txt | 41913 ++++++++++++++++ .../_script/flamegraph/example-dtrace.svg | 1842 + .../flamegraph/example-perf-stacks.txt.gz | Bin 0 -> 110532 bytes .../_script/flamegraph/example-perf.svg | 4895 ++ tests/benchmarks/_script/flamegraph/files.pl | 62 + .../_script/flamegraph/flamegraph.pl | 1303 + tests/benchmarks/_script/flamegraph/jmaps | 104 + .../_script/flamegraph/pkgsplit-perf.pl | 86 + .../_script/flamegraph/range-perf.pl | 137 + .../_script/flamegraph/record-test.sh | 21 + .../_script/flamegraph/stackcollapse-aix.pl | 61 + .../flamegraph/stackcollapse-bpftrace.pl | 72 + .../stackcollapse-chrome-tracing.py | 144 + .../flamegraph/stackcollapse-elfutils.pl | 98 + .../flamegraph/stackcollapse-faulthandler.pl | 61 + .../_script/flamegraph/stackcollapse-gdb.pl | 72 + .../_script/flamegraph/stackcollapse-go.pl | 150 + .../flamegraph/stackcollapse-ibmjava.pl | 145 + .../flamegraph/stackcollapse-instruments.pl | 34 + .../stackcollapse-java-exceptions.pl | 72 + .../flamegraph/stackcollapse-jstack.pl | 176 + .../_script/flamegraph/stackcollapse-ljp.awk | 74 + .../flamegraph/stackcollapse-perf-sched.awk | 228 + .../_script/flamegraph/stackcollapse-perf.pl | 435 + .../_script/flamegraph/stackcollapse-pmc.pl | 74 + .../flamegraph/stackcollapse-recursive.pl | 60 + .../flamegraph/stackcollapse-sample.awk | 231 + .../_script/flamegraph/stackcollapse-stap.pl | 84 + .../flamegraph/stackcollapse-vsprof.pl | 98 + .../flamegraph/stackcollapse-vtune-mc.pl | 103 + .../_script/flamegraph/stackcollapse-vtune.pl | 97 + .../_script/flamegraph/stackcollapse-wcp.pl | 69 + .../flamegraph/stackcollapse-xdebug.php | 197 + .../_script/flamegraph/stackcollapse.pl | 109 + tests/benchmarks/_script/flamegraph/test.sh | 26 + tests/benchmarks/benchmark_helpers.sh | 178 +- 39 files changed, 53845 insertions(+), 38 deletions(-) create mode 100644 tests/benchmarks/_script/flamegraph/README.md create mode 100755 tests/benchmarks/_script/flamegraph/aix-perf.pl create mode 100755 tests/benchmarks/_script/flamegraph/difffolded.pl create mode 100644 tests/benchmarks/_script/flamegraph/example-dtrace-stacks.txt create mode 100644 tests/benchmarks/_script/flamegraph/example-dtrace.svg create mode 100644 tests/benchmarks/_script/flamegraph/example-perf-stacks.txt.gz create mode 100644 tests/benchmarks/_script/flamegraph/example-perf.svg create mode 100755 tests/benchmarks/_script/flamegraph/files.pl create mode 100755 tests/benchmarks/_script/flamegraph/flamegraph.pl create mode 100755 tests/benchmarks/_script/flamegraph/jmaps create mode 100755 tests/benchmarks/_script/flamegraph/pkgsplit-perf.pl create mode 100755 tests/benchmarks/_script/flamegraph/range-perf.pl create mode 100755 tests/benchmarks/_script/flamegraph/record-test.sh create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-aix.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-bpftrace.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-chrome-tracing.py create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-elfutils.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-faulthandler.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-gdb.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-go.pl create mode 100644 tests/benchmarks/_script/flamegraph/stackcollapse-ibmjava.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-instruments.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-java-exceptions.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-jstack.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-ljp.awk create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-perf-sched.awk create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-perf.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-pmc.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-recursive.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-sample.awk create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-stap.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-vsprof.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-vtune-mc.pl create mode 100644 tests/benchmarks/_script/flamegraph/stackcollapse-vtune.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-wcp.pl create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse-xdebug.php create mode 100755 tests/benchmarks/_script/flamegraph/stackcollapse.pl create mode 100755 tests/benchmarks/_script/flamegraph/test.sh diff --git a/tests/benchmarks/_script/flamegraph/README.md b/tests/benchmarks/_script/flamegraph/README.md new file mode 100644 index 00000000000..ee1b3eee429 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/README.md @@ -0,0 +1,226 @@ +# Flame Graphs visualize profiled code + +Main Website: http://www.brendangregg.com/flamegraphs.html + +Example (click to zoom): + +[![Example](http://www.brendangregg.com/FlameGraphs/cpu-bash-flamegraph.svg)](http://www.brendangregg.com/FlameGraphs/cpu-bash-flamegraph.svg) + +Click a box to zoom the Flame Graph to this stack frame only. +To search and highlight all stack frames matching a regular expression, click the _search_ button in the upper right corner or press Ctrl-F. +By default, search is case sensitive, but this can be toggled by pressing Ctrl-I or by clicking the _ic_ button in the upper right corner. + +Other sites: +- The Flame Graph article in ACMQ and CACM: http://queue.acm.org/detail.cfm?id=2927301 http://cacm.acm.org/magazines/2016/6/202665-the-flame-graph/abstract +- CPU profiling using Linux perf\_events, DTrace, SystemTap, or ktap: http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html +- CPU profiling using XCode Instruments: http://schani.wordpress.com/2012/11/16/flame-graphs-for-instruments/ +- CPU profiling using Xperf.exe: http://randomascii.wordpress.com/2013/03/26/summarizing-xperf-cpu-usage-with-flame-graphs/ +- Memory profiling: http://www.brendangregg.com/FlameGraphs/memoryflamegraphs.html +- Other examples, updates, and news: http://www.brendangregg.com/flamegraphs.html#Updates + +Flame graphs can be created in three steps: + +1. Capture stacks +2. Fold stacks +3. flamegraph.pl + +1\. Capture stacks +================= +Stack samples can be captured using Linux perf\_events, FreeBSD pmcstat (hwpmc), DTrace, SystemTap, and many other profilers. See the stackcollapse-\* converters. + +### Linux perf\_events + +Using Linux perf\_events (aka "perf") to capture 60 seconds of 99 Hertz stack samples, both user- and kernel-level stacks, all processes: + +``` +# perf record -F 99 -a -g -- sleep 60 +# perf script > out.perf +``` + +Now only capturing PID 181: + +``` +# perf record -F 99 -p 181 -g -- sleep 60 +# perf script > out.perf +``` + +### DTrace + +Using DTrace to capture 60 seconds of kernel stacks at 997 Hertz: + +``` +# dtrace -x stackframes=100 -n 'profile-997 /arg0/ { @[stack()] = count(); } tick-60s { exit(0); }' -o out.kern_stacks +``` + +Using DTrace to capture 60 seconds of user-level stacks for PID 12345 at 97 Hertz: + +``` +# dtrace -x ustackframes=100 -n 'profile-97 /pid == 12345 && arg1/ { @[ustack()] = count(); } tick-60s { exit(0); }' -o out.user_stacks +``` + +60 seconds of user-level stacks, including time spent in-kernel, for PID 12345 at 97 Hertz: + +``` +# dtrace -x ustackframes=100 -n 'profile-97 /pid == 12345/ { @[ustack()] = count(); } tick-60s { exit(0); }' -o out.user_stacks +``` + +Switch `ustack()` for `jstack()` if the application has a ustack helper to include translated frames (eg, node.js frames; see: http://dtrace.org/blogs/dap/2012/01/05/where-does-your-node-program-spend-its-time/). The rate for user-level stack collection is deliberately slower than kernel, which is especially important when using `jstack()` as it performs additional work to translate frames. + +2\. Fold stacks +============== +Use the stackcollapse programs to fold stack samples into single lines. The programs provided are: + +- `stackcollapse.pl`: for DTrace stacks +- `stackcollapse-perf.pl`: for Linux perf_events "perf script" output +- `stackcollapse-pmc.pl`: for FreeBSD pmcstat -G stacks +- `stackcollapse-stap.pl`: for SystemTap stacks +- `stackcollapse-instruments.pl`: for XCode Instruments +- `stackcollapse-vtune.pl`: for Intel VTune profiles +- `stackcollapse-ljp.awk`: for Lightweight Java Profiler +- `stackcollapse-jstack.pl`: for Java jstack(1) output +- `stackcollapse-gdb.pl`: for gdb(1) stacks +- `stackcollapse-go.pl`: for Golang pprof stacks +- `stackcollapse-vsprof.pl`: for Microsoft Visual Studio profiles +- `stackcollapse-wcp.pl`: for wallClockProfiler output + +Usage example: + +``` +For perf_events: +$ ./stackcollapse-perf.pl out.perf > out.folded + +For DTrace: +$ ./stackcollapse.pl out.kern_stacks > out.kern_folded +``` + +The output looks like this: + +``` +unix`_sys_sysenter_post_swapgs 1401 +unix`_sys_sysenter_post_swapgs;genunix`close 5 +unix`_sys_sysenter_post_swapgs;genunix`close;genunix`closeandsetf 85 +unix`_sys_sysenter_post_swapgs;genunix`close;genunix`closeandsetf;c2audit`audit_closef 26 +unix`_sys_sysenter_post_swapgs;genunix`close;genunix`closeandsetf;c2audit`audit_setf 5 +unix`_sys_sysenter_post_swapgs;genunix`close;genunix`closeandsetf;genunix`audit_getstate 6 +unix`_sys_sysenter_post_swapgs;genunix`close;genunix`closeandsetf;genunix`audit_unfalloc 2 +unix`_sys_sysenter_post_swapgs;genunix`close;genunix`closeandsetf;genunix`closef 48 +[...] +``` + +3\. flamegraph.pl +================ +Use flamegraph.pl to render a SVG. + +``` +$ ./flamegraph.pl out.kern_folded > kernel.svg +``` + +An advantage of having the folded input file (and why this is separate to flamegraph.pl) is that you can use grep for functions of interest. Eg: + +``` +$ grep cpuid out.kern_folded | ./flamegraph.pl > cpuid.svg +``` + +Provided Examples +================= + +### Linux perf\_events + +An example output from Linux "perf script" is included, gzip'd, as example-perf-stacks.txt.gz. The resulting flame graph is example-perf.svg: + +[![Example](http://www.brendangregg.com/FlameGraphs/example-perf.svg)](http://www.brendangregg.com/FlameGraphs/example-perf.svg) + +You can create this using: + +``` +$ gunzip -c example-perf-stacks.txt.gz | ./stackcollapse-perf.pl --all | ./flamegraph.pl --color=java --hash > example-perf.svg +``` + +This shows my typical workflow: I'll gzip profiles on the target, then copy them to my laptop for analysis. Since I have hundreds of profiles, I leave them gzip'd! + +Since this profile included Java, I used the flamegraph.pl --color=java palette. I've also used stackcollapse-perf.pl --all, which includes all annotations that help flamegraph.pl use separate colors for kernel and user level code. The resulting flame graph uses: green == Java, yellow == C++, red == user-mode native, orange == kernel. + +This profile was from an analysis of vert.x performance. The benchmark client, wrk, is also visible in the flame graph. + +### DTrace + +An example output from DTrace is also included, example-dtrace-stacks.txt, and the resulting flame graph, example-dtrace.svg: + +[![Example](http://www.brendangregg.com/FlameGraphs/example-dtrace.svg)](http://www.brendangregg.com/FlameGraphs/example-dtrace.svg) + +You can generate this using: + +``` +$ ./stackcollapse.pl example-stacks.txt | ./flamegraph.pl > example.svg +``` + +This was from a particular performance investigation: the Flame Graph identified that CPU time was spent in the lofs module, and quantified that time. + + +Options +======= +See the USAGE message (--help) for options: + +USAGE: ./flamegraph.pl [options] infile > outfile.svg + + --title TEXT # change title text + --subtitle TEXT # second level title (optional) + --width NUM # width of image (default 1200) + --height NUM # height of each frame (default 16) + --minwidth NUM # omit smaller functions. In pixels or use "%" for + # percentage of time (default 0.1 pixels) + --fonttype FONT # font type (default "Verdana") + --fontsize NUM # font size (default 12) + --countname TEXT # count type label (default "samples") + --nametype TEXT # name type label (default "Function:") + --colors PALETTE # set color palette. choices are: hot (default), mem, + # io, wakeup, chain, java, js, perl, red, green, blue, + # aqua, yellow, purple, orange + --bgcolors COLOR # set background colors. gradient choices are yellow + # (default), blue, green, grey; flat colors use "#rrggbb" + --hash # colors are keyed by function name hash + --cp # use consistent palette (palette.map) + --reverse # generate stack-reversed flame graph + --inverted # icicle graph + --flamechart # produce a flame chart (sort by time, do not merge stacks) + --negate # switch differential hues (blue<->red) + --notes TEXT # add notes comment in SVG (for debugging) + --help # this message + + eg, + ./flamegraph.pl --title="Flame Graph: malloc()" trace.txt > graph.svg + +As suggested in the example, flame graphs can process traces of any event, +such as malloc()s, provided stack traces are gathered. + + +Consistent Palette +================== +If you use the `--cp` option, it will use the $colors selection and randomly +generate the palette like normal. Any future flamegraphs created using the `--cp` +option will use the same palette map. Any new symbols from future flamegraphs +will have their colors randomly generated using the $colors selection. + +If you don't like the palette, just delete the palette.map file. + +This allows your to change your colorscheme between flamegraphs to make the +differences REALLY stand out. + +Example: + +Say we have 2 captures, one with a problem, and one when it was working +(whatever "it" is): + +``` +cat working.folded | ./flamegraph.pl --cp > working.svg +# this generates a palette.map, as per the normal random generated look. + +cat broken.folded | ./flamegraph.pl --cp --colors mem > broken.svg +# this svg will use the same palette.map for the same events, but a very +# different colorscheme for any new events. +``` + +Take a look at the demo directory for an example: + +palette-example-working.svg +palette-example-broken.svg diff --git a/tests/benchmarks/_script/flamegraph/aix-perf.pl b/tests/benchmarks/_script/flamegraph/aix-perf.pl new file mode 100755 index 00000000000..1edd082ecfc --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/aix-perf.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +use Getopt::Std; + +getopt('urt'); + +unless ($opt_r && $opt_t){ + print "Usage: $0 [ -u user] -r sample_count -t sleep_time\n"; + exit(0); +} + +my $i; +my @proc = ""; +for ($i = 0; $i < $opt_r ; $i++){ + if ($opt_u){ + $proc = `/usr/sysv/bin/ps -u $opt_u `; + $proc =~ s/^.*\n//; + $proc =~ s/\s*(\d+).*\n/\1 /g; + @proc = split(/\s+/,$proc); + } else { + opendir(my $dh, '/proc') || die "Cant't open /proc: $!"; + @proc = grep { /^[\d]+$/ } readdir($dh); + closedir ($dh); + } + + foreach my $pid (@proc){ + my $command = "/usr/bin/procstack $pid"; + print `$command 2>/dev/null`; + } + select(undef, undef, undef, $opt_t); +} diff --git a/tests/benchmarks/_script/flamegraph/difffolded.pl b/tests/benchmarks/_script/flamegraph/difffolded.pl new file mode 100755 index 00000000000..4c76c2ecf30 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/difffolded.pl @@ -0,0 +1,115 @@ +#!/usr/bin/perl -w +# +# difffolded.pl diff two folded stack files. Use this for generating +# flame graph differentials. +# +# USAGE: ./difffolded.pl [-hns] folded1 folded2 | ./flamegraph.pl > diff2.svg +# +# Options are described in the usage message (-h). +# +# The flamegraph will be colored based on higher samples (red) and smaller +# samples (blue). The frame widths will be based on the 2nd folded file. +# This might be confusing if stack frames disappear entirely; it will make +# the most sense to ALSO create a differential based on the 1st file widths, +# while switching the hues; eg: +# +# ./difffolded.pl folded2 folded1 | ./flamegraph.pl --negate > diff1.svg +# +# Here's what they mean when comparing a before and after profile: +# +# diff1.svg: widths show the before profile, colored by what WILL happen +# diff2.svg: widths show the after profile, colored by what DID happen +# +# INPUT: See stackcollapse* programs. +# +# OUTPUT: The full list of stacks, with two columns, one from each file. +# If a stack wasn't present in a file, the column value is zero. +# +# folded_stack_trace count_from_folded1 count_from_folded2 +# +# eg: +# +# funca;funcb;funcc 31 33 +# ... +# +# COPYRIGHT: Copyright (c) 2014 Brendan Gregg. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# (http://www.gnu.org/copyleft/gpl.html) +# +# 28-Oct-2014 Brendan Gregg Created this. + +use strict; +use Getopt::Std; + +# defaults +my $normalize = 0; # make sample counts equal +my $striphex = 0; # strip hex numbers + +sub usage { + print STDERR < diff2.svg + -h # help message + -n # normalize sample counts + -s # strip hex numbers (addresses) +See stackcollapse scripts for generating folded files. +Also consider flipping the files and hues to highlight reduced paths: +$0 folded2 folded1 | ./flamegraph.pl --negate > diff1.svg +USAGE_END + exit 2; +} + +usage() if @ARGV < 2; +our($opt_h, $opt_n, $opt_s); +getopts('ns') or usage(); +usage() if $opt_h; +$normalize = 1 if defined $opt_n; +$striphex = 1 if defined $opt_s; + +my ($total1, $total2) = (0, 0); +my %Folded; + +my $file1 = $ARGV[0]; +my $file2 = $ARGV[1]; + +open FILE, $file1 or die "ERROR: Can't read $file1\n"; +while () { + chomp; + my ($stack, $count) = (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + $stack =~ s/0x[0-9a-fA-F]+/0x.../g if $striphex; + $Folded{$stack}{1} += $count; + $total1 += $count; +} +close FILE; + +open FILE, $file2 or die "ERROR: Can't read $file2\n"; +while () { + chomp; + my ($stack, $count) = (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + $stack =~ s/0x[0-9a-fA-F]+/0x.../g if $striphex; + $Folded{$stack}{2} += $count; + $total2 += $count; +} +close FILE; + +foreach my $stack (keys %Folded) { + $Folded{$stack}{1} = 0 unless defined $Folded{$stack}{1}; + $Folded{$stack}{2} = 0 unless defined $Folded{$stack}{2}; + if ($normalize && $total1 != $total2) { + $Folded{$stack}{1} = int($Folded{$stack}{1} * $total2 / $total1); + } + print "$stack $Folded{$stack}{1} $Folded{$stack}{2}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/example-dtrace-stacks.txt b/tests/benchmarks/_script/flamegraph/example-dtrace-stacks.txt new file mode 100644 index 00000000000..04d84424719 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/example-dtrace-stacks.txt @@ -0,0 +1,41913 @@ +CPU ID FUNCTION:NAME + 0 64091 :tick-60s + + + genunix`kmem_cpu_reload+0x20 + genunix`kmem_cache_free+0xce + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_broadcast+0x1 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`tsc_gethrtimeunscaled+0x21 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 1 + + unix`mutex_exit+0x12 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_exit+0x12 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_init+0x32 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`tsc_read+0x3 + unix`mutex_vector_enter+0xcc + genunix`lookuppnatcred+0x89 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_lookup+0xa5 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookupnameatcred+0x76 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x16 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x46 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`crfree+0x76 + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0x27 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x118 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`dispatch_hilevel+0x18 + unix`do_interrupt+0x120 + unix`_interrupt+0xba + unix`strlen+0x10 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cpu_reload+0x28 + genunix`kmem_cache_free+0xce + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cpu_reload+0x28 + genunix`kmem_cache_free+0xce + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + ufs`ufs_lookup+0x48 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x1f9 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x49 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x49 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_exit+0x19 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_init+0x39 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`ufalloc_file+0x4b + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`setf+0xfb + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_free+0xb + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0x2c + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x1d + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cpu_reload+0x2d + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cpu_reload+0x2d + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x4e + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dnlc_lookup+0xef + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`sigcheck+0x20 + genunix`post_syscall+0x3d3 + unix`0xfffffffffb800c91 + 1 + + ufs`ufs_getpage+0x1 + genunix`segvn_fault+0xdfa + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + genunix`dnlc_lookup+0xf2 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_get_buf+0x13 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`specvp_check+0x24 + zfs`zfs_lookup+0xf4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`openat+0x25 + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x56 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`post_syscall+0x1b7 + unix`0xfffffffffb800c91 + 1 + + genunix`cv_broadcast+0x17 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_fastaccesschk_execute+0x47 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`table_lock_enter+0x8 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_recycle+0x98 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`specvp_check+0x29 + zfs`zfs_lookup+0xf4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x129 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x5a + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`table_lock_enter+0xc + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0x3d + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mtype_func+0x8e + unix`page_get_mnode_freelist+0x4f + unix`page_get_freelist+0x16d + unix`page_create_va+0x2ad + genunix`pvn_read_kluster+0x10c + ufs`ufs_getpage_ra+0x11c + ufs`ufs_getpage+0x866 + genunix`fop_getpage+0x7e + genunix`segvn_faulta+0x12b + genunix`as_faulta+0x143 + genunix`memcntl+0x53d + unix`sys_syscall+0x17a + 1 + + genunix`post_syscall+0x1bf + unix`0xfffffffffb800c91 + 1 + + genunix`lookuppnvp+0xf + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dnlc_lookup+0x100 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dnlc_lookup+0x104 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`copen+0x1a6 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_lookup+0xc7 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`setbackdq+0x258 + FSS`fss_preempt+0x241 + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`kmem_cache_alloc+0x6a + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fd_find+0x9c + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`thread_lock+0x3f + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 1 + + genunix`disp_lock_exit+0x20 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 1 + + genunix`segvn_fault + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + lofs`lo_root+0x22 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x73 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`lo_lookup+0x54 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`open+0x14 + unix`sys_syscall+0x17a + 1 + + unix`htable_lookup+0x44 + unix`htable_walk+0x17e + unix`hat_unload_callback+0x138 + genunix`segvn_unmap+0x5b7 + genunix`as_unmap+0x19c + unix`mmapobj_map_elf+0x147 + unix`mmapobj_map_interpret+0x22c + unix`mmapobj+0x71 + genunix`mmapobjsys+0x1d0 + unix`sys_syscall+0x17a + 1 + + lofs`freelonode+0x1f9 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_free+0x3a + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_free+0x3a + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0xc + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dnlc_lookup+0x11e + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0x60 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x330 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xb0 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_mountedvfs+0x1 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x13 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_getcomponent+0x84 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`bcopy+0x244 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x84 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xb4 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + ufs`ufs_lookup+0x84 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`audit_falloc+0x6 + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`bcopy+0x248 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x138 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x89 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x23a + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`disp_lock_exit+0x3b + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 1 + + genunix`vn_vfslocks_getlock+0x1b + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fd_reserve+0xb + genunix`ufalloc_file+0x103 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`table_lock_enter+0x3c + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`table_lock_enter+0x3c + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x8d + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x8d + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xbd + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x1f + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_reinit+0xf + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0xff + unix`0xfffffffffb800c86 + 1 + + unix`page_numtopp_nolock+0x130 + unix`hat_pte_unmap+0xb8 + unix`hat_unload_callback+0x259 + genunix`segvn_unmap+0x5b7 + genunix`as_free+0xdc + genunix`relvm+0x220 + genunix`proc_exit+0x444 + genunix`exit+0x15 + genunix`rexit+0x18 + unix`sys_syscall+0x17a + 1 + + genunix`vn_mountedvfs+0x10 + genunix`lookuppnvp+0x217 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_exit + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_exit+0x1 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_free+0x52 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_openat+0x83 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`table_lock_enter+0x45 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_exists+0x15 + lofs`makelonode+0x1e7 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`setbackdq+0x286 + FSS`fss_preempt+0x241 + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`vn_openat+0x486 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_openat+0x87 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_free+0x57 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_destroy+0x78 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x29 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_openat+0x48a + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnatcred+0x13a + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_init+0x1b + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_destroy+0x7b + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_init+0xd + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_init+0xd + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x2d + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xce + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`lwp_getdatamodel+0xf + genunix`post_syscall+0x2f5 + unix`0xfffffffffb800c91 + 1 + + unix`prunstop + unix`0xfffffffffb800c91 + 1 + + unix`hment_compare+0x10 + genunix`avl_find+0x72 + genunix`avl_add+0x27 + unix`hment_insert+0x8b + unix`hment_assign+0x3a + unix`hati_pte_map+0x343 + unix`hati_load_common+0x139 + unix`hat_memload+0x75 + unix`hat_memload_region+0x25 + genunix`segvn_fault+0x1079 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + unix`bcopy+0x260 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x10 + unix`sys_syscall+0x1a1 + 1 + + genunix`cv_init+0x11 + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_init+0x11 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_init+0x21 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_init+0x21 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`copen+0x1e2 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`membar_enter+0x3 + unix`disp+0x11e + unix`swtch+0xba + unix`preempt+0xec + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + lofs`table_lock_enter+0x54 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_openat+0x94 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_getcomponent+0xa5 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x35 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`cpucaps_charge+0x75 + FSS`fss_preempt+0x12f + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + unix`bcopy+0x268 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x58 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_enter_common+0x1e8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x39 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_alloc+0xd9 + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`lwp_getdatamodel+0x19 + genunix`post_syscall+0x2f5 + unix`0xfffffffffb800c91 + 1 + + unix`lwp_getdatamodel+0x1a + unix`0xfffffffffb800c91 + 1 + + genunix`fop_lookup+0x7b + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x7b + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xdb + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`crgetuid+0xb + ufs`ufs_iaccess+0xe5 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x3c + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`copen+0xed + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_init+0x1d + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`freelonode+0x2f + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_getcomponent+0xb0 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`ufalloc_file+0xb0 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x22 + unix`0xfffffffffb800c86 + 1 + + genunix`audit_falloc+0x34 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_broadcast+0x76 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`lock_try+0x6 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 1 + + genunix`set_errno+0x17 + genunix`copen+0x4fa + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`copen+0x1f8 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_getcomponent+0xba + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x2a + unix`0xfffffffffb800c86 + 1 + + genunix`post_syscall+0x21b + unix`0xfffffffffb800c91 + 1 + + genunix`lookuppnatcred+0x5b + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`post_syscall+0x1b + unix`0xfffffffffb800c91 + 1 + + unix`prunstop+0x1c + unix`0xfffffffffb800c91 + 1 + + genunix`dnlc_lookup+0x5c + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookuppn+0x38 + genunix`resolvepath+0x86 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xed + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xed + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xed + genunix`kmem_free+0x4e + genunix`removectx+0xf5 + genunix`schedctl_lwp_cleanup+0x8e + genunix`exitlwps+0x73 + genunix`proc_exit+0x59 + genunix`exit+0x15 + genunix`rexit+0x18 + unix`sys_syscall+0x17a + 1 + + lofs`freelonode+0x23f + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dnlc_lookup+0x160 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`copen+0x1 + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_invalid+0x1 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_invalid+0x1 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_enter_common+0x1 + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`do_splx+0x1 + unix`preempt+0xec + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`crhold+0x11 + genunix`falloc+0xbc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dnlc_lookup+0x65 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_lookup+0x25 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnatcred+0x66 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_destroy+0x8 + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_setpath+0xc9 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnatcred+0x6a + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xfa + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cv_destroy+0xc + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_recycle+0xc + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x9c + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x5d + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x7d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x13d + unix`0xfffffffffb800c86 + 1 + + genunix`syscall_mstate+0x13d + unix`sys_syscall+0x1a1 + 1 + + genunix`lookuppnatcred+0x6e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_reinit+0x4f + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_fixslash+0x40 + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`do_splx+0x10 + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 1 + + genunix`kmem_cache_free + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`thread_lock+0xa1 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 1 + + genunix`memcmp+0x1 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_exit+0x41 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + doorfs`door_close+0x1 + namefs`nm_close+0xac + genunix`fop_close+0x61 + genunix`closef+0x5e + genunix`close_exec+0xfd + genunix`exec_common+0x7e4 + genunix`exece+0x1b + unix`_sys_sysenter_post_swapgs+0x149 + 1 + + unix`cpucaps_charge+0xa2 + FSS`fss_preempt+0x12f + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`vn_vfslocks_rele+0x23 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`setf+0x83 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dotoprocs+0xc4 + genunix`doprio+0x77 + genunix`priocntl_common+0x616 + genunix`priocntlsys+0x24 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_alloc+0x4 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x45 + unix`sys_syscall+0x10e + 1 + + genunix`setf+0x87 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`lock_clear_splx+0x7 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 1 + + genunix`fop_lookup+0xaa + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fd_find+0xb + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_fixslash+0x4c + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0xc + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_getlock+0x6e + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_zalloc+0x1e + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`post_syscall+0x13e + unix`0xfffffffffb800c91 + 1 + + genunix`copen+0x20 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`traverse+0x10 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x10 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x10 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x10 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + FSS`fss_preempt + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`vn_recycle+0x21 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`crfree+0x11 + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_enter_common+0x22 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`memcmp+0x13 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_lookup+0x43 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x153 + unix`sys_syscall+0x1a1 + 1 + + genunix`lookuppnatcred+0x84 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`crfree+0x15 + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`bitset_in_set+0x6 + unix`cpu_wakeup_mwait+0x40 + unix`setbackdq+0x200 + FSS`fss_preempt+0x241 + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`dnlc_lookup+0x186 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_zalloc+0x26 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`hment_insert+0x37 + unix`hment_assign+0x3a + unix`hati_pte_map+0x343 + unix`hati_load_common+0x139 + unix`hat_memload+0x75 + unix`hat_memload_region+0x25 + genunix`segvn_fault+0x1079 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + genunix`kmem_cache_free+0x17 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`setf+0x98 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`post_syscall+0x34b + unix`0xfffffffffb800c91 + 1 + + genunix`traverse+0x1c + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_enter_common+0x2d + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_zalloc+0x2d + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`setbackdq+0x3de + FSS`fss_preempt+0x241 + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + lofs`lo_inactive+0x1e + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_free+0x9e + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookupnameatcred+0x1e + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`falloc+0xaf + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fd_find+0x21 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`dnlc_lookup+0x92 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x22 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x22 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`secpolicy_vnode_access2+0x222 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_free+0xa3 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`cmt_balance+0xc3 + unix`setbackdq+0x3a3 + FSS`fss_preempt+0x241 + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`rwst_enter_common+0x335 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_recycle+0x36 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookuppnvp+0x3a7 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x167 + unix`sys_syscall+0x1a1 + 1 + + ufs`ufs_lookup+0xf7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_delay_default+0x7 + unix`mutex_vector_enter+0xcc + genunix`lookuppnatcred+0x89 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`page_create_va+0x218 + genunix`pvn_read_kluster+0x10c + ufs`ufs_getpage_ra+0x11c + ufs`ufs_getpage+0x866 + genunix`fop_getpage+0x7e + genunix`segvn_faulta+0x12b + genunix`as_faulta+0x143 + genunix`memcntl+0x53d + unix`sys_syscall+0x17a + 1 + + lofs`makelonode+0x6a + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`unfalloc+0x1a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x1cb + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0x1cb + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x2b + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vmem_free+0x2b + genunix`segkp_release_internal+0x1ab + genunix`segkp_release+0xa0 + genunix`schedctl_freepage+0x34 + genunix`schedctl_proc_cleanup+0x68 + genunix`proc_exit+0x1ab + genunix`exit+0x15 + genunix`rexit+0x18 + unix`sys_syscall+0x17a + 1 + + genunix`crgetmapped+0xb + genunix`fop_lookup+0x1dc + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`copystr+0x2e + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x2f + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x2f + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`crgetmapped+0xf + genunix`fop_lookup+0x1dc + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x100 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x100 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + ufs`ufs_lookup+0x100 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`makelonode+0x71 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_openat+0xf1 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfsrlock+0x31 + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`ufalloc_file+0x1 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`swtch+0x14 + unix`preempt+0xec + unix`kpreempt+0x98 + unix`sys_rtt_common+0x1ba + unix`_sys_rtt_ints_disabled+0x8 + genunix`audit_getstate + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_recycle+0x45 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfslocks_rele+0x57 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x37 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_lookup+0x68 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`lookupnameatcred+0x3a + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_free+0x3a + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`schedctl_save+0x1b + genunix`savectx+0x35 + unix`resume+0x5b + unix`swtch+0x141 + unix`preempt+0xec + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`dnlc_lookup+0xac + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vsd_free+0xdc + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vsd_free+0xdc + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`thread_lock+0xdd + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 1 + + lofs`freelonode+0x18e + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + ufs`ufs_lookup+0xf + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + ufs`ufs_lookup+0x10f + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pn_getcomponent+0x10 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x110 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_enter + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_enter + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`lgrp_mem_choose+0x1 + genunix`swap_getapage+0x113 + genunix`swap_getpage+0x90 + genunix`fop_getpage+0x7e + genunix`anon_zero+0xb6 + genunix`segvn_faultpage+0x6d2 + genunix`segvn_fault+0x8e6 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + genunix`audit_getstate+0x1 + unix`0xfffffffffb800c91 + 1 + + genunix`rwst_destroy+0x32 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`disp_lock_exit_high+0x33 + unix`swtch+0xba + unix`preempt+0xec + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`lookuppnvp+0x3c3 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + ufs`ufs_lookup+0x13 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x84 + unix`sys_syscall+0x1a1 + 1 + + zfs`zfs_lookup+0x76 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`unfalloc+0x37 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x118 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`lo_lookup+0x2f9 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vsd_free+0xe9 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_enter+0x9 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_enter+0x9 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_enter+0x9 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_enter+0x9 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_exit+0x8a + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_zalloc+0x5a + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x1b + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`copen+0x15c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`unfalloc+0x3c + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_fastaccesschk_execute+0xc + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`audit_getstate+0xd + genunix`setf+0x3f + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`audit_getstate+0xd + genunix`lookuppnvp+0x82 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + zfs`zfs_lookup+0x7e + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`traverse+0x4e + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x1e + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`hwblkclr+0x3f + unix`pfnzero+0x78 + unix`pagezero+0x2d + genunix`anon_zero+0xd2 + genunix`segvn_faultpage+0x6d2 + genunix`segvn_fault+0x8e6 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + unix`tsc_gethrtimeunscaled + genunix`mstate_thread_onproc_time+0x59 + unix`caps_charge_adjust+0x32 + unix`cpucaps_charge+0x58 + FSS`fss_preempt+0x12f + unix`preempt+0xd6 + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + unix`page_lookup_create+0xf0 + unix`page_lookup+0x21 + genunix`swap_getapage+0xea + genunix`swap_getpage+0x90 + genunix`fop_getpage+0x7e + genunix`anon_zero+0xb6 + genunix`segvn_faultpage+0x6d2 + genunix`segvn_fault+0x8e6 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + unix`page_lookup_create+0xf0 + unix`page_lookup+0x21 + ufs`ufs_getpage+0x762 + genunix`fop_getpage+0x7e + genunix`segvn_fault+0xdfa + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + unix`mutex_enter+0x10 + unix`page_get_mnode_freelist+0x32c + unix`page_get_freelist+0x16d + unix`page_create_va+0x2ad + genunix`swap_getapage+0x113 + genunix`swap_getpage+0x90 + genunix`fop_getpage+0x7e + genunix`anon_zero+0xb6 + genunix`segvn_faultpage+0x6d2 + genunix`segvn_fault+0x8e6 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + unix`mutex_enter+0x10 + unix`page_get_mnode_freelist+0x32c + unix`page_get_freelist+0x16d + unix`page_create_va+0x2ad + genunix`pvn_read_kluster+0x10c + ufs`ufs_getpage_ra+0x11c + ufs`ufs_getpage+0x866 + genunix`fop_getpage+0x7e + genunix`segvn_faulta+0x12b + genunix`as_faulta+0x143 + genunix`memcntl+0x53d + unix`sys_syscall+0x17a + 1 + + ufs`ufs_iaccess+0x91 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0x1 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`fop_lookup+0xf1 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_destroy+0x1 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_destroy+0x1 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`rwst_enter_common+0x162 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`pvn_plist_init+0x42 + genunix`swap_getapage+0x323 + genunix`swap_getpage+0x90 + genunix`fop_getpage+0x7e + genunix`anon_zero+0xb6 + genunix`segvn_faultpage+0x6d2 + genunix`segvn_fault+0x8e6 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + genunix`kmem_cache_alloc+0x22 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x22 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`copen+0x63 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`do_splx+0x65 + unix`swtch+0x17c + unix`preempt+0xec + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + unix`do_splx+0x65 + genunix`disp_lock_exit_nopreempt+0x42 + unix`preempt+0xe7 + unix`kpreempt+0x98 + genunix`disp_lock_exit+0x6f + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 1 + + unix`mutex_enter+0x16 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`cpu_decay+0x27 + genunix`cpu_grow+0x24 + genunix`cpu_update_pct+0x86 + genunix`new_mstate+0x73 + unix`trap+0x63e + unix`sys_rtt_common+0x55 + unix`_sys_rtt_ints_disabled+0x8 + 1 + + unix`tsc_gethrtimeunscaled+0x8 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 1 + + unix`do_splx+0x68 + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 1 + + genunix`traverse+0x5a + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x2a + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_init+0x1b + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0xc + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_destroy+0xc + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_destroy+0xc + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`lo_lookup+0xf + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`freelonode+0x1b0 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0x10 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`openat+0x1 + unix`sys_syscall+0x17a + 1 + + genunix`as_fault+0x381 + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + genunix`vn_vfsunlock+0x1 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`audit_getstate+0x21 + genunix`copen+0x59 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`hwblkclr+0x52 + unix`pfnzero+0x78 + unix`pagezero+0x2d + genunix`anon_zero+0xd2 + genunix`segvn_faultpage+0x6d2 + genunix`segvn_fault+0x8e6 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + genunix`fop_lookup+0x103 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x33 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`savectx+0x24 + unix`resume+0x5b + unix`swtch+0x141 + unix`preempt+0xec + genunix`post_syscall+0x4cd + unix`0xfffffffffb800c91 + 1 + + genunix`kmem_cache_alloc+0x37 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`kmem_cache_alloc+0x37 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`thread_lock+0x8 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 1 + + genunix`lookuppnvp+0xe9 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_exit+0x9 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_exit+0x9 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`mutex_exit+0x9 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + unix`hwblkclr+0x5b + unix`pfnzero+0x78 + unix`pagezero+0x2d + genunix`anon_zero+0xd2 + genunix`segvn_faultpage+0x6d2 + genunix`segvn_fault+0x8e6 + genunix`as_fault+0x36a + unix`pagefault+0x96 + unix`trap+0x2c7 + unix`0xfffffffffb8001d6 + 1 + + genunix`vn_vfsunlock+0xc + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`audit_getstate+0x2d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + lofs`lo_lookup+0x1e + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`syscall_mstate+0x1ae + unix`sys_syscall+0x1a1 + 1 + + genunix`kmem_cache_alloc+0x3e + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_rele+0x1f + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1 + + genunix`vn_vfsunlock+0x10 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfsunlock+0x10 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`audit_getstate+0x30 + unix`0xfffffffffb800c91 + 2 + + genunix`kmem_cache_free+0x70 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`pn_get_buf+0x1 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_exit+0x12 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fd_find+0x73 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`audit_getstate+0x33 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`audit_getstate+0x33 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0x24 + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_setpath+0x144 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0xb4 + unix`sys_syscall+0x10e + 2 + + genunix`lookuppnvp+0xf5 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_fastaccesschk_execute+0x35 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_setpath+0x46 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`tsc_read+0x7 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 2 + + genunix`cv_broadcast+0x8 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_broadcast+0x8 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_exit+0x19 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_init+0x39 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`bcopy+0xa + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x1ab + unix`0xfffffffffb800c91 + 2 + + genunix`kmem_free+0xb + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x8d + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookupnameatcred+0x7e + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`sys_syscall+0x104 + 2 + + genunix`kmem_free+0xf + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_free + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`disp_lock_exit+0x1 + unix`0xfffffffffb800c91 + 2 + + genunix`vn_rele+0x31 + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0x31 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lo_lookup+0x132 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookupnameatcred+0x82 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`traverse+0x82 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0x82 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`falloc+0x13 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`tsc_gethrtimeunscaled+0x34 + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 2 + + unix`tsc_gethrtimeunscaled+0x34 + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 2 + + genunix`falloc+0x15 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0xf6 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x56 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_broadcast+0x17 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lo_root+0x8 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`disp_lock_exit+0x8 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 2 + + genunix`setf+0x8 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnvp+0x209 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`pn_get_buf+0x1b + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_openat+0x4b + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_broadcast+0x1b + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x1b + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`disp_lock_exit+0xc + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 2 + + lofs`freelonode+0x1de + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0x3e + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x19f + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`setf+0x10 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_lookup+0x131 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x1a2 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`table_lock_enter+0x13 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x26 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x26 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x26 + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_lookup+0x139 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnvp+0x1a + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`table_lock_enter+0x1b + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lo_root+0x1b + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fsop_root+0x3b + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`setf+0x1b + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnatcred+0xf + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_fastaccesschk_execute+0x5f + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x1 + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`open+0x12 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0x113 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`setf+0x123 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x1b4 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`ufalloc+0x6 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x77 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x77 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x77 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`bzero+0x188 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`ufalloc+0xe + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`freelonode + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`bcopy+0x240 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_free+0x32 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0x63 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x13 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x43 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 2 + + genunix`fsop_root+0x56 + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`rw_enter+0x26 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x1c7 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x17 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_lookup+0xe8 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnatcred+0x29 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnatcred+0x129 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x89 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x1b + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_lookup+0xec + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0xbd + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`audit_falloc+0xe + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0xc0 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`lwp_getdatamodel + unix`0xfffffffffb800c91 + 2 + + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`rwst_enter_common+0x2d3 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x203 + unix`0xfffffffffb800ca0 + 2 + + unix`mutex_destroy+0x74 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fd_reserve+0x17 + genunix`ufalloc_file+0x103 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x57 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_free+0x57 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`bcopy+0x258 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x108 + unix`0xfffffffffb800c86 + 2 + + genunix`rwst_exit+0x8 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`freelonode+0x1b + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`rwst_enter_common+0x2db + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_destroy+0x7b + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x2d + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_exists+0x1f + lofs`makelonode+0x1e7 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`hment_compare+0x10 + genunix`avl_find+0x72 + unix`hment_remove+0xac + unix`hat_pte_unmap+0x159 + unix`hat_unload_callback+0xe8 + genunix`segvn_unmap+0x5b7 + genunix`as_free+0xdc + genunix`relvm+0x220 + genunix`proc_exit+0x444 + genunix`exit+0x15 + genunix`rexit+0x18 + unix`sys_syscall+0x17a + 2 + + lofs`lo_lookup+0x80 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`set_errno+0x1 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_init+0x11 + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + ufs`ufs_iaccess+0x12 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`rwst_enter_common+0x1e2 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_destroy+0x84 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_init+0x15 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`set_errno+0x6 + genunix`copen+0x4fa + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnatcred+0x46 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lo_root+0x58 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x1e8 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`crgetuid+0x8 + zfs`zfs_fastaccesschk_execute+0x2e + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x39 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x39 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x39 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 2 + + lofs`freelonode+0x2b + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x1b + unix`0xfffffffffb800c86 + 2 + + genunix`kmem_cache_free+0xdb + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0xb + unix`0xfffffffffb800c91 + 2 + + genunix`vn_vfslocks_getlock+0x3c + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lsave+0x4e + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x1ef + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_getlock+0x41 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0xf2 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`bcopy+0x272 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x22 + unix`sys_syscall+0x1a1 + 2 + + genunix`fd_reserve+0x33 + genunix`ufalloc_file+0x103 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x13 + unix`0xfffffffffb800c91 + 2 + + genunix`dnlc_lookup+0x154 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_lookup+0x85 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0x56 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_broadcast+0x76 + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x26 + unix`sys_syscall+0x10e + 2 + + lofs`lsave+0x57 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`freelonode+0x37 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x17 + unix`0xfffffffffb800c91 + 2 + + genunix`vn_vfslocks_rele+0x8 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0xe8 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x4fa + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_broadcast+0x7a + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0xed + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0xed + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`0xfffffffffb800c81 + 2 + + genunix`cv_destroy+0x1 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0xf1 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0xf1 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnatcred+0x62 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x33 + unix`0xfffffffffb800ca0 + 2 + + genunix`copen+0x204 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_lookup+0x97 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_destroy+0x8 + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnatcred+0x168 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`do_splx+0x8 + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 2 + + genunix`vn_vfslocks_getlock+0x59 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`set_errno+0x2e + genunix`copen+0x4fa + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0x6e + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`setf+0x7f + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_zalloc+0x10 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fd_find+0x1 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0x75 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0x175 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x45 + unix`0xfffffffffb800c86 + 2 + + zfs`zfs_lookup+0x37 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`memcmp+0x8 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0x8 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x19 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0x79 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`bcopy+0x399 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_rele+0x29 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`memcmp+0xb + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`do_splx+0x1b + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 2 + + genunix`dnlc_lookup+0x17f + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_lookup+0x3f + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`secpolicy_vnode_access2+0xf + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lo_inactive+0x14 + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`rwst_exit+0x54 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0xe4 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x55 + unix`0xfffffffffb800c86 + 2 + + unix`strlen+0x16 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fd_find+0x17 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`crfree+0x18 + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_recycle+0x2b + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_lookup+0x4b + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_lookup+0xbb + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0x1b + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`setf+0x9c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`copystr+0x1d + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`rwst_exit+0x5d + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + ufs`ufs_lookup+0xed + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x14d + unix`0xfffffffffb800c91 + 2 + + genunix`dnlc_lookup+0x8f + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x4f + unix`0xfffffffffb800c91 + 2 + + genunix`unfalloc+0x10 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`secpolicy_vnode_access2+0x22 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`traverse+0x23 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x163 + unix`sys_syscall+0x1a1 + 2 + + genunix`syscall_mstate+0x167 + unix`0xfffffffffb800c86 + 2 + + genunix`traverse+0x28 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`ufalloc_file+0xf8 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`unfalloc+0x18 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`setf+0xa9 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnvp+0xaa + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`secpolicy_vnode_access2+0x22a + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lo_lookup+0x1db + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`copystr+0x2b + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0x2b + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0xfc + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookupnameatcred+0x2d + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x100 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x1 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x64 + unix`0xfffffffffb800c91 + 2 + + genunix`memcmp+0x35 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_inactive+0x35 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x46 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + ufs`ufs_lookup+0x106 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`copystr+0x37 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_openat+0xf7 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0x1a8 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`memcmp+0x38 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`freelonode+0x189 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_free+0x3a + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_vfslocks_rele+0x5c + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`falloc+0xcc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`syscall_mstate+0x17c + unix`sys_syscall+0x1a1 + 2 + + genunix`fd_find+0x40 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_lookup+0xe0 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnvp+0xc1 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`post_syscall+0x173 + unix`0xfffffffffb800c91 + 2 + + genunix`fop_lookup+0xe4 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_openat+0x106 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnvp+0x3c7 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x17 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`freelonode+0x98 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + ufs`ufs_lookup+0x118 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter+0x9 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter+0x9 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_enter+0x9 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookupnameatcred+0x4b + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x1b + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`dnlc_lookup+0xbe + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + ufs`ufs_lookup+0x11e + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fd_find+0x4f + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookuppnvp+0x3cf + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x22 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fd_find+0x53 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`rwst_enter_common+0x165 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_openat+0x16 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`lookupnameatcred+0x56 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_alloc+0x27 + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0x8 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`audit_getstate+0x18 + genunix`lookuppnvp+0x82 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x2a + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x16c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0xc + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_openat+0x1c + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_lookup+0xfc + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`falloc+0xed + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_fastaccesschk_execute+0x11f + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cpu_reload+0x10 + genunix`kmem_cache_free+0xce + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_exit + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_exit + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_exit + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_exit + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + lofs`lo_lookup+0x13 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_openat+0x24 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0x17 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_rele+0x17 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x37 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`mutex_destroy+0x17 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`audit_getstate+0x28 + genunix`setf+0x3f + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cpu_reload+0x18 + genunix`kmem_cache_alloc+0x118 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`ufalloc_file+0x3a + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + unix`tsc_gethrtimeunscaled+0x1b + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 2 + + unix`mutex_exit+0xc + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`copen+0x17d + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`vn_openat+0x2e + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`kmem_cache_alloc+0x3e + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + zfs`zfs_lookup+0x9f + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 2 + + genunix`cv_broadcast + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`audit_getstate+0x30 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`audit_getstate+0x30 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0x70 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_free + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0xe1 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookupnameatcred+0x72 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit+0x12 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit+0x12 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_rele+0x24 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_rele+0x24 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`freelonode+0x1c5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`lo_lookup+0x25 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`openat+0x16 + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0x36 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`freelonode+0xc7 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`ufalloc_file+0x48 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0x118 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit+0x19 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`lo_lookup+0x12a + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x18b + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`copyinstr+0xc + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`cv_broadcast+0xc + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0xfd + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_alloc+0x4e + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`freelonode+0x1cf + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x90 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`pn_get_buf+0x10 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0x120 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`setf+0x103 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`tsc_gethrtimeunscaled+0x34 + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 3 + + genunix`fd_find+0x85 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vsd_free+0x26 + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`pn_get_buf+0x17 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_free+0x17 + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_free+0x8 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookupnameatcred+0x88 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x1c8 + unix`0xfffffffffb800c86 + 3 + + unix`sys_syscall+0x10e + 3 + + genunix`falloc+0x19 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_free+0x1b + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0x12d + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`post_syscall+0x2bf + unix`0xfffffffffb800c91 + 3 + + lofs`lo_root+0x10 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`dnlc_lookup+0x1 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fd_find+0x91 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x111 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`falloc+0x24 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0x55 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`thread_lock+0x36 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 3 + + genunix`vn_free+0x17 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fd_find+0x98 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`falloc+0x28 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0x139 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`pn_get_buf+0x2a + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_alloc+0x6a + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_free+0x2a + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_free+0x2a + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0xb + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`clear_stale_fd+0xd + genunix`post_syscall+0x1fe + unix`0xfffffffffb800c91 + 3 + + genunix`fop_lookup+0x13d + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`falloc+0x2f + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0x110 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`ufalloc+0x1 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`table_lock_enter+0x22 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0x13 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x124 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`pn_get_buf+0x35 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`rw_enter+0x1c + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x2be + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_rele+0xce + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + zfs`zfs_fastaccesschk_execute+0x6e + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fd_reserve + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0xb0 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`thread_lock+0x53 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 3 + + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_getlock+0x13 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`setf+0x33 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_free+0x43 + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_alloc+0x84 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`dnlc_lookup+0x26 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x1f7 + unix`0xfffffffffb800ca0 + 3 + + lofs`freelonode+0x8 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0xf8 + unix`sys_syscall+0x10e + 3 + + genunix`kmem_cache_alloc+0x89 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x2ca + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_exists+0xc + lofs`makelonode+0x1e7 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x43c + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0xbd + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x2ce + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0x47f + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_getlock+0x1f + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_getlock+0x1f + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x1d0 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`rwst_exit + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`disp_lock_exit+0x42 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 3 + + genunix`kmem_cache_alloc+0x92 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x1d3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x203 + unix`sys_syscall+0x1a1 + 3 + + genunix`lookuppnatcred+0x34 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x444 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`audit_falloc+0x15 + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`freelonode+0x17 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x8 + unix`0xfffffffffb800c86 + 3 + + genunix`syscall_mstate+0x108 + unix`sys_syscall+0x10e + 3 + + genunix`rwst_exit+0x8 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`sys_syscall+0x14e + 3 + + genunix`fop_inactive+0xcb + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_inactive+0xcb + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_getlock+0x2d + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0x8e + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`freelonode+0x1f + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`splr+0x1f + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 3 + + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`table_lock_enter+0x50 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x4e0 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x10 + unix`0xfffffffffb800c86 + 3 + + genunix`crgetuid + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`sys_syscall+0x156 + 3 + + genunix`rwst_enter_common+0x1e2 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0x147 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x17 + unix`0xfffffffffb800c86 + 3 + + genunix`dnlc_lookup+0x149 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x119 + unix`0xfffffffffb800ca0 + 3 + + genunix`syscall_mstate+0x1b + unix`0xfffffffffb800ca0 + 3 + + genunix`post_syscall+0x30c + unix`0xfffffffffb800c91 + 3 + + unix`sys_syscall+0x162 + 3 + + genunix`falloc+0x6f + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`crgetuid+0x10 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`lock_try + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 3 + + genunix`lookuppnatcred+0x151 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`cv_broadcast+0x72 + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + zfs`zfs_lookup+0x12 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x123 + unix`sys_syscall+0x10e + 3 + + zfs`zfs_lookup+0x16 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`pn_fixslash+0x28 + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0xe8 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x36b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`table_lock_enter+0x6d + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`set_errno+0x1e + genunix`copen+0x4fa + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`cv_broadcast+0x7f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`cv_broadcast+0x7f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`cv_broadcast+0x7f + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`atomic_add_32_nv + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`pn_fixslash+0x32 + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x33 + unix`sys_syscall+0x1a1 + 3 + + genunix`syscall_mstate+0x135 + unix`0xfffffffffb800c86 + 3 + + genunix`syscall_mstate+0x135 + unix`0xfffffffffb800ca0 + 3 + + genunix`rwst_exit+0x35 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_zalloc+0x5 + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`0xfffffffffb800c86 + 3 + + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x207 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_rele+0x17 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0x97 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0x2b8 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_free+0x78 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`dnlc_lookup+0x16c + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0x9c + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`do_splx+0xc + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 3 + + genunix`post_syscall+0x32d + unix`0xfffffffffb800c91 + 3 + + genunix`syscall_mstate+0x13d + unix`sys_syscall+0x10e + 3 + + genunix`memcmp + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + zfs`zfs_lookup+0x30 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`bcopy+0x391 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x41 + unix`0xfffffffffb800c86 + 3 + + genunix`lookuppnatcred+0x72 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`set_errno+0x35 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x45 + unix`sys_syscall+0x1a1 + 3 + + genunix`vn_vfslocks_getlock+0x66 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0x77 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`do_splx+0x17 + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 3 + + genunix`audit_unfalloc+0x17 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0xc8 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_inactive+0x8 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_rele+0x29 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`crfree+0x9 + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`rwst_init+0x5a + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_inactive+0xc + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x1d + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fd_find+0xf + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`0xfffffffffb800ca0 + 3 + + genunix`rwst_destroy + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0x10 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x157 + unix`0xfffffffffb800c86 + 3 + + genunix`kmem_cache_free+0x17 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0x17 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`secpolicy_vnode_access2+0x17 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_rele+0x38 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`traverse+0x18 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`unfalloc+0x8 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x39a + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`dnlc_lookup+0x8b + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0x1b + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_getlock+0x7d + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`secpolicy_vnode_access2+0x21e + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x15f + unix`0xfffffffffb800c86 + 3 + + unix`bzero + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`dnlc_lookup+0x92 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_inactive+0x22 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`copystr+0x24 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fd_find+0x24 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`rwst_enter_common+0x35 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0xc7 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x167 + unix`0xfffffffffb800ca0 + 3 + + genunix`rwst_destroy+0x17 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`dnlc_lookup+0x99 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x69 + unix`0xfffffffffb800c86 + 3 + + genunix`syscall_mstate+0x69 + unix`sys_syscall+0x1a1 + 3 + + genunix`kmem_cache_free+0x2b + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`post_syscall+0x35c + 3 + + genunix`copen+0x3d + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`dnlc_lookup+0x9d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0x2f + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + ufs`ufs_lookup+0x1 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0xd2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`ufalloc_file+0x103 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x3b5 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`crgetmapped+0x15 + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`bzero+0x16 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0x37 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vsd_free+0xd8 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_alloc+0x8 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`post_syscall+0x6b + unix`0xfffffffffb800c91 + 3 + + genunix`vn_vfsrlock+0x3c + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fd_find+0x3c + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0xad + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`setf+0xbd + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`bcopy+0x3d0 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_enter + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_enter + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_enter + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x84 + unix`0xfffffffffb800ca0 + 3 + + genunix`post_syscall+0x75 + unix`0xfffffffffb800c91 + 3 + + genunix`ufalloc_file+0x17 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_lookup+0x1e7 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`bcopy+0x3d8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fd_find+0x48 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0x9 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_rele+0x6b + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`ufalloc_file+0x1b + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_setpath+0x11c + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + lofs`makelonode+0x8d + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnatcred+0xbe + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + zfs`zfs_lookup+0x7f + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`bcopy+0x3e0 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookuppnvp+0x3d0 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_destroy + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`lookupnameatcred+0x52 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x193 + unix`sys_syscall+0x1a1 + 3 + + genunix`vn_openat+0x115 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`falloc+0xe5 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`copen+0x166 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`ufalloc_file+0x126 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_alloc+0x26 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_rele+0x8 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`tsc_gethrtimeunscaled+0x8 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 3 + + genunix`audit_getstate+0x18 + genunix`post_syscall+0xbe + unix`0xfffffffffb800c91 + 3 + + genunix`audit_getstate+0x18 + genunix`setf+0x3f + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_openat+0x11b + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`traverse+0x5b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfslocks_getlock+0xbc + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`tsc_gethrtimeunscaled+0xc + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 3 + + genunix`syscall_mstate+0x19d + unix`sys_syscall+0x1a1 + 3 + + unix`mutex_exit + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`syscall_mstate+0x1a1 + unix`0xfffffffffb800ca0 + 3 + + genunix`syscall_mstate+0xa2 + unix`sys_syscall+0x1a1 + 3 + + genunix`vn_rele+0x17 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_rele+0x17 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_alloc+0x37 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`openat+0x8 + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_vfsunlock+0x8 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_free+0x68 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit+0x9 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit+0x9 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`kmem_cache_alloc+0x3a + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`tsc_gethrtimeunscaled+0x1b + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 3 + + genunix`vn_vfsunlock+0xc + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`falloc+0xfc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + unix`mutex_exit+0xc + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`fop_inactive+0x6d + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`vn_rele+0x1f + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 3 + + genunix`post_syscall+0x19f + unix`0xfffffffffb800c91 + 3 + + genunix`pn_get_buf + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`cv_broadcast + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0x70 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`freelonode+0x1c1 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_lookup+0x12 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x12 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x12 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x12 + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x12 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x12 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x12 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_free+0x5 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`pn_get_buf+0x6 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`bcopy+0x308 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`copyinstr+0x8 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit+0x19 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_lookup+0x1a + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`tsc_read+0xa + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 4 + + genunix`fsop_root+0x1b + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`crfree+0x7b + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0x9e + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`ufalloc_file+0x50 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x1c0 + unix`0xfffffffffb800c86 + 4 + + zfs`zfs_fastaccesschk_execute+0x140 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_rele+0x31 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_rele+0x31 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`sys_syscall+0x109 + 4 + + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0xa6 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0xa6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0x86 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0x86 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookupnameatcred+0x87 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_free+0x17 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x1c8 + unix`sys_syscall+0x10e + 4 + + genunix`vn_rele+0x39 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_rele+0x39 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0xc9 + unix`0xfffffffffb800c86 + 4 + + genunix`post_syscall+0xb9 + unix`0xfffffffffb800c91 + 4 + + genunix`fsop_root+0x2a + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_free+0x1b + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_free+0x1b + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`zfs_lookup+0xbd + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`post_syscall+0xbe + unix`0xfffffffffb800c91 + 4 + + genunix`clear_stale_fd+0x1 + unix`0xfffffffffb800c91 + 4 + + genunix`dnlc_lookup+0x104 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`open+0x6 + unix`sys_syscall+0x17a + 4 + + genunix`pn_get_buf+0x26 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`setf+0x116 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_alloc+0x66 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lo_root+0x17 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookuppnatcred+0x109 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`specvp_check+0x3a + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_free+0x2a + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0x9f + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`post_syscall+0x2d0 + unix`0xfffffffffb800c91 + 4 + + genunix`pn_get_buf+0x31 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`setf+0x22 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0xa3 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`zfs_lookup+0xd4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0xc6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`setf+0x26 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`dnlc_lookup+0x118 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_alloc+0x79 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_alloc+0x79 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x1bd + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0xce + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookuppnatcred+0x1e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_free+0x2f + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x1ef + unix`0xfffffffffb800ca0 + 4 + + genunix`fd_reserve + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xb0 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_free+0x43 + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lo_lookup+0x64 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lo_lookup+0x67 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_getlock+0x17 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_alloc+0x89 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fd_reserve+0xb + genunix`setf+0x123 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0xbb + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xbd + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`dnlc_lookup+0x2e + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x2cf + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`post_syscall+0x1f0 + unix`0xfffffffffb800c91 + 4 + + ufs`ufs_lookup+0x93 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`lwp_getdatamodel+0x8 + genunix`post_syscall+0x2f5 + unix`0xfffffffffb800c91 + 4 + + genunix`vn_vfslocks_getlock+0x29 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`splr+0x1b + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 4 + + genunix`pn_fixslash+0xc + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`clear_stale_fd+0x3c + genunix`post_syscall+0x1fe + unix`0xfffffffffb800c91 + 4 + + genunix`vn_rele+0x7d + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_openat+0x48e + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`set_errno + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + ufs`ufs_iaccess+0x110 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_setpath+0xa0 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`gethrtime_unscaled + unix`0xfffffffffb800c86 + 4 + + genunix`cv_init+0x11 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookuppnvp+0x51 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_enter_common+0x1e4 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`cv_init+0x15 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`freelonode+0x27 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_openat+0x497 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_lookup+0x77 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x17 + unix`sys_syscall+0x1a1 + 4 + + genunix`copen+0xe8 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_exit+0x18 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_openat+0x9a + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xdb + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xdb + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`post_syscall+0x20c + unix`0xfffffffffb800c91 + 4 + + genunix`cv_init+0x1d + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`bcmp + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x22 + unix`0xfffffffffb800ca0 + 4 + + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`prunstop+0x14 + genunix`post_syscall+0x2d0 + unix`0xfffffffffb800c91 + 4 + + genunix`vn_vfslocks_rele+0x105 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_openat+0xa7 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fd_reserve+0x37 + genunix`ufalloc_file+0x103 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lo_root+0x68 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0x8 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xe8 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`zfs_lookup+0x1a + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x2a + unix`sys_syscall+0x10e + 4 + + lofs`lo_root+0x70 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_zalloc + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`membar_consumer + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`membar_consumer + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xf1 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xf1 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xf1 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_lookup+0x93 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x135 + unix`sys_syscall+0x1a1 + 4 + + genunix`lookuppnvp+0x76 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`set_errno+0x27 + genunix`copen+0x4fa + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0x17 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fd_reserve+0x48 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x139 + unix`0xfffffffffb800c86 + 4 + + genunix`kmem_cache_free+0xfa + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xfa + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0xfa + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`sys_syscall+0x180 + 4 + + genunix`copen+0xb + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_openat+0xbc + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`table_lock_enter+0x7d + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x13d + unix`0xfffffffffb800ca0 + 4 + + genunix`lookuppnvp+0x37f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookupnameatcred + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`audit_unfalloc+0x10 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lo_inactive+0x1 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x13 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_exit+0x44 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`ufalloc_file+0xd7 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fd_find+0x8 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0x8 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_zalloc+0x1a + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_exit+0x4c + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`do_splx+0x1f + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 4 + + genunix`kmem_cache_free+0x10 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`strlen+0x10 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`strlen+0x13 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x24 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfsrlock+0x14 + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`setf+0x94 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_exit+0x54 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_alloc+0xe4 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_lookup+0xb6 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`post_syscall+0x347 + unix`0xfffffffffb800c91 + 4 + + genunix`syscall_mstate+0x157 + unix`sys_syscall+0x10e + 4 + + genunix`kmem_cache_free+0x17 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x28 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_rele+0x38 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x58 + unix`sys_syscall+0x1a1 + 4 + + genunix`rwst_destroy+0x8 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_openat+0x2d9 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_zalloc+0x29 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0x1b + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`sys_syscall+0x1a1 + 4 + + genunix`dnlc_lookup+0x18e + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`audit_unfalloc+0x2e + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x2f + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`setf+0xa0 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`crgetmapped + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0x22 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0x22 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`post_syscall+0x353 + unix`0xfffffffffb800c91 + 4 + + genunix`falloc+0xb3 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`setf+0xa4 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_getlock+0x86 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_vfslocks_getlock+0x86 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x67 + unix`sys_syscall+0x1a1 + 4 + + genunix`syscall_mstate+0x167 + unix`sys_syscall+0x10e + 4 + + genunix`setf+0xa8 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_invalid+0x39 + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x69 + unix`0xfffffffffb800ca0 + 4 + + unix`splr+0x79 + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 4 + + genunix`lookuppnatcred+0x9b + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_alloc+0xfc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0x2d + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`splr+0x7e + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 4 + + genunix`syscall_mstate+0x170 + unix`0xfffffffffb800ca0 + 4 + + genunix`rwst_destroy+0x20 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x71 + unix`0xfffffffffb800ca0 + 4 + + unix`clear_int_flag+0x1 + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 4 + + genunix`lookuppnvp+0xb4 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_lookup+0xd4 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0x35 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`memcmp+0x37 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`freelonode+0x88 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`ufalloc_file+0x8 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vsd_free+0xd8 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`copystr+0x3c + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0x3f + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`ufalloc_file+0x10 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`unfalloc+0x30 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`audit_getstate + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_alloc+0x10 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_enter + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_enter + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_enter + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`zfs_fastaccesschk_execute + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_destroy+0x32 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`traverse+0x43 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`syscall_mstate+0x84 + unix`0xfffffffffb800c86 + 4 + + genunix`rwst_exit+0x86 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`ufalloc_file+0x117 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x59 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_enter+0x9 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`bcopy+0x2db + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fd_find+0x4c + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`freelonode+0x9d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_inactive+0x4e + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + ufs`ufs_lookup+0x1e + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`zfs_fastaccesschk_execute+0x10f + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`freelonode+0xa0 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x160 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cpu_reload + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`i_ddi_splhigh + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 4 + + lofs`makelonode+0x91 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lo_lookup+0x1 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lsave+0xc4 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookuppnatcred+0xc5 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`bcopy+0x3e8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_rele+0x8 + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_rele+0x8 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vn_openat+0x18 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vfs_matchops+0x8 + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`copen+0x169 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`copystr+0x5a + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`ufalloc_file+0x2a + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`falloc+0xee + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`post_syscall+0x18f + unix`0xfffffffffb800c91 + 4 + + unix`mutex_exit + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`mutex_exit + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookupnameatcred+0x61 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`unfalloc+0x52 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`lookuppnvp+0x1e4 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fop_lookup+0x107 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + zfs`specvp_check+0x8 + zfs`zfs_lookup+0xf4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`audit_getstate+0x28 + genunix`post_syscall+0xbe + unix`0xfffffffffb800c91 + 4 + + genunix`vsd_free+0x8 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`vsd_free+0x8 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0x68 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`kmem_cache_free+0x68 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + lofs`lo_lookup+0x11b + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + unix`tsc_gethrtimeunscaled+0x1b + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 4 + + genunix`fd_find+0x6f + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 4 + + genunix`fsop_root+0x10 + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`audit_getstate+0x30 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`lo_lookup+0x122 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x1b2 + unix`0xfffffffffb800ca0 + 5 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit+0x12 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit+0x12 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`audit_getstate+0x33 + unix`0xfffffffffb800c91 + 5 + + genunix`vn_rele+0x24 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0xb4 + unix`sys_syscall+0x1a1 + 5 + + genunix`fsop_root+0x17 + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`traverse+0x77 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`tsc_read+0x7 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 5 + + unix`tsc_gethrtimeunscaled+0x28 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 5 + + unix`mutex_exit+0x19 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x1bb + unix`sys_syscall+0x1a1 + 5 + + genunix`kmem_free+0xb + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_free+0xf + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_free+0xf + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0xf0 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_rele+0x31 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`copyinstr+0x11 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`setf+0x1 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_init+0x41 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fsop_root+0x22 + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fd_find+0x82 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_openat+0x47 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`bcopy+0x318 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookuppnvp+0xb + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_free+0x1b + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`lo_root+0xc + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameatcred+0x8c + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fd_find+0x8d + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_rele+0x3e + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_rele+0x3e + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameatcred+0x93 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x1d4 + unix`0xfffffffffb800c86 + 5 + + genunix`kmem_free+0x26 + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`table_lock_enter+0x17 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_openat+0x59 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_free+0x2a + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`pn_get_buf+0x2d + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_openat+0x60 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`falloc+0x33 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_openat+0x64 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x15 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`lo_root+0x28 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`open+0x18 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_getlock+0x8 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_alloc+0x79 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_openat+0x6a + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`falloc+0x3a + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`thread_lock+0x4b + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 5 + + genunix`dnlc_lookup+0x11c + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0xb0 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0xb0 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_mountedvfs+0x1 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x22 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_getlock+0x13 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_alloc+0x84 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_getlock+0x17 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookuppnvp+0x39 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x2a + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`setf+0x3a + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_getlock+0x1b + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_destroy+0x6b + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_alloc+0x8d + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_getlock+0x1f + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`rwst_enter_common+0x2cf + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`freelonode+0x10 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`pn_fixslash+0x1 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`cv_init+0x8 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x8 + unix`sys_syscall+0x10e + 5 + + genunix`syscall_mstate+0x108 + unix`sys_syscall+0x1a1 + 5 + + genunix`vn_vfslocks_getlock+0x29 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + ufs`ufs_iaccess+0xa + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0xc + unix`0xfffffffffb800c86 + 5 + + genunix`cv_init+0xd + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_getlock+0x2d + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0x6d + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_zalloc+0xdf + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`gethrtime_unscaled + unix`sys_syscall+0x1a1 + 5 + + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`freelonode+0x23 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_destroy+0x84 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`sys_syscall+0x15a + 5 + + genunix`fd_reserve+0x26 + genunix`setf+0x123 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`table_lock_enter+0x57 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x17 + unix`0xfffffffffb800ca0 + 5 + + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 5 + + genunix`kmem_cache_free+0xdb + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0xdb + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0xdb + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`table_lock_enter+0x5c + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`pn_getcomponent+0xad + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookuppnvp+0x35e + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_alloc+0xdf + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`crhold + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`cv_broadcast+0x72 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x22 + unix`sys_syscall+0x10e + 5 + + genunix`syscall_mstate+0x123 + unix`0xfffffffffb800c86 + 5 + + genunix`rwst_exit+0x23 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`audit_falloc+0x33 + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x105 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0x85 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_free+0x66 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x26 + unix`sys_syscall+0x1a1 + 5 + + genunix`copen+0xf8 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0xe8 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0xe8 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x159 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`crhold+0x9 + genunix`falloc+0xbc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0x8e + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookuppnvp+0x6f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`lo_lookup+0x1a0 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookuppnatcred+0x60 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`audit_unfalloc + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`freelonode+0x42 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`post_syscall+0x23 + unix`0xfffffffffb800c91 + 5 + + unix`sys_syscall+0x17a + 5 + + genunix`crhold+0x16 + genunix`falloc+0xbc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`cv_destroy+0x8 + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`ufalloc_file+0xc8 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x69 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_getlock+0x59 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x3a + unix`0xfffffffffb800ca0 + 5 + + genunix`post_syscall+0x2e + unix`0xfffffffffb800c91 + 5 + + lofs`freelonode+0x4f + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fd_find + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`crfree + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`table_lock_enter+0x82 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookuppnvp+0x82 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x45 + unix`0xfffffffffb800ca0 + 5 + + unix`lock_clear_splx+0x5 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 5 + + genunix`post_syscall+0x338 + unix`0xfffffffffb800c91 + 5 + + genunix`lookuppnatcred+0x78 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`traverse+0x8 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x8 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x29 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x29 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`rwst_init+0x5b + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0xad + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_alloc+0xe4 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`lo_lookup+0x1c5 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameatcred+0x17 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + zfs`zfs_lookup+0x47 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x38 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x58 + unix`0xfffffffffb800c86 + 5 + + unix`rw_exit+0x8 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookuppnatcred+0x89 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`rwst_enter_common+0x29 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x8b + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x1b + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 5 + + genunix`crfree+0x1d + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameat+0x10 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_zalloc+0x31 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_openat+0xe2 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x22 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x22 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x46 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x46 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x46 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`post_syscall+0x357 + unix`0xfffffffffb800c91 + 5 + + genunix`rwst_destroy+0x17 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0x198 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameat+0x18 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x168 + 5 + + genunix`crgetmapped+0x8 + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_invalid+0x39 + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameatcred+0x29 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + zfs`zfs_lookup+0x59 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`post_syscall+0x35b + unix`0xfffffffffb800c91 + 5 + + genunix`kmem_cache_free+0x2b + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x2b + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`unfalloc+0x1d + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`atomic_add_32 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`atomic_add_32 + genunix`falloc+0xbc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_alloc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`clear_int_flag + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 5 + + genunix`syscall_mstate+0x71 + unix`sys_syscall+0x10e + 5 + + genunix`syscall_mstate+0x71 + unix`sys_syscall+0x1a1 + 5 + + genunix`fop_inactive+0x31 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0xd2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`bcopy+0x3c8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + zfs`zfs_lookup+0x6a + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfsrlock+0x3c + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0xdd + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x3f + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x3f + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`atomic_add_64 + unix`sys_syscall+0x10e + 5 + + unix`atomic_add_64 + unix`0xfffffffffb800ca0 + 5 + + unix`atomic_add_64 + unix`sys_syscall+0x1a1 + 5 + + genunix`vn_openat + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_setpath+0x10 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_enter + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_enter + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_enter + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_enter + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_enter + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_enter + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`makelonode+0x81 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_openat+0x1 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`bcopy+0x2d2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`rwst_destroy+0x33 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`copen+0x54 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameat+0x34 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + ufs`ufs_iaccess+0x86 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameatcred+0x47 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0x1e7 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`freelonode+0x98 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vsd_free+0xe8 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`falloc+0xd9 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0xe9 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_enter+0x9 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`lookupnameat+0x3a + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_inactive+0x4a + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`crgetmapped+0x2a + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_vfslocks_rele+0x6b + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_alloc+0x1b + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0x18c + unix`sys_syscall+0x1a1 + 5 + + genunix`audit_getstate+0xd + genunix`copen+0x59 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_rele + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`ufalloc_file+0x22 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + zfs`zfs_fastaccesschk_execute+0x16 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + lofs`freelonode+0xa8 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_rele+0x8 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`falloc+0xe9 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`copystr+0x5d + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_setpath+0x2d + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`falloc+0xf0 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_exit + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`post_syscall+0x291 + unix`0xfffffffffb800c91 + 5 + + genunix`lookuppnatcred+0xd1 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`syscall_mstate+0xa2 + unix`sys_syscall+0x10e + 5 + + genunix`syscall_mstate+0xa2 + unix`0xfffffffffb800c86 + 5 + + genunix`lookuppnvp+0xe3 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`vn_rele+0x17 + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + zfs`zfs_lookup+0x97 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`mutex_destroy+0x17 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`setf+0xe8 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`fop_lookup+0x208 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`audit_getstate+0x28 + genunix`lookuppnvp+0x82 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`audit_getstate+0x28 + genunix`copen+0x59 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x68 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`kmem_cache_free+0x68 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + unix`tsc_gethrtimeunscaled+0x1b + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 5 + + genunix`thread_lock+0xc + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 5 + + genunix`dnlc_lookup+0xdc + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`audit_getstate+0x2d + unix`0xfffffffffb800c91 + 5 + + genunix`kmem_cache_alloc+0x3e + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + zfs`zfs_fastaccesschk_execute+0x2e + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`dnlc_lookup+0xdf + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 5 + + genunix`cv_broadcast + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0x70 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_free + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_free + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`tsc_read + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 6 + + unix`splx + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 6 + + genunix`post_syscall+0x2a1 + unix`0xfffffffffb800c91 + 6 + + unix`copyinstr+0x1 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnvp+0x1f1 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`ufalloc_file+0x41 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit+0x12 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit+0x12 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit+0x12 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0xb4 + unix`0xfffffffffb800c86 + 6 + + genunix`syscall_mstate+0xb4 + unix`0xfffffffffb800ca0 + 6 + + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_free+0x5 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`freelonode+0xc7 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vsd_free+0x17 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`tsc_read+0x7 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 6 + + unix`tsc_read+0x7 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 6 + + genunix`cv_broadcast+0x8 + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`tsc_gethrtimeunscaled+0x28 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 6 + + unix`tsc_gethrtimeunscaled+0x28 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 6 + + genunix`fd_find+0x78 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit+0x19 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`openat+0x1a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_free+0xb + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele+0x9e + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`thread_lock+0x1f + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 6 + + genunix`syscall_mstate+0x1c0 + unix`sys_syscall+0x10e + 6 + + genunix`post_syscall+0x1b3 + unix`0xfffffffffb800c91 + 6 + + genunix`fsop_root+0x26 + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`copyinstr+0x16 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele+0xa6 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_rele+0x39 + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`setf+0xc + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`falloc+0x1d + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`openat+0x2f + unix`sys_syscall+0x17a + 6 + + genunix`pn_get_buf+0x1f + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`bcopy+0x320 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + zfs`specvp_check+0x30 + zfs`zfs_lookup+0xf4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`clear_stale_fd + unix`0xfffffffffb800c91 + 6 + + genunix`dnlc_lookup+0x1 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnatcred+0x104 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_alloc+0x66 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_alloc+0x66 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`table_lock_enter+0x17 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_free+0x17 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`thread_lock+0x39 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 6 + + genunix`fop_inactive+0x9f + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock+0x1 + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0xe3 + unix`sys_syscall+0x10e + 6 + + lofs`table_lock_enter+0x26 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele+0xc6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock+0x8 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`traverse+0xa8 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnatcred+0x1a + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_free+0x3a + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`freelonode+0xfb + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock+0xc + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnatcred+0x11c + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`_sys_rtt + 6 + + genunix`ufalloc_file+0x7e + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0xb0 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0xb0 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_free+0x43 + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_mountedvfs+0x8 + genunix`traverse+0x77 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_zalloc+0xc8 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`freelonode+0x109 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_alloc+0x89 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_alloc+0x8d + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0xbd + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0xbd + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`splr+0x10 + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 6 + + genunix`fsop_root+0x61 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_rele+0x71 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`dnlc_lookup+0x32 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_alloc+0x92 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_zalloc+0xd3 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`post_syscall+0x2f5 + unix`0xfffffffffb800c91 + 6 + + genunix`fd_reserve+0x17 + genunix`setf+0x123 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_init+0x17 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`splr+0x17 + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 6 + + genunix`kmem_free+0x57 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`copen+0x1d8 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnatcred+0x138 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`falloc+0x5c + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_rele+0x7d + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + ufs`ufs_iaccess+0xe + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0x10 + unix`sys_syscall+0x10e + 6 + + genunix`gethrtime_unscaled + unix`sys_syscall+0x10e + 6 + + genunix`dnlc_lookup+0x43 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_alloc+0xd4 + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fd_reserve+0x26 + genunix`ufalloc_file+0x103 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`freelonode+0x27 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`sys_syscall+0x15e + 6 + + ufs`ufs_iaccess+0x19 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_zalloc+0xea + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 6 + + genunix`syscall_mstate+0x1b + unix`sys_syscall+0x1a1 + 6 + + lofs`table_lock_enter+0x5c + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock+0x3c + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`prunstop+0xd + genunix`post_syscall+0x2d0 + unix`0xfffffffffb800c91 + 6 + + ufs`ufs_iaccess+0x1d + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_openat+0xa1 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`lo_root+0x62 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`cv_broadcast+0x72 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fd_reserve+0x33 + genunix`setf+0x123 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_exit+0x23 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`freelonode+0x37 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele+0x8 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele+0x8 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0xe8 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0x2a + unix`0xfffffffffb800ca0 + 6 + + genunix`post_syscall+0x31b + unix`0xfffffffffb800c91 + 6 + + genunix`post_syscall+0x1f + unix`0xfffffffffb800c91 + 6 + + genunix`vn_invalid + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + zfs`zfs_lookup+0x21 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0xf1 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0xf1 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`dnlc_lookup+0x62 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`post_syscall+0x324 + unix`0xfffffffffb800c91 + 6 + + genunix`falloc+0x84 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele+0x17 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`post_syscall+0x27 + unix`0xfffffffffb800c91 + 6 + + genunix`cv_destroy+0x8 + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fd_reserve+0x48 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0x139 + unix`sys_syscall+0x10e + 6 + + genunix`syscall_mstate+0x3a + unix`sys_syscall+0x1a1 + 6 + + genunix`kmem_cache_free+0xfa + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`cv_destroy+0xc + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`pn_fixslash+0x3d + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnatcred+0x16f + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`lo_inactive + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_alloc + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`post_syscall+0x134 + unix`0xfffffffffb800c91 + 6 + + genunix`fop_lookup+0xa5 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`lo_inactive+0x8 + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0x8 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`lsave+0x7a + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`pn_fixslash+0x4b + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`sys_syscall+0x192 + 6 + + genunix`dnlc_lookup+0x7d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock+0x6e + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`unfalloc + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_destroy + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`ufalloc_file+0xe3 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`memcmp+0x17 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fop_inactive+0x17 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0x17 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0x17 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fop_lookup+0xbb + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock+0x7d + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 6 + + genunix`rwst_exit+0x5d + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`copen+0x33 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_rele+0x46 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`traverse+0x26 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0x2b + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_alloc+0xfc + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + ufs`ufs_lookup+0xfd + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`rw_exit+0x1e + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`copen+0x13f + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`bcopy+0x3c0 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookupnameat+0x20 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnvp+0x1b7 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0x177 + unix`sys_syscall+0x1a1 + 6 + + genunix`kmem_cache_alloc+0x8 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0x3a + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`dnlc_lookup+0x1ad + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`fd_find+0x3f + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`ufalloc_file+0x10f + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`audit_getstate + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_enter + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_enter + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_enter + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_enter + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_enter + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_enter + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`audit_getstate+0x1 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnvp+0xc3 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_destroy+0x33 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfslocks_getlock+0xa6 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_exit+0x86 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + ufs`ufs_lookup+0x17 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + zfs`zfs_fastaccesschk_execute+0x8 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + zfs`zfs_lookup+0x7a + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`audit_getstate+0xa + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`setf+0xcc + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`crgetmapped+0x2e + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`post_syscall+0x7f + unix`0xfffffffffb800c91 + 6 + + genunix`vn_rele + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_destroy + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`traverse+0x52 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`rwst_enter_common+0x162 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`ufalloc_file+0x26 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`tsc_gethrtimeunscaled+0x8 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 6 + + unix`mutex_destroy+0x8 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`thread_lock + unix`0xfffffffffb800c91 + 6 + + genunix`vn_rele+0x10 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + zfs`specvp_check + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vsd_free + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`mutex_exit + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0xa2 + unix`0xfffffffffb800ca0 + 6 + + unix`do_splx+0x74 + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 6 + + zfs`zfs_fastaccesschk_execute+0x26 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`vn_vfsunlock+0x8 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`kmem_cache_free+0x68 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`freelonode+0xb9 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + lofs`freelonode+0xb9 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`lookuppnvp+0x1e9 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + unix`do_splx+0x79 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 6 + + unix`bcopy+0x3fa + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`syscall_mstate+0x1ab + unix`sys_syscall+0x1a1 + 6 + + genunix`traverse+0x6f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 6 + + genunix`thread_lock+0x10 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 7 + + genunix`kmem_cache_free+0x70 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0x70 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`tsc_read + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 7 + + genunix`cv_broadcast+0x1 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`thread_lock+0x17 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 7 + + unix`tsc_gethrtimeunscaled+0x28 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 7 + + zfs`zfs_fastaccesschk_execute+0x138 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_openat+0x3d + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`dnlc_lookup+0xef + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`falloc+0xf + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`bcopy+0x310 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`lookuppnvp + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`lo_root+0x1 + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`tsc_gethrtimeunscaled+0x34 + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 7 + + genunix`lookuppnatcred+0xf5 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`cv_broadcast+0x17 + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_free+0x8 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_rele+0x39 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`copyinstr+0x1b + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_inactive+0x8b + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`dnlc_lookup+0xfc + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_lookup+0x12d + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + ufs`ufs_lookup+0x365 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_alloc+0x66 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfslocks_getlock + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`ufalloc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`clear_stale_fd+0x13 + genunix`post_syscall+0x1fe + unix`0xfffffffffb800c91 + 7 + + genunix`lookuppnvp+0x29 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`copen+0x2ba + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`freelonode+0xfb + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_free+0x2b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`setf+0x12b + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_inactive+0xab + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`sys_syscall+0x132 + 7 + + genunix`audit_falloc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`freelonode+0x1 + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`disp_lock_exit+0x32 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 7 + + genunix`open+0x26 + 7 + + genunix`thread_lock+0x57 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 7 + + genunix`syscall_mstate+0x1f7 + unix`sys_syscall+0x1a1 + 7 + + lofs`freelonode+0x8 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_enter_common+0x2cb + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_destroy+0x6b + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_mountedvfs+0xc + genunix`traverse+0x77 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_alloc+0x8d + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`pn_get_buf+0x4f + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`setf+0x3f + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`pn_get_buf+0x50 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`lookuppnatcred+0x30 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_mountedvfs+0x10 + genunix`traverse+0x77 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + zfs`zfs_lookup+0xf4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`lo_lookup+0x275 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`cv_init+0x8 + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`freelonode+0x21e + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`lookuppnatcred+0x3f + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`gethrtime_unscaled + unix`0xfffffffffb800ca0 + 7 + + genunix`fop_lookup+0x73 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_alloc+0xd4 + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`lookuppnvp+0x458 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_exit+0x18 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_init+0x28 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`syscall_mstate+0x119 + unix`0xfffffffffb800c86 + 7 + + genunix`syscall_mstate+0x1b + unix`sys_syscall+0x10e + 7 + + genunix`kmem_cache_free+0xdb + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`syscall_mstate+0x11c + unix`sys_syscall+0x1a1 + 7 + + lofs`freelonode+0x2f + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_free+0x66 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`syscall_mstate+0x26 + unix`0xfffffffffb800c86 + 7 + + genunix`syscall_mstate+0x26 + unix`0xfffffffffb800ca0 + 7 + + genunix`fd_reserve+0x37 + genunix`setf+0x123 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + ufs`ufs_iaccess+0x28 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfslocks_rele+0x8 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`syscall_mstate+0x2a + unix`sys_syscall+0x1a1 + 7 + + genunix`dnlc_lookup+0x5f + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`bcmp+0xf + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fd_reserve+0x40 + genunix`setf+0x123 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`do_splx+0x1 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 7 + + genunix`rwst_exit+0x35 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`lo_lookup+0xa6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfslocks_rele+0x17 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_invalid+0x8 + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0xfa + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0xfa + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_enter_common+0xb + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`cv_destroy+0xc + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + zfs`zfs_lookup+0x2c + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfsrlock + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`lock_clear_splx + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 7 + + unix`strlen+0x3 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_exit+0x44 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfslocks_getlock+0x66 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`falloc+0x97 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0x8 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0x8 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_alloc+0xb + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`lookuppnatcred+0x7c + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`setf+0x8c + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_invalid+0x1d + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfslocks_getlock+0x6e + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`ufalloc_file+0xde + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`lo_inactive+0x10 + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`copystr+0x14 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`makelfsnode+0x17 + lofs`makelonode+0x192 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0x17 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`lo_inactive+0x18 + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`lo_inactive+0x18 + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfsrlock+0x18 + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`syscall_mstate+0x58 + unix`0xfffffffffb800ca0 + 7 + + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`secpolicy_vnode_access2+0x1e + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_enter_common+0x331 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`dnlc_lookup+0x195 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`memcmp+0x26 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_inactive+0x26 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`syscall_mstate+0x69 + unix`sys_syscall+0x10e + 7 + + genunix`falloc+0xbc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`syscall_mstate+0x170 + unix`sys_syscall+0x1a1 + 7 + + genunix`syscall_mstate+0x71 + unix`0xfffffffffb800c86 + 7 + + zfs`zfs_lookup+0x63 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`crgetmapped+0x15 + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0x3a + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfslocks_rele+0x5c + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_lookup+0x1e0 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`audit_getstate + unix`0xfffffffffb800c91 + 7 + + genunix`kmem_cache_alloc+0x10 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_enter + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_enter + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_enter + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`audit_getstate+0x1 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`pn_getcomponent+0x14 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_openat+0x307 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_alloc+0x17 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`makelonode+0x89 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`audit_getstate+0xa + unix`0xfffffffffb800c91 + 7 + + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_lookup+0xed + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`crgetmapped+0x2e + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`freelonode+0x1a0 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + zfs`zfs_lookup+0x80 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_alloc+0x22 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_inactive+0x53 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_inactive+0x53 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`post_syscall+0x85 + unix`0xfffffffffb800c91 + 7 + + genunix`vn_setpath+0x26 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_alloc+0x26 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_destroy+0x8 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_alloc+0x2a + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_lookup+0xfc + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + lofs`makelonode+0x1a0 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_exit + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_exit + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`vn_rele+0x17 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`copystr+0x67 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + unix`mutex_init+0x27 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`kmem_cache_free+0x68 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_lookup+0x20b + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_lookup+0x10c + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`fop_inactive+0x6d + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 7 + + genunix`falloc + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0x70 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit+0x12 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit+0x12 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit+0x12 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_free+0x5 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`copen+0x86 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`unfalloc+0x66 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0x46 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + zfs`specvp_check+0x17 + zfs`zfs_lookup+0xf4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0x49 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit+0x19 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit+0x19 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit+0x19 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`thread_lock+0x1b + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 8 + + unix`mutex_init+0x3d + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0x4e + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`lo_lookup+0x30 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`copen+0x195 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfslocks_rele+0xa6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`freelonode+0xdd + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`freelonode+0xdd + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_rele+0x3e + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fop_inactive+0x90 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfslocks_getlock+0xf2 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfslocks_rele+0xb3 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x1d4 + unix`sys_syscall+0x10e + 8 + + lofs`lsave+0x8 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fop_lookup+0x13d + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`disp_lock_exit+0x1e + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 8 + + genunix`syscall_mstate+0xe3 + unix`0xfffffffffb800c86 + 8 + + lofs`lo_root+0x25 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`disp_lock_exit+0x30 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 8 + + genunix`rwst_init + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_free+0x43 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_setpath+0x85 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`table_lock_enter+0x38 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_rele+0x68 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_enter_common+0x1c8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0xf8 + unix`0xfffffffffb800c86 + 8 + + genunix`kmem_cache_free+0xbd + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0xbd + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`lo_lookup+0x26f + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`pn_fixslash + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`lookuppnvp+0x240 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_mountedvfs+0x11 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_enter_common+0x2d7 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_free+0x57 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x108 + unix`0xfffffffffb800ca0 + 8 + + genunix`vn_vfslocks_getlock+0x29 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfslocks_getlock+0x29 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_enter_common+0x2db + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fop_lookup+0x6d + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_destroy+0x7f + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x10 + unix`0xfffffffffb800ca0 + 8 + + genunix`kmem_alloc+0xd4 + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`table_lock_enter+0x57 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x17 + unix`sys_syscall+0x10e + 8 + + genunix`rwst_exit+0x18 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 8 + + lofs`makelonode+0x1b + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_enter_common+0x1ec + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`copen+0x4ee + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`post_syscall+0xf + unix`0xfffffffffb800c91 + 8 + + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 8 + + genunix`kmem_cache_free+0xe8 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`freelonode+0x23a + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fop_lookup+0x8a + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0xf1 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0xf1 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x132 + unix`sys_syscall+0x1a1 + 8 + + genunix`syscall_mstate+0x135 + unix`sys_syscall+0x10e + 8 + + genunix`vn_free+0x78 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0xfa + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0xfa + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`cv_destroy+0xc + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_zalloc+0xc + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`freelonode+0x4f + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`lo_inactive+0x8 + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0x8 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`secpolicy_vnode_access2+0x8 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`copen+0x21b + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + zfs`zfs_lookup+0x3b + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`lo_inactive+0xc + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_exit+0x4c + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`strlen+0x10 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`secpolicy_vnode_access2+0x13 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0xe4 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x157 + unix`0xfffffffffb800ca0 + 8 + + genunix`kmem_cache_free+0x1b + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfslocks_getlock+0x7d + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 8 + + genunix`rwst_exit+0x5d + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`lookuppnvp+0xa2 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + zfs`zfs_lookup+0x52 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`memcmp+0x23 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0xf3 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`lfind+0x16 + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfslocks_getlock+0x86 + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`copen+0x37 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_destroy+0x17 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fop_lookup+0x1c8 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_enter_common+0x38 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_alloc+0x2a + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fop_lookup+0xcb + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`memcmp+0x2c + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`dnlc_lookup+0xa0 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`atomic_add_32 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_alloc + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`secpolicy_vnode_access2+0x34 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vsd_free+0xd8 + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`freelonode+0x189 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fd_find+0x3a + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0x3a + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0xc + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`audit_unfalloc+0x4d + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0x3f + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fop_lookup+0xe0 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_enter + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_enter + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_enter + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + ufs`ufs_lookup+0x111 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`syscall_mstate+0x84 + unix`sys_syscall+0x10e + 8 + + genunix`kmem_cache_alloc+0x17 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_enter+0x9 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + lofs`freelonode+0x9d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`rwst_enter_common+0x15f + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_rele + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + ufs`ufs_lookup+0x22 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_init+0x17 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`audit_getstate+0x18 + genunix`copen+0x59 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0x2a + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`ufalloc_file+0x12f + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`vn_vfsunlock + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`mutex_exit + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`fd_find+0x62 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`post_syscall+0x93 + unix`0xfffffffffb800c91 + 8 + + genunix`vn_vfslocks_getlock+0xc4 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + unix`bcopy+0x3f5 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_alloc+0x3a + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`audit_getstate+0x2c + genunix`post_syscall+0xbe + unix`0xfffffffffb800c91 + 8 + + genunix`kmem_cache_alloc+0x3e + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 8 + + genunix`kmem_cache_free+0x70 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x70 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`tsc_read + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 9 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_exit+0x12 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_exit+0x12 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_exit+0x12 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`audit_getstate+0x33 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vsd_free+0x17 + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_exit+0x19 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`openat+0x1e + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_recycle+0x90 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`fd_find+0x80 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`setf + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 9 + + genunix`kmem_free+0x17 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`table_lock_enter+0x8 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_rele+0x39 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`lookuppnatcred + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`lookuppnvp+0x217 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_free+0x2a + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_getlock+0x106 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_alloc+0x77 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_getlock+0x8 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_enter_common+0x1b8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`post_syscall+0xda + unix`0xfffffffffb800c91 + 9 + + genunix`fsop_root+0x4b + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_setops+0x30 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0xb0 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`lookuppnvp+0x132 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`table_lock_enter+0x38 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_init+0x8 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0xbd + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_exit + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 9 + + genunix`rwst_enter_common+0x1d8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_enter_common+0x2dc + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_enter_common+0x2dc + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`freelonode+0x21e + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_destroy+0x7f + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`table_lock_enter+0x50 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`makelonode+0x10 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + zfs`zfs_lookup+0x1 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`post_syscall+0x1 + 9 + + genunix`copen+0x4e3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + ufs`ufs_iaccess+0x15 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_enter_common+0x1e8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`cv_init+0x19 + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`cv_init+0x19 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0xdb + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0xdb + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_getlock+0x3c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`freelonode+0x22e + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_getlock+0x41 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_getlock+0x41 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`freelonode+0x33 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0xe8 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`cv_broadcast+0x7f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`cv_destroy+0x1 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_init+0x42 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`fop_lookup+0x93 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`lo_root+0x77 + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_getlock+0x59 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0xfa + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`cv_destroy+0xc + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`strlen + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`lookuppnvp+0x182 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_alloc+0x5 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`post_syscall+0x35 + unix`0xfffffffffb800c91 + 9 + + lofs`makelfsnode+0x8 + lofs`makelonode+0x192 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x8 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_rele+0x29 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfsrlock+0x9 + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_enter_common+0x1b + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_enter_common+0x1b + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0xc + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`syscall_mstate+0x14d + unix`0xfffffffffb800c86 + 9 + + genunix`vn_openat+0xd1 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_exit+0x54 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_alloc+0xe4 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`lo_lookup+0xc7 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`fop_inactive+0x17 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x17 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x17 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_alloc+0x17 + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_setpath+0xea + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_alloc+0xf3 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_alloc+0xf3 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfslocks_getlock+0x88 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x2b + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_openat+0x2ef + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_alloc + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`fd_find+0x36 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vfs_getops+0x3b + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_alloc+0x3b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`fop_lookup+0x1dc + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x3f + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`secpolicy_vnode_access2+0x3f + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_enter + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`copen+0x156 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`secpolicy_vnode_access2+0x46 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_enter+0x9 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`freelonode+0x1a0 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_rele + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`traverse+0x52 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`lookuppnvp+0xd6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`freelonode+0xa8 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_exit + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_setpath+0x35 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x68 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x68 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_alloc+0x3a + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`vn_setpath+0x13b + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + unix`mutex_exit+0xc + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + lofs`freelonode+0x1bd + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 9 + + genunix`kmem_cache_free+0x70 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_exit+0x12 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_exit+0x12 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vsd_free+0x17 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_exit+0x19 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`table_lock_enter + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`disp_lock_exit + unix`0xfffffffffb800c91 + 10 + + genunix`dnlc_lookup+0xf2 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_openat+0x43 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`cv_broadcast+0x17 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`lsave + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`open + 10 + + genunix`vn_vfslocks_rele+0xb3 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_setpath+0x66 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`table_lock_enter+0x17 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`sys_syscall+0x121 + 10 + + genunix`fop_inactive+0xa3 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`table_lock_enter+0x26 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_alloc+0x77 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`syscall_mstate+0x1ef + unix`sys_syscall+0x1a1 + 10 + + genunix`vn_reinit + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_free+0xb0 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`lookuppnatcred+0x25 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfslocks_getlock+0x17 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_rele+0x68 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`freelonode+0x109 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`cv_init+0x1 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_alloc+0x92 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`thread_lock+0x167 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 10 + + genunix`rwst_enter_common+0x2d7 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_alloc+0xc8 + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`lookuppnatcred+0x3b + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + zfs`zfs_lookup + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`pn_fixslash+0x14 + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`table_lock_enter+0x57 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfslocks_getlock+0x3c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`rwst_enter_common+0x1ec + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`lookuppnvp+0x45f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfslocks_rele + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`syscall_mstate+0x123 + unix`sys_syscall+0x1a1 + 10 + + genunix`vn_setpath+0xb8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`freelonode+0x23a + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`dnlc_lookup+0x5c + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`table_lock_enter+0x6d + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_openat+0xb1 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_free+0xf1 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`cv_destroy+0xd + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`lo_inactive + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfsrlock + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`strlen + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`syscall_mstate+0x41 + unix`0xfffffffffb800ca0 + 10 + + genunix`rwst_init+0x51 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`lookupnameatcred+0xf + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`lfind + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_setpath+0xe2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_alloc+0xe4 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vfs_getops+0x17 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_free+0x17 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_alloc+0x1b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`dnlc_lookup+0x8f + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`memcmp+0x20 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`lookupnameat+0x14 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfslocks_getlock+0x88 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`crgetmapped+0x8 + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`fop_lookup+0xcd + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`secpolicy_vnode_access2+0x2d + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_alloc+0x2e + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfslocks_getlock+0x90 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_alloc + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`lookupnameatcred+0x31 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`makelonode+0x17d + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`atomic_add_64 + unix`0xfffffffffb800c86 + 10 + + genunix`vfs_getops+0x40 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`audit_getstate + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_enter + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_enter + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`secpolicy_vnode_access2+0x43 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`kmem_cache_alloc+0x17 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vsd_free+0xe8 + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_init+0x8 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`thread_lock+0xed + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 10 + + genunix`fop_inactive+0x4e + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + lofs`freelonode+0xa0 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`tsc_gethrtimeunscaled + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 10 + + unix`tsc_gethrtimeunscaled + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 10 + + unix`tsc_gethrtimeunscaled + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 10 + + genunix`vn_rele+0x8 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`openat + unix`sys_syscall+0x17a + 10 + + genunix`vsd_free + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_exit + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_exit + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_exit + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`vn_vfslocks_getlock+0xc4 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + genunix`fd_find+0x67 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`mutex_init+0x27 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 10 + + unix`bcopy+0x300 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + unix`tsc_read + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 11 + + lofs`freelonode+0x1c1 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_rele+0x24 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`post_syscall+0x1a5 + unix`0xfffffffffb800c91 + 11 + + genunix`kmem_cache_alloc+0x4e + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_free + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`fop_lookup+0x126 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`table_lock_enter+0x8 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_setops+0x8 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_rele+0x3e + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_free+0x26 + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_vfslocks_getlock+0x106 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_alloc+0x79 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_free+0x2b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_free+0x2f + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_rele+0x60 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_mountedvfs + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_free+0xb0 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`syscall_mstate+0x1f3 + unix`sys_syscall+0x1a1 + 11 + + genunix`kmem_free+0x43 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`lsave+0x26 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`ufalloc_file+0x86 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_vfslocks_getlock+0x17 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`rwst_enter_common+0x2c7 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_mountedvfs+0x8 + genunix`traverse+0x77 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_free+0xbd + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`post_syscall+0x5f0 + unix`0xfffffffffb800c91 + 11 + + genunix`kmem_cache_alloc+0x92 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`makelonode+0x8 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_rele+0x78 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`syscall_mstate+0xc + unix`sys_syscall+0x10e + 11 + + genunix`post_syscall+0x1fe + unix`0xfffffffffb800c91 + 11 + + lofs`lsave+0x42 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`makelonode+0x26 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_free+0xe8 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`pn_fixslash+0x2c + genunix`lookuppnvp+0x105 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`cv_destroy + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`lo_lookup+0x1a8 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_setpath+0xce + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`makelonode+0x42 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_vfsrlock+0x9 + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`rwst_init+0x5a + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_invalid+0x1d + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`fop_lookup+0xb2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_alloc+0x17 + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`secpolicy_vnode_access2+0x218 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_free+0x1b + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`unfalloc+0xc + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 11 + + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`rwst_enter_common+0x331 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_alloc+0xf3 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`ufalloc_file + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_alloc + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`rwst_enter_common+0x341 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`lfind+0x24 + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`freelonode+0x88 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_setpath+0x8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_cache_free+0x3a + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`fop_lookup+0xdd + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + unix`mutex_enter + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`rwst_destroy+0x33 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + lofs`lfind+0x35 + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_vfslocks_getlock+0xa6 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`kmem_alloc+0x46 + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + unix`bcopy+0x2d7 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_setpath+0x17 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vsd_free+0xe8 + genunix`vn_free+0x8b + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + unix`mutex_enter+0x9 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + unix`mutex_enter+0x9 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`fop_lookup+0xea + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`crgetmapped+0x2a + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`syscall_mstate+0x18c + unix`0xfffffffffb800ca0 + 11 + + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + unix`tsc_gethrtimeunscaled + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 11 + + genunix`vn_vfslocks_getlock+0xb4 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + ufs`ufs_lookup+0x2d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`rwst_tryenter+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`fop_inactive+0x60 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_setpath+0x31 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + genunix`vn_openat+0x124 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + ufs`ufs_lookup+0x34 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 11 + + unix`copyinstr + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_alloc+0x43 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_alloc+0x4e + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_rele+0x31 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + unix`mutex_init+0x42 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfslocks_rele+0xa6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_rele+0x39 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`fop_inactive+0x90 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfsunlock+0x35 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`fop_lookup+0x135 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_setops+0x17 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfslocks_getlock + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`dnlc_lookup+0x11 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`lsave+0x17 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + unix`rw_enter+0x17 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_alloc+0x79 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`dnlc_lookup+0x22 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`table_lock_enter+0x38 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_reinit+0x8 + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`rwst_enter_common+0x1c8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`lsave+0x32 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`table_lock_enter+0x50 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`fop_lookup+0x77 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`cv_init+0x19 + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_free+0xdb + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`dnlc_lookup+0x59 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + ufs`ufs_iaccess+0x2f + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_invalid + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + unix`membar_consumer + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_setpath+0x1c7 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_free+0xfa + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`dnlc_lookup+0x16c + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vfs_getops + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_alloc + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`ufalloc_file+0xd3 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`set_errno+0x34 + genunix`copen+0x4fa + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`dnlc_lookup+0x17f + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_alloc+0xf + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_free+0x1b + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfslocks_getlock+0x7d + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_free+0xa3 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_alloc+0xf3 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfslocks_getlock+0x86 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfslocks_getlock+0x86 + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`makelonode+0x168 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_free+0x2b + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_free+0x2b + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`rwst_enter_common+0x341 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_alloc+0x32 + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_alloc+0x8 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfslocks_rele+0x5c + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_free+0x3f + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + unix`mutex_enter + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`fop_inactive+0x41 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`rwst_enter_common+0x157 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`rwst_enter_common+0x157 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_alloc+0x17 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_alloc+0x17 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`lfind+0x3b + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_setpath+0x1b + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`fop_lookup+0x1f0 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`fop_lookup+0xf1 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_alloc+0x26 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + unix`mutex_init+0x17 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + lofs`freelonode+0x1b0 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + unix`mutex_exit + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`dnlc_lookup+0xd3 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_vfsunlock+0x8 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + ufs`ufs_lookup+0x138 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`vn_setpath+0x3d + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 12 + + genunix`kmem_cache_free+0x70 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`traverse+0x77 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + unix`mutex_init+0x3d + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0x25 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_free+0x17 + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`freelonode+0x1de + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0x30 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_getlock+0xf2 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0x37 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`table_lock_enter+0x1b + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`lo_lookup+0x250 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`table_lock_enter+0x26 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0x47 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_mountedvfs + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0x55 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`dnlc_lookup+0x26 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_setops+0x3d + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_free+0xbd + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`dnlc_lookup+0x2e + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`cv_init + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`freelonode+0x17 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`rwst_init+0x17 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`cv_init+0x8 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`lo_lookup+0x283 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`rwst_enter_common+0x1e4 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`rwst_init+0x28 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`table_lock_enter+0x5c + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_setpath+0xb0 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`lsave+0x52 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`rwst_exit+0x23 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + ufs`ufs_iaccess+0x24 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_exists+0x36 + lofs`makelonode+0x1e7 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_rele+0x8 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_free+0xe8 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_free+0xe8 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`makelonode+0x2a + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`table_lock_enter+0x6d + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_recycle + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`post_syscall+0x221 + unix`0xfffffffffb800c91 + 13 + + genunix`cv_destroy+0x8 + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_invalid+0x8 + lofs`freelonode+0x115 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + ufs`ufs_iaccess+0x3c + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`audit_unfalloc+0xc + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`table_lock_enter+0x7d + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`lsave+0x6f + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0x9f + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`makelfsnode + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + unix`sys_syscall+0x186 + 13 + + lofs`table_lock_enter+0x82 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`rwst_exit+0x44 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`traverse+0x8 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_free+0x8 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_alloc+0xb + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + unix`strlen+0xb + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_getlock+0x6e + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_rele+0x38 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`traverse+0x18 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_getlock+0x7d + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_alloc+0xf3 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_rele+0x46 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`traverse+0x26 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`unfalloc+0x16 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_alloc+0x26 + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0xc7 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_alloc+0xfc + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_alloc + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfsrlock+0x3b + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_setpath+0x118 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + unix`mutex_init+0x8 + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + ufs`ufs_lookup+0x1a + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_vfslocks_rele+0x6b + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_setpath+0x22 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`makelonode+0x98 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`lo_lookup+0xb + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + ufs`ufs_iaccess+0x9d + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`makelfsnode+0x5f + lofs`makelonode+0x192 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + unix`mutex_exit + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_setpath+0x133 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_rele+0x17 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_alloc+0x37 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`kmem_cache_alloc+0x3a + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fd_find+0x6b + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`fop_lookup+0xb + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`audit_getstate+0x2c + genunix`lookuppnvp+0x82 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + lofs`freelonode+0x1bd + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 13 + + genunix`vn_setpath+0x140 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_exit+0x12 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_exit+0x12 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`dnlc_lookup+0xe5 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vfs_matchops+0x27 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`cv_broadcast+0x8 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x1a + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x21 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x21 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_setpath+0x155 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_vfslocks_rele+0xa6 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_inactive+0x8b + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x2c + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`makelonode+0x1d2 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_recycle+0xa2 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`table_lock_enter+0x13 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_setpath+0x163 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_alloc+0x66 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x3b + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x43 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fd_find+0xa6 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_vfslocks_getlock+0x8 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_vfslocks_getlock+0x8 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x4b + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_recycle+0xbd + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`table_lock_enter+0x2e + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`freelonode + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`rwst_init + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_free+0xb0 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_alloc+0x84 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_exists+0x8 + lofs`makelonode+0x1e7 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + ufs`ufs_lookup+0x9b + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_destroy+0x84 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`lsave+0x45 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_reinit+0x29 + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_setpath+0xb5 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`dnlc_lookup+0x56 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`makelonode+0x2e + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + ufs`ufs_iaccess+0x130 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`syscall_mstate+0x130 + unix`sys_syscall+0x1a1 + 14 + + genunix`rwst_init+0x42 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_vfslocks_rele+0x17 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_vfslocks_rele+0x17 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`rwst_enter_common+0xb + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`lo_lookup+0x1ae + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`traverse + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_inactive + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`0xfffffffffb800c91 + 14 + + genunix`lookupnameatcred+0x1 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`bcopy+0x395 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vfs_getops+0x8 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_inactive+0x8 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_free+0x8 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`rwst_init+0x5b + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0xb0 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_free+0x17 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_vfsrlock+0x18 + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`secpolicy_vnode_access2+0x1a + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`crgetmapped + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_alloc+0xf3 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + ufs`ufs_lookup+0xf4 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_inactive+0x26 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`rwst_enter_common+0x38 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_alloc+0x2a + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_alloc+0xfc + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`makelonode+0x6d + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`post_syscall+0x5e + unix`0xfffffffffb800c91 + 14 + + genunix`secpolicy_vnode_access2+0x22f + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vfs_getops+0x32 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_free+0x3a + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`lookupnameat+0x30 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_enter + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_enter + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_enter + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_enter + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0xed + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + ufs`ufs_iaccess+0x8e + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vfs_matchops + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_destroy+0x8 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vn_rele+0xc + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`vsd_free + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_exit + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_exit + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_exit + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_exit + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`kmem_cache_alloc+0x3a + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + genunix`fop_lookup+0x10c + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + ufs`ufs_lookup+0x3c + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 14 + + unix`mutex_exit+0x12 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`mutex_exit+0x12 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`makelfsnode+0x77 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`makelfsnode+0x78 + lofs`makelonode+0x192 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`dnlc_lookup+0xeb + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vsd_free+0x1b + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_vfslocks_rele+0x9e + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`lo_root + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`makelonode+0xc2 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`mutex_init+0x42 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x66 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x66 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_free+0x2a + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`table_lock_enter+0x22 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + ufs`ufs_iaccess+0xe5 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_setops+0x26 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`lookupnameatcred+0xa8 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`rwst_enter_common+0x1b8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x84 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`lookuppnvp+0x235 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`rwst_enter_common+0x2c7 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + ufs`ufs_lookup+0x88 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x89 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`fop_lookup+0x5a + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`mutex_destroy+0x6b + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x92 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x92 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_free+0x57 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`disp_lock_exit+0x48 + unix`0xfffffffffb800c91 + 15 + + genunix`kmem_alloc+0xc8 + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`syscall_mstate+0xc + unix`sys_syscall+0x1a1 + 15 + + genunix`syscall_mstate+0x10f + unix`sys_syscall+0x1a1 + 15 + + genunix`vn_setops+0x50 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`crgetuid + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`dnlc_lookup+0x43 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`post_syscall+0x205 + unix`0xfffffffffb800c91 + 15 + + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_rele+0x87 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`cv_init+0x19 + genunix`rwst_init+0x56 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`crgetuid+0x10 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`makelonode+0x22 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`cv_destroy + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`rwst_exit+0x35 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`cv_destroy+0x8 + genunix`rwst_destroy+0x2e + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_recycle+0x8 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`syscall_mstate+0x139 + unix`0xfffffffffb800ca0 + 15 + + lofs`table_lock_enter+0x7d + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`lo_lookup+0xaf + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`traverse + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`lock_clear_splx+0x3 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 15 + + lofs`lo_lookup+0xb7 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`lfind+0xb + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`makelonode+0x5e + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`rwst_destroy+0x25 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_alloc+0x6 + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`memcmp+0x37 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`pn_getcomponent+0x8 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x8 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x8 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + lofs`makelonode+0x79 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + ufs`ufs_lookup+0xb + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`mutex_enter + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`syscall_mstate+0x183 + unix`sys_syscall+0x1a1 + 15 + + lofs`makelonode+0x186 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`rwst_exit+0x86 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x1b + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`crgetmapped+0x2e + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`copystr+0x54 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_alloc+0x26 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_rele+0x8 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`traverse+0x5b + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_vfsunlock + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`mutex_exit + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`mutex_exit + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_free+0x68 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`kmem_cache_free+0x68 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`vn_setpath+0x39 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`fsop_root+0xc + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 15 + + genunix`cv_broadcast + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vsd_free+0x10 + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_rele+0x24 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`lfind+0x67 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0x4e + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`table_lock_enter + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`lo_lookup+0x34 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`dnlc_lookup+0x100 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`lo_lookup+0x48 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`post_syscall+0x1d0 + unix`0xfffffffffb800c91 + 16 + + unix`bcopy+0x330 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_vfslocks_getlock + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`bcopy+0x238 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_mountedvfs+0x8 + genunix`lookuppnvp+0x217 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`pn_get_buf+0x4b + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`splr+0xc + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 16 + + genunix`kmem_cache_alloc+0x8d + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0x92 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`fop_lookup+0x64 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_setpath+0x97 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_alloc+0xc8 + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`syscall_mstate+0xc + unix`0xfffffffffb800ca0 + 16 + + genunix`vn_setops+0x5f + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`bcmp + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_vfslocks_getlock+0x41 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`cv_broadcast+0x72 + genunix`rwst_exit+0x8f + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`fop_lookup+0x82 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`lo_lookup+0x198 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`lsave+0x61 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_setpath+0x1c2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + ufs`ufs_iaccess+0x137 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`sys_syscall+0x17d + 16 + + genunix`rwst_init+0x51 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`lookuppnvp+0x185 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vn_vfslocks_getlock+0x66 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_free+0x8 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0xe4 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`memcmp+0x17 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0xfc + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`atomic_add_32 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0x8 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0x8 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`mutex_enter + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vfs_getops+0x49 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`lookuppnvp+0xcb + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`lsave+0xc0 + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`mutex_destroy + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0x22 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`kmem_cache_alloc+0x26 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + ufs`ufs_iaccess+0xa2 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`fop_lookup+0x107 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + genunix`vsd_free+0x8 + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + lofs`lfind+0x5f + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 16 + + unix`mutex_exit+0x12 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`fop_lookup+0x16 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_setpath+0x14d + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`kmem_cache_alloc+0x4e + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`makelonode+0x1bf + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`kmem_free+0x17 + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`lo_lookup+0x138 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`dnlc_lookup + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_vfslocks_rele+0xc6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`lookuppnvp+0x327 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`fop_lookup+0x47 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`fop_inactive+0xab + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`lookuppnvp+0x32e + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`lo_lookup+0x60 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_exists + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`rwst_init+0x8 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`rwst_enter_common+0x1d8 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_exists+0x1d + lofs`makelonode+0x1e7 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`makelonode+0x17 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`dnlc_lookup+0x50 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_vfslocks_getlock+0x41 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`cv_init+0x22 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + unix`membar_consumer + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`makelonode+0x31 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_reinit+0x47 + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`syscall_mstate+0x41 + unix`sys_syscall+0x1a1 + 17 + + lofs`table_lock_enter+0x82 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_recycle+0x17 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`memcmp+0x8 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`secpolicy_vnode_access2+0x108 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_vfslocks_rele+0x29 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`rwst_exit+0x4c + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`rwst_destroy+0x8 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`lookuppnvp+0x1ac + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`fop_lookup+0xcd + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`lo_lookup+0x2e0 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + unix`mutex_enter + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + unix`mutex_enter + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`traverse+0x43 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`fop_lookup+0xe9 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`crgetmapped+0x2a + genunix`fop_lookup+0x1dc + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vn_recycle+0x65 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`kmem_cache_alloc+0x26 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`lsave+0xca + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`makelonode+0x9f + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`rwst_tryenter+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + unix`mutex_exit + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`kmem_cache_alloc+0x33 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vfs_matchops+0x17 + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + unix`mutex_exit+0xc + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + lofs`makelfsnode+0x6e + lofs`makelonode+0x192 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 17 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`vfs_matchops+0x23 + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`vsd_free+0x1f + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`lookuppnvp+0x205 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + unix`bcopy+0x1f + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`fop_lookup+0x135 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`fop_lookup+0x3f + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + lofs`lo_lookup+0x50 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + ufs`ufs_lookup+0x70 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`kmem_cache_alloc+0x89 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`dnlc_lookup+0x2a + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + lofs`lo_lookup+0x26b + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`cv_init+0x1 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`vn_mountedvfs+0x11 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`dnlc_lookup+0x32 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`fop_lookup+0x64 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`cv_init+0x8 + genunix`rwst_init+0x47 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + lofs`lo_lookup+0x79 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + ufs`ufs_iaccess+0x10c + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`lookuppnvp+0x15e + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`kmem_alloc+0xdf + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`post_syscall+0x211 + unix`0xfffffffffb800c91 + 18 + + genunix`fop_lookup+0x82 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`fop_lookup+0x8e + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`rwst_enter_common + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + unix`do_splx + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 18 + + unix`strlen + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`dnlc_lookup+0x7d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`fop_lookup+0xb0 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`fop_lookup+0xb6 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`rwst_enter_common+0x29 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`lookupnameat+0xc + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`vn_vfslocks_rele+0x46 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`pn_getcomponent + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`vn_vfslocks_getlock+0x90 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`vn_vfsrlock+0x3b + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`kmem_alloc+0x3b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`rwst_destroy+0x32 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`rwst_tryenter+0x9 + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`crgetmapped+0x2a + genunix`fop_lookup+0x1dc + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + lofs`makelonode+0x192 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`vn_alloc+0x35 + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + genunix`audit_getstate+0x2c + genunix`copen+0x59 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + lofs`makelonode+0x1af + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 18 + + unix`mutex_exit+0x12 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`vn_rele+0x24 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`dnlc_lookup+0x9 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`fop_lookup+0x3f + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`fop_lookup+0x43 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`dnlc_lookup+0x15 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + lofs`lo_lookup+0x25d + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`vn_vfslocks_rele+0xce + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`rw_enter+0x22 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`fop_lookup+0x55 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + lofs`makelonode + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`vn_mountedvfs+0x11 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`vn_vfslocks_rele+0x105 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`dnlc_lookup+0x160 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`membar_consumer + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`audit_unfalloc+0x1 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`fop_lookup+0x9f + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`audit_unfalloc+0x24 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`vn_reinit+0x67 + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + lofs`lo_lookup+0x1d4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`fop_lookup+0x1c8 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`crgetmapped+0x8 + genunix`fop_lookup+0x1dc + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`memcmp+0x30 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`clear_int_flag + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 19 + + genunix`crgetmapped+0x15 + genunix`fop_lookup+0x1dc + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + ufs`ufs_iaccess+0x7f + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`mutex_enter + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`mutex_init + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`rwst_tryenter+0x9 + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`i_ddi_splhigh+0x5 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 19 + + genunix`kmem_cache_alloc+0x26 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`tsc_gethrtimeunscaled+0xc + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 19 + + unix`copystr+0x60 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + unix`mutex_exit + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + ufs`ufs_lookup+0x38 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + lofs`lo_lookup+0x1a + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`traverse+0x6f + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 19 + + genunix`kmem_free + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`traverse+0x7c + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_setpath+0x4e + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_setops + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`fop_lookup+0x25 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + lofs`lo_lookup+0x3c + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_vfslocks_rele+0xb3 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_vfslocks_getlock + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`traverse+0xa8 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_recycle+0xbe + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_setpath+0x190 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + lofs`table_lock_enter+0x41 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + unix`mutex_destroy+0x7f + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + ufs`ufs_iaccess+0x11c + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`kmem_alloc+0xdf + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_setpath+0x1b0 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`dnlc_lookup+0x159 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`kmem_cache_free+0xf1 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`dnlc_lookup+0x65 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`cv_destroy+0xd + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`vn_vfslocks_rele+0x38 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`dnlc_lookup+0x198 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`crgetmapped+0x8 + genunix`fop_lookup+0x1dc + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`kmem_alloc+0x2a + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`crgetmapped+0x15 + genunix`fop_lookup+0x1dc + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`fop_lookup+0x1d7 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`rwst_tryenter + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + lofs`makelonode+0x92 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + unix`mutex_exit + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + genunix`dnlc_lookup+0xdf + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 20 + + ufs`ufs_lookup+0x40 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + lofs`lo_lookup+0x29 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`kmem_free+0xb + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`fop_lookup+0x126 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`kmem_free+0x17 + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`fop_lookup+0x13e + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + lofs`makelonode+0x1e7 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`vn_recycle+0xb9 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + ufs`ufs_lookup+0x80 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`vn_free+0x32 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + ufs`ufs_lookup+0x85 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`vn_setops+0x4a + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`crgetuid+0x8 + ufs`ufs_iaccess+0xe5 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + ufs`ufs_iaccess+0x33 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`dnlc_lookup+0x79 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + unix`strlen+0xb + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`vn_vfslocks_getlock+0x6e + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`rwst_destroy + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + unix`strlen+0x13 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + unix`strlen+0x13 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`crgetmapped + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + lofs`makelfsnode+0x26 + lofs`makelonode+0x192 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + unix`bcopy+0x3b8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`vfs_getops+0x28 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`dnlc_lookup+0x9d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`vn_recycle+0x41 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`rwst_enter_common+0x44 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`secpolicy_vnode_access2+0x38 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`kmem_cache_free+0x3a + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + lofs`lo_lookup+0x1ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`rwst_tryenter + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + unix`mutex_enter + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`fop_lookup+0x1f8 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + unix`mutex_destroy+0x17 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 21 + + genunix`syscall_mstate+0x1b2 + unix`sys_syscall+0x1a1 + 22 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + lofs`lo_lookup+0x40 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`fop_lookup+0x30 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`lookuppnvp+0x31a + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`disp_lock_exit+0x1b + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 22 + + genunix`dnlc_lookup+0x11 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`vn_setpath+0x83 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`pn_getcomponent+0x90 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + ufs`ufs_iaccess+0x8 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + lofs`lsave+0x3a + lofs`makelonode+0x1df + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`rwst_init+0x38 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`secpolicy_vnode_access2+0x1 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`kmem_cache_alloc+0xfc + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`dnlc_lookup+0xa0 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + ufs`ufs_lookup + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`fop_lookup+0x1d7 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`dnlc_lookup+0xa9 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + ufs`ufs_iaccess+0x7a + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + unix`mutex_enter + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + unix`mutex_enter + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + genunix`rwst_enter_common+0x15f + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + ufs`ufs_lookup+0x29 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + unix`mutex_exit + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 22 + + unix`mutex_exit+0x12 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + unix`mutex_exit+0x19 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`lookuppnvp+0x308 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`dnlc_lookup+0x11c + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`pn_getcomponent+0x89 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`lookuppnvp+0x13e + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`pn_getcomponent+0xab + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`rwst_enter_common + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`cv_destroy+0x1 + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + lofs`lo_lookup+0x1bf + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + unix`rw_exit+0x3 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`secpolicy_vnode_access2+0x29 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`kmem_cache_alloc + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`dnlc_lookup+0x1ad + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`kmem_cache_alloc+0x17 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`pn_getcomponent+0x18 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`fop_lookup+0x1eb + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`crgetmapped+0x2e + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`fsop_root + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + unix`mutex_exit + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + unix`mutex_exit+0x9 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 23 + + genunix`falloc+0x1 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`vn_alloc+0x42 + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + lofs`lo_lookup+0x126 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`traverse+0x7f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + unix`bcopy+0x1b + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`vn_vfsunlock+0x35 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + ufs`ufs_iaccess+0xd8 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + ufs`ufs_iaccess+0x1 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`fop_lookup+0x73 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + ufs`ufs_lookup+0xb7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + lofs`lo_lookup+0x9d + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`pn_getcomponent+0xc1 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`syscall_mstate+0x139 + unix`sys_syscall+0x1a1 + 24 + + genunix`dnlc_lookup+0x175 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`fop_lookup+0xc2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`secpolicy_vnode_access2+0x226 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`fop_lookup+0xcb + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`dnlc_lookup+0x1a8 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + unix`copystr+0x45 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + zfs`zfs_lookup+0x88 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`fop_lookup+0xb + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 24 + + genunix`dnlc_lookup+0xeb + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`fop_lookup+0x1d + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`fop_lookup+0x2c + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`secpolicy_vnode_access2+0xa0 + ufs`ufs_iaccess+0x128 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`fop_lookup+0x5a + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`cv_init+0x22 + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + lofs`lo_lookup+0x1a4 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`post_syscall+0x22d + unix`0xfffffffffb800c91 + 25 + + genunix`lookupnameat + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`unfalloc+0x1 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + unix`strlen+0x16 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + ufs`ufs_lookup+0xe9 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + unix`mutex_enter + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`lookuppnvp+0x1c5 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`fop_lookup+0x1eb + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`vn_setpath+0x12b + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + unix`mutex_exit + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + unix`mutex_exit + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`vn_setpath+0x137 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + genunix`audit_getstate+0x2c + genunix`setf+0x3f + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 25 + + lofs`table_lock_enter + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`fop_lookup+0x3b + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`fop_lookup+0x13e + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`kmem_free+0x3a + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`cv_init + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`fop_inactive+0xc2 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`rwst_exit+0x8 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + lofs`lo_lookup+0x8f + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + unix`prunstop+0x1b + genunix`post_syscall+0x2d0 + unix`0xfffffffffb800c91 + 26 + + unix`bcmp+0xf + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + lofs`lo_lookup+0xa1 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`cv_destroy+0xd + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + ufs`ufs_iaccess+0x59 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`kmem_cache_alloc + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`dnlc_lookup+0xbe + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + unix`mutex_exit + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + unix`mutex_exit + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + lofs`lo_lookup+0x118 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 26 + + genunix`dnlc_lookup+0x149 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + ufs`ufs_iaccess+0x141 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + unix`bcopy+0x3b4 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + unix`rw_exit+0x24 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + genunix`thread_lock+0x1 + unix`0xfffffffffb800c91 + 27 + + unix`mutex_exit+0xc + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + genunix`lookuppnvp+0x1ed + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 27 + + unix`strlen + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + unix`strlen+0xb + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + genunix`vn_setpath+0xc + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + genunix`kmem_cache_alloc+0x10 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + genunix`fd_find+0x58 + genunix`ufalloc_file+0x91 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + genunix`fop_lookup+0x1 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 28 + + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 29 + + genunix`fop_lookup+0x37 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 29 + + unix`bcopy+0x234 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 29 + + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 29 + + genunix`fop_lookup+0x5e + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 29 + + genunix`rwst_enter_common+0x44 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 29 + + unix`tsc_gethrtimeunscaled+0x1 + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 29 + + genunix`syscall_mstate+0x1a1 + unix`sys_syscall+0x1a1 + 29 + + unix`mutex_exit+0xc + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 29 + + lofs`lo_lookup+0x133 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + unix`bcopy+0x32c + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + genunix`fop_inactive+0xc2 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + genunix`clear_stale_fd+0x46 + genunix`post_syscall+0x1fe + unix`0xfffffffffb800c91 + 30 + + genunix`vn_vfslocks_rele + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + genunix`syscall_mstate+0x14d + unix`0xfffffffffb800ca0 + 30 + + unix`rw_exit + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + genunix`rwst_enter_common+0x40 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + unix`mutex_enter + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + unix`mutex_exit + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 30 + + genunix`post_syscall+0x29a + unix`0xfffffffffb800c91 + 30 + + lofs`lo_lookup+0x38 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 31 + + unix`rw_enter+0x9 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 31 + + unix`splr + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 31 + + genunix`fop_lookup+0xc2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 31 + + genunix`memcmp+0x23 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 31 + + unix`mutex_init + genunix`vn_vfslocks_getlock+0xb0 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 31 + + lofs`lo_lookup + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 31 + + genunix`fop_lookup + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 31 + + unix`bcopy+0x17 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 32 + + genunix`pn_getcomponent+0x73 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 32 + + genunix`pn_getcomponent+0x81 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 32 + + unix`bcopy+0x38c + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 32 + + genunix`crgetmapped + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 32 + + ufs`ufs_lookup+0xfa + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 32 + + genunix`dnlc_lookup+0xd0 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 32 + + ufs`ufs_lookup+0x44 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 33 + + genunix`post_syscall+0x2b9 + unix`0xfffffffffb800c91 + 33 + + genunix`dnlc_lookup+0x75 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 33 + + ufs`ufs_iaccess+0x89 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 33 + + genunix`fsop_root+0x1 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 33 + + genunix`kmem_free + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + genunix`fop_lookup+0x113 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + lofs`lo_root+0x1f + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + genunix`fop_lookup+0x5e + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + lofs`table_lock_enter+0x41 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + genunix`dnlc_lookup+0x99 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + unix`clear_int_flag+0x2 + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 34 + + lofs`lfind+0x40 + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + genunix`lookuppnvp+0x1db + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + genunix`fop_lookup + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 34 + + lofs`lo_lookup+0x58 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 35 + + genunix`memcmp + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 35 + + unix`strlen+0xe + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 35 + + unix`mutex_enter + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 35 + + genunix`fop_lookup+0x1ff + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 35 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 35 + + genunix`vn_setpath+0x6b + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 36 + + genunix`vn_setpath+0x9e + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 36 + + unix`membar_consumer+0x3 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 36 + + genunix`secpolicy_vnode_access2 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 36 + + unix`copystr+0x39 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 36 + + unix`mutex_exit + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 36 + + genunix`vn_mountedvfs + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 37 + + unix`mutex_enter+0x9 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 37 + + genunix`vn_reinit+0x7c + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 38 + + unix`mutex_exit+0xc + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 38 + + unix`mutex_exit+0xc + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 38 + + genunix`lookupnameat+0x1 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 39 + + unix`mutex_exit + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 39 + + genunix`pn_getcomponent+0x9e + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 40 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 40 + + unix`bcopy + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 41 + + unix`mutex_exit+0x12 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 41 + + unix`mutex_exit+0x12 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 41 + + genunix`dnlc_lookup + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 41 + + genunix`syscall_mstate+0x1 + 41 + + unix`bcopy+0x2cd + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 41 + + unix`bcopy+0x2fc + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 41 + + unix`0xfffffffffb800c7c + 42 + + genunix`dnlc_lookup+0x5f + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 42 + + genunix`cv_destroy + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 42 + + genunix`audit_getstate+0x1 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 42 + + unix`copystr+0x52 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 42 + + unix`mutex_exit+0xc + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 42 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 43 + + genunix`syscall_mstate + 43 + + genunix`vn_setpath+0xe7 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 43 + + unix`mutex_exit+0xc + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 43 + + unix`mutex_exit+0xc + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 43 + + genunix`vn_setpath + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 44 + + unix`mutex_exit+0xc + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 44 + + genunix`dnlc_lookup+0x6b + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 45 + + genunix`kmem_alloc + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 45 + + genunix`fop_lookup+0x1dc + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 46 + + unix`mutex_enter + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 46 + + genunix`dnlc_lookup+0x53 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 47 + + genunix`vn_rele + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 47 + + unix`mutex_exit+0xc + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 47 + + unix`mutex_exit+0xc + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 47 + + unix`mutex_exit+0xc + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 47 + + unix`mutex_exit+0x12 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 48 + + unix`rw_enter+0x14 + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 48 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 49 + + unix`mutex_exit+0xc + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 49 + + unix`atomic_cas_64 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 50 + + unix`mutex_exit+0xc + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 50 + + ufs`ufs_iaccess + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 51 + + unix`strlen+0x8 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 51 + + unix`strlen+0xb + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 52 + + genunix`vn_setpath+0xee + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 52 + + unix`mutex_enter + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 52 + + unix`mutex_exit+0xc + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 52 + + unix`mutex_exit+0x12 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 53 + + genunix`vn_setpath+0x6f + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 53 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 53 + + unix`rw_enter + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 55 + + unix`mutex_exit+0xc + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 55 + + genunix`vn_setpath+0x126 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 56 + + genunix`kmem_free + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 57 + + unix`splr+0x1 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 57 + + genunix`dnlc_lookup+0x62 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 57 + + lofs`table_lock_enter+0x41 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 58 + + genunix`syscall_mstate+0x14d + unix`sys_syscall+0x10e + 58 + + unix`mutex_exit+0x12 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 59 + + unix`mutex_exit+0x12 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 59 + + genunix`vsd_free+0xc + genunix`vn_recycle+0xb5 + genunix`vn_reinit+0x7b + genunix`vn_alloc+0x3e + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 59 + + unix`bcopy+0x388 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 60 + + genunix`kmem_alloc+0x17 + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 60 + + unix`bcopy+0x3b0 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 60 + + unix`mutex_exit+0xc + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 61 + + unix`mutex_exit+0xc + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 61 + + unix`membar_consumer+0x3 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 62 + + unix`mutex_enter + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 62 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 64 + + unix`strlen+0x10 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 64 + + unix`bcopy+0x328 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 66 + + genunix`dnlc_lookup+0x6e + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 66 + + lofs`lo_lookup+0x279 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 67 + + genunix`vn_setpath+0x76 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 69 + + genunix`vn_setops+0x2b + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 69 + + genunix`vn_openat+0x7b + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 69 + + genunix`dnlc_lookup+0x69 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 69 + + unix`mutex_exit+0xc + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 69 + + unix`strlen+0xe + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 71 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 71 + + genunix`vfs_getops+0x20 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 72 + + unix`bcopy+0x2c8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 72 + + unix`mutex_exit+0x12 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 74 + + unix`bcopy+0x230 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 74 + + unix`bcopy+0x2f8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 74 + + unix`mutex_enter+0x10 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 75 + + genunix`vn_setpath+0x15a + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 76 + + unix`mutex_exit+0xc + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 77 + + unix`mutex_exit+0xc + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 77 + + genunix`vn_setpath+0x199 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 78 + + genunix`fop_lookup+0xf8 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 78 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 79 + + genunix`memcmp+0x20 + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 80 + + unix`mutex_enter+0x10 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 82 + + genunix`memcmp+0x2c + unix`bcmp+0x9 + genunix`dnlc_lookup+0x10d + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 87 + + unix`mutex_enter+0x10 + genunix`lookuppnvp+0x39f + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 87 + + unix`atomic_add_64+0x4 + unix`0xfffffffffb800ca0 + 90 + + unix`mutex_enter+0x10 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 90 + + unix`mutex_enter+0x10 + genunix`unfalloc+0x61 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 91 + + unix`mutex_enter+0x10 + genunix`traverse+0x9f + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 91 + + unix`mutex_enter+0x10 + genunix`fsop_root+0x2d + genunix`traverse+0x87 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 92 + + unix`mutex_enter+0x10 + zfs`zfs_lookup+0xc2 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 92 + + unix`mutex_exit + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 92 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 93 + + unix`mutex_enter+0x10 + genunix`falloc+0x63 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 93 + + unix`mutex_enter+0x10 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 93 + + unix`mutex_enter+0x10 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 93 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 94 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 94 + + unix`mutex_exit+0x12 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 95 + + unix`mutex_enter+0x10 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 95 + + unix`mutex_enter+0x10 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 95 + + unix`mutex_enter+0x10 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 96 + + unix`atomic_add_32_nv+0x6 + genunix`unfalloc+0x4a + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 97 + + unix`atomic_add_64+0x4 + unix`sys_syscall+0x1a1 + 97 + + unix`mutex_exit+0xc + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 97 + + unix`atomic_add_64+0x4 + unix`sys_syscall+0x10e + 98 + + unix`mutex_exit+0xc + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 99 + + unix`mutex_exit+0x12 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 100 + + unix`membar_consumer+0x3 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 100 + + unix`atomic_add_64+0x4 + unix`0xfffffffffb800c86 + 100 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 101 + + unix`mutex_destroy+0x74 + genunix`rwst_destroy+0x1c + genunix`vn_vfslocks_rele+0xd6 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 102 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 102 + + unix`atomic_add_32+0x3 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 105 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 105 + + unix`mutex_exit+0xc + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 105 + + unix`membar_consumer+0x3 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 106 + + unix`membar_consumer+0x3 + genunix`vfs_matchops+0x1c + lofs`lo_lookup+0x1e6 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 106 + + unix`mutex_exit+0xc + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 106 + + unix`mutex_exit+0xc + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 107 + + unix`mutex_enter+0x10 + ufs`ufs_lookup+0x36d + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 108 + + unix`mutex_exit+0xc + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 108 + + unix`mutex_enter+0x10 + genunix`kmem_free+0x4e + genunix`audit_unfalloc+0x44 + genunix`unfalloc+0x41 + genunix`copen+0x4f3 + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 109 + + genunix`pn_getcomponent+0xa8 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 110 + + unix`mutex_enter+0x10 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 111 + + genunix`dnlc_lookup+0x5c + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 114 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0x92 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 114 + + unix`mutex_enter+0x10 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 114 + + unix`mutex_exit+0xc + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 114 + + genunix`dnlc_lookup+0xe5 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 115 + + genunix`pn_getcomponent+0xb3 + genunix`lookuppnvp+0x16d + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 116 + + genunix`rwst_enter_common+0x40 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 116 + + unix`mutex_enter+0x10 + genunix`kmem_zalloc+0x47 + genunix`audit_falloc+0x1f + genunix`falloc+0xf8 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 121 + + unix`mutex_exit+0xc + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 123 + + unix`mutex_exit+0x12 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 124 + + unix`mutex_exit+0xc + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 126 + + unix`atomic_add_32+0x3 + genunix`falloc+0xbc + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 129 + + unix`tsc_read+0x3 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800ca0 + 145 + + unix`strlen+0x13 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 146 + + genunix`fop_lookup+0x113 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 154 + + unix`clear_int_flag+0x2 + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 157 + + unix`tsc_read+0x3 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x1a1 + 163 + + unix`copystr+0x34 + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 164 + + unix`mutex_exit+0xc + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 168 + + unix`tsc_read+0x3 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`0xfffffffffb800c86 + 169 + + unix`mutex_enter+0x10 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 169 + + lofs`lfind+0x38 + lofs`makelonode+0x47 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 171 + + unix`mutex_exit+0xc + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 172 + + unix`atomic_add_32+0x3 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 174 + + unix`mutex_enter+0x10 + lofs`freelonode+0x47 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 174 + + unix`mutex_exit+0xc + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 178 + + unix`tsc_read+0x3 + genunix`gethrtime_unscaled+0xa + genunix`syscall_mstate+0x5d + unix`sys_syscall+0x10e + 180 + + unix`mutex_enter+0x10 + lofs`freelonode+0x1fe + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 186 + + genunix`fop_lookup+0xf8 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 188 + + genunix`dnlc_lookup+0x50 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 190 + + unix`mutex_enter+0x10 + genunix`vn_free+0x9a + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 190 + + unix`mutex_enter+0x10 + genunix`ufalloc+0x13 + genunix`falloc+0x43 + genunix`copen+0x1ab + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 191 + + unix`mutex_enter+0x10 + genunix`kmem_free+0x4e + genunix`vn_free+0x37 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 193 + + unix`mutex_enter+0x10 + lofs`freelonode+0x1ed + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 196 + + unix`mutex_enter+0x10 + genunix`copen+0x4ea + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 196 + + unix`mutex_enter+0x10 + zfs`zfs_lookup+0xaa + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 201 + + unix`mutex_exit+0xc + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 210 + + unix`mutex_enter+0x10 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 233 + + unix`mutex_enter+0x10 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 237 + + unix`mutex_exit+0xc + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 258 + + unix`copystr+0x3e + genunix`pn_get_buf+0x43 + genunix`lookupnameatcred+0x69 + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 261 + + unix`atomic_cas_64+0x8 + lofs`makelonode+0x1c4 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 268 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 279 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x28 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 280 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x20 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 286 + + unix`mutex_enter+0x10 + genunix`vn_vfsunlock+0x15 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 290 + + unix`mutex_enter+0x10 + genunix`vn_alloc+0x1a + lofs`makelonode+0xb6 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 293 + + unix`mutex_enter+0x10 + lofs`makelonode+0x36 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 298 + + unix`mutex_enter+0x10 + lofs`makelonode+0xa9 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 298 + + unix`mutex_enter+0x10 + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 301 + + unix`mutex_enter+0x10 + genunix`rwst_tryenter+0x1a + genunix`vn_vfsrlock+0x2f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 305 + + unix`mutex_enter+0x10 + genunix`kmem_free+0x4e + genunix`vn_vfslocks_rele+0xe3 + genunix`vn_vfsunlock+0x30 + genunix`traverse+0xb3 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 308 + + unix`atomic_add_32+0x3 + lofs`lo_lookup+0x268 + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 309 + + unix`mutex_enter+0x10 + genunix`kmem_alloc+0x4b + genunix`vn_setpath+0xc2 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 318 + + unix`strlen+0x10 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 327 + + genunix`syscall_mstate+0x14d + unix`sys_syscall+0x1a1 + 330 + + unix`rw_exit+0xf + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 348 + + unix`mutex_enter+0x10 + genunix`kmem_alloc+0x4b + genunix`vn_vfslocks_getlock+0x9c + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 349 + + unix`rw_enter+0x2b + ufs`ufs_lookup+0xc7 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 355 + + unix`splr+0x6a + genunix`thread_lock+0x24 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 361 + + unix`mutex_enter+0x10 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 372 + + unix`strlen+0x8 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x387 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 407 + + unix`mutex_enter+0x10 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + genunix`lookuppnvp+0x229 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 420 + + unix`strlen+0x8 + lofs`freelonode+0x1f5 + lofs`lo_inactive+0x1d + genunix`fop_inactive+0x76 + genunix`vn_rele+0x82 + genunix`lookuppnvp+0x33b + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 534 + + unix`strlen+0xe + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 562 + + unix`sys_syscall+0xff + 565 + + unix`mutex_enter+0x10 + genunix`vn_vfsrlock+0x1f + genunix`traverse+0x30 + lofs`lo_lookup+0x2ee + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 673 + + unix`lock_try+0x8 + genunix`post_syscall+0x2e4 + unix`0xfffffffffb800c91 + 774 + + unix`mutex_enter+0x10 + ufs`ufs_lookup+0xa6 + genunix`fop_lookup+0xa2 + lofs`lo_lookup+0xbc + genunix`fop_lookup+0xa2 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 816 + + unix`mutex_enter+0x10 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 884 + + unix`strlen+0x8 + genunix`fop_lookup+0x210 + genunix`lookuppnvp+0x1f6 + genunix`lookuppnatcred+0x15e + genunix`lookupnameatcred+0xad + genunix`lookupnameat+0x39 + genunix`vn_openat+0x315 + genunix`copen+0x20c + genunix`openat+0x2a + genunix`open+0x25 + unix`sys_syscall+0x17a + 1535 + + unix`do_splx+0x65 + genunix`disp_lock_exit+0x47 + genunix`post_syscall+0x318 + unix`0xfffffffffb800c91 + 1971 diff --git a/tests/benchmarks/_script/flamegraph/example-dtrace.svg b/tests/benchmarks/_script/flamegraph/example-dtrace.svg new file mode 100644 index 00000000000..6702dc8b38f --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/example-dtrace.svg @@ -0,0 +1,1842 @@ + + + + + + + + + + + + + +Flame Graph + +Reset Zoom +Search + +unix`mutex_enter (195 samples, 0.34%) + + + +genunix`as_fault (12 samples, 0.02%) + + + +genunix`disp_lock_exit (27 samples, 0.05%) + + + +genunix`vsd_free (17 samples, 0.03%) + + + +genunix`pn_fixslash (44 samples, 0.08%) + + + +unix`mutex_exit (105 samples, 0.18%) + + + +genunix`falloc (1,363 samples, 2.37%) +g.. + + +genunix`traverse (30 samples, 0.05%) + + + +genunix`fop_lookup (55 samples, 0.10%) + + + +genunix`kmem_cache_free (29 samples, 0.05%) + + + +lofs`makelonode (39 samples, 0.07%) + + + +genunix`vsd_free (155 samples, 0.27%) + + + +unix`strlen (2,659 samples, 4.63%) +unix`.. + + +unix`clear_int_flag (180 samples, 0.31%) + + + +unix`mutex_exit (38 samples, 0.07%) + + + +genunix`kmem_cpu_reload (5 samples, 0.01%) + + + +unix`mutex_exit (26 samples, 0.05%) + + + +genunix`vn_vfslocks_getlock (47 samples, 0.08%) + + + +unix`bzero (8 samples, 0.01%) + + + +genunix`vn_exists (50 samples, 0.09%) + + + +unix`mutex_enter (727 samples, 1.27%) + + + +genunix`kmem_cache_alloc (179 samples, 0.31%) + + + +unix`mutex_enter (905 samples, 1.58%) + + + +genunix`ufalloc (10 samples, 0.02%) + + + +genunix`vn_rele (25 samples, 0.04%) + + + +genunix`vn_exists (17 samples, 0.03%) + + + +unix`lock_try (778 samples, 1.35%) + + + +genunix`rwst_enter_common (314 samples, 0.55%) + + + +genunix`fsop_root (62 samples, 0.11%) + + + +lofs`table_lock_enter (44 samples, 0.08%) + + + +unix`mutex_exit (138 samples, 0.24%) + + + +unix`mutex_enter (316 samples, 0.55%) + + + +genunix`kmem_cache_free (5 samples, 0.01%) + + + +unix`preempt (14 samples, 0.02%) + + + +genunix`vn_alloc (1,189 samples, 2.07%) +g.. + + +genunix`kmem_cache_alloc (126 samples, 0.22%) + + + +genunix`vfs_getops (157 samples, 0.27%) + + + +lofs`lsave (27 samples, 0.05%) + + + +unix`tsc_read (160 samples, 0.28%) + + + +lofs`lfind (26 samples, 0.05%) + + + +unix`atomic_add_64 (205 samples, 0.36%) + + + +unix`mutex_enter (320 samples, 0.56%) + + + +genunix`traverse (17 samples, 0.03%) + + + +unix`mutex_enter (197 samples, 0.34%) + + + +genunix`vn_mountedvfs (20 samples, 0.03%) + + + +genunix`audit_unfalloc (340 samples, 0.59%) + + + +genunix`kmem_cache_free (209 samples, 0.36%) + + + +genunix`kmem_zalloc (13 samples, 0.02%) + + + +genunix`thread_lock (33 samples, 0.06%) + + + +unix`tsc_read (186 samples, 0.32%) + + + +genunix`vn_vfsrlock (12 samples, 0.02%) + + + +lofs`lo_inactive (21 samples, 0.04%) + + + +genunix`rwst_destroy (20 samples, 0.03%) + + + +unix`mutex_enter (379 samples, 0.66%) + + + +genunix`vn_setops (41 samples, 0.07%) + + + +genunix`vn_recycle (33 samples, 0.06%) + + + +lofs`lo_inactive (6,307 samples, 10.98%) +lofs`lo_inactive + + +lofs`table_lock_enter (220 samples, 0.38%) + + + +genunix`cv_broadcast (25 samples, 0.04%) + + + +unix`mutex_exit (358 samples, 0.62%) + + + +genunix`kmem_cache_alloc (234 samples, 0.41%) + + + +unix`rw_enter (525 samples, 0.91%) + + + +unix`membar_consumer (237 samples, 0.41%) + + + +unix`swtch (5 samples, 0.01%) + + + +genunix`rwst_enter_common (32 samples, 0.06%) + + + +lofs`freelonode (5,313 samples, 9.25%) +lofs`freelonode + + +genunix`vn_openat (46,342 samples, 80.68%) +genunix`vn_openat + + +genunix`vn_rele (19 samples, 0.03%) + + + +genunix`proc_exit (5 samples, 0.01%) + + + +unix`mutex_exit (512 samples, 0.89%) + + + +genunix`kmem_free (35 samples, 0.06%) + + + +unix`mutex_enter (252 samples, 0.44%) + + + +genunix`rwst_exit (12 samples, 0.02%) + + + +genunix`crgetuid (22 samples, 0.04%) + + + +genunix`kmem_free (17 samples, 0.03%) + + + +unix`mutex_init (53 samples, 0.09%) + + + +ufs`ufs_iaccess (648 samples, 1.13%) + + + +all (57,441 samples, 100%) + + + +genunix`fop_inactive (6,689 samples, 11.64%) +genunix`fop_inact.. + + +genunix`kmem_cache_alloc (9 samples, 0.02%) + + + +genunix`kmem_cache_free (184 samples, 0.32%) + + + +genunix`pn_get_buf (13 samples, 0.02%) + + + +unix`strlen (107 samples, 0.19%) + + + +unix`mutex_exit (46 samples, 0.08%) + + + +genunix`post_syscall (12 samples, 0.02%) + + + +unix`mutex_init (38 samples, 0.07%) + + + +unix`rw_exit (439 samples, 0.76%) + + + +lofs`lo_lookup (65 samples, 0.11%) + + + +genunix`clear_stale_fd (44 samples, 0.08%) + + + +unix`mutex_enter (238 samples, 0.41%) + + + +genunix`pn_get_buf (687 samples, 1.20%) + + + +genunix`vn_free (1,663 samples, 2.90%) +ge.. + + +unix`mutex_enter (980 samples, 1.71%) + + + +genunix`crhold (5 samples, 0.01%) + + + +unix`mutex_exit (59 samples, 0.10%) + + + +genunix`vn_reinit (48 samples, 0.08%) + + + +genunix`vfs_getops (21 samples, 0.04%) + + + +genunix`open (49,669 samples, 86.47%) +genunix`open + + +genunix`kmem_cache_alloc (39 samples, 0.07%) + + + +genunix`vn_vfslocks_getlock (79 samples, 0.14%) + + + +unix`clear_int_flag (39 samples, 0.07%) + + + +genunix`kmem_cache_free (215 samples, 0.37%) + + + +unix`mutex_destroy (53 samples, 0.09%) + + + +genunix`vn_vfsunlock (3,578 samples, 6.23%) +genunix`.. + + +genunix`dnlc_lookup (1,843 samples, 3.21%) +gen.. + + +genunix`lookupnameatcred (45,978 samples, 80.04%) +genunix`lookupnameatcred + + +genunix`crgetmapped (41 samples, 0.07%) + + + +genunix`anon_zero (7 samples, 0.01%) + + + +genunix`rwst_tryenter (628 samples, 1.09%) + + + +unix`mutex_enter (309 samples, 0.54%) + + + +genunix`vn_rele (14 samples, 0.02%) + + + +genunix`vn_setpath (1,969 samples, 3.43%) +gen.. + + +unix`mutex_enter (111 samples, 0.19%) + + + +genunix`cv_broadcast (40 samples, 0.07%) + + + +genunix`kmem_cache_alloc (66 samples, 0.11%) + + + +genunix`audit_getstate (21 samples, 0.04%) + + + +genunix`vn_setpath (58 samples, 0.10%) + + + +genunix`open (17 samples, 0.03%) + + + +unix`bcopy (896 samples, 1.56%) + + + +unix`mutex_enter (99 samples, 0.17%) + + + +genunix`traverse (5,557 samples, 9.67%) +genunix`traverse + + +genunix`pn_getcomponent (41 samples, 0.07%) + + + +unix`mutex_enter (640 samples, 1.11%) + + + +unix`mutex_destroy (176 samples, 0.31%) + + + +unix`lwp_getdatamodel (6 samples, 0.01%) + + + +genunix`unfalloc (39 samples, 0.07%) + + + +genunix`syscall_mstate (355 samples, 0.62%) + + + +genunix`cv_init (65 samples, 0.11%) + + + +unix`mutex_enter (95 samples, 0.17%) + + + +unix`bcmp (42 samples, 0.07%) + + + +unix`mutex_exit (350 samples, 0.61%) + + + +genunix`kmem_free (288 samples, 0.50%) + + + +unix`mutex_exit (58 samples, 0.10%) + + + +genunix`kmem_alloc (32 samples, 0.06%) + + + +unix`mutex_exit (356 samples, 0.62%) + + + +unix`mutex_init (46 samples, 0.08%) + + + +genunix`rwst_init (173 samples, 0.30%) + + + +genunix`rwst_enter_common (28 samples, 0.05%) + + + +genunix`openat (49,647 samples, 86.43%) +genunix`openat + + +unix`mutex_enter (303 samples, 0.53%) + + + +lofs`lfind (278 samples, 0.48%) + + + +unix`mutex_exit (90 samples, 0.16%) + + + +genunix`cv_init (49 samples, 0.09%) + + + +unix`tsc_gethrtimeunscaled (43 samples, 0.07%) + + + +genunix`rwst_tryenter (32 samples, 0.06%) + + + +genunix`pn_fixslash (14 samples, 0.02%) + + + +genunix`gethrtime_unscaled (420 samples, 0.73%) + + + +genunix`post_syscall (4,245 samples, 7.39%) +genunix`po.. + + +genunix`kmem_zalloc (280 samples, 0.49%) + + + +genunix`vn_alloc (20 samples, 0.03%) + + + +genunix`vn_mountedvfs (43 samples, 0.07%) + + + +genunix`audit_getstate (15 samples, 0.03%) + + + +zfs`zfs_lookup (22 samples, 0.04%) + + + +genunix`crgetuid (6 samples, 0.01%) + + + +unix`copystr (598 samples, 1.04%) + + + +unix`i_ddi_splhigh (23 samples, 0.04%) + + + +unix`trap (13 samples, 0.02%) + + + +genunix`audit_getstate (27 samples, 0.05%) + + + +genunix`vn_mountedvfs (56 samples, 0.10%) + + + +unix`mutex_destroy (17 samples, 0.03%) + + + +genunix`cv_broadcast (14 samples, 0.02%) + + + +genunix`segvn_fault (11 samples, 0.02%) + + + +genunix`vn_rele (39 samples, 0.07%) + + + +genunix`kmem_free (457 samples, 0.80%) + + + +genunix`vn_vfsunlock (20 samples, 0.03%) + + + +genunix`vn_vfslocks_rele (34 samples, 0.06%) + + + +unix`atomic_cas_64 (318 samples, 0.55%) + + + +unix`mutex_enter (337 samples, 0.59%) + + + +unix`do_splx (31 samples, 0.05%) + + + +genunix`ufalloc_file (20 samples, 0.03%) + + + +genunix`fd_reserve (35 samples, 0.06%) + + + +genunix`copen (49,444 samples, 86.08%) +genunix`copen + + +unix`mutex_enter (279 samples, 0.49%) + + + +unix`0xfffffffffb800c91 (4,361 samples, 7.59%) +unix`0xfff.. + + +genunix`crgetmapped (55 samples, 0.10%) + + + +genunix`cv_init (56 samples, 0.10%) + + + +genunix`dnlc_lookup (26 samples, 0.05%) + + + +genunix`kmem_alloc (11 samples, 0.02%) + + + +genunix`cv_init (53 samples, 0.09%) + + + +unix`copyinstr (25 samples, 0.04%) + + + +genunix`gethrtime_unscaled (203 samples, 0.35%) + + + +genunix`kmem_cache_alloc (11 samples, 0.02%) + + + +genunix`vn_free (26 samples, 0.05%) + + + +unix`mutex_exit (149 samples, 0.26%) + + + +genunix`vn_recycle (319 samples, 0.56%) + + + +genunix`vn_rele (64 samples, 0.11%) + + + +unix`bcmp (11 samples, 0.02%) + + + +genunix`kmem_cache_free (154 samples, 0.27%) + + + +unix`lock_clear_splx (28 samples, 0.05%) + + + +genunix`unfalloc (729 samples, 1.27%) + + + +genunix`fop_lookup (85 samples, 0.15%) + + + +zfs`specvp_check (10 samples, 0.02%) + + + +genunix`lookupnameatcred (22 samples, 0.04%) + + + +unix`tsc_read (367 samples, 0.64%) + + + +genunix`memcmp (38 samples, 0.07%) + + + +unix`splx (6 samples, 0.01%) + + + +unix`mutex_exit (95 samples, 0.17%) + + + +genunix`gethrtime_unscaled (7 samples, 0.01%) + + + +genunix`rwst_init (13 samples, 0.02%) + + + +genunix`audit_getstate (31 samples, 0.05%) + + + +genunix`kmem_cache_alloc (32 samples, 0.06%) + + + +genunix`disp_lock_exit (2,096 samples, 3.65%) +genu.. + + +unix`mutex_exit (49 samples, 0.09%) + + + +unix`copyinstr (18 samples, 0.03%) + + + +ufs`ufs_lookup (46 samples, 0.08%) + + + +genunix`clear_stale_fd (10 samples, 0.02%) + + + +genunix`rwst_destroy (296 samples, 0.52%) + + + +genunix`syscall_mstate (1,336 samples, 2.33%) +g.. + + +genunix`kmem_alloc (934 samples, 1.63%) + + + +unix`atomic_add_32 (325 samples, 0.57%) + + + +unix`mutex_enter (947 samples, 1.65%) + + + +unix`mutex_exit (56 samples, 0.10%) + + + +unix`mutex_enter (318 samples, 0.55%) + + + +lofs`lo_root (80 samples, 0.14%) + + + +genunix`lookuppnvp (44,242 samples, 77.02%) +genunix`lookuppnvp + + +genunix`lookupnameat (46,075 samples, 80.21%) +genunix`lookupnameat + + +unix`setbackdq (5 samples, 0.01%) + + + +lofs`lo_root (31 samples, 0.05%) + + + +genunix`kmem_cache_alloc (17 samples, 0.03%) + + + +unix`mutex_exit (212 samples, 0.37%) + + + +genunix`vn_vfsrlock (2,414 samples, 4.20%) +genun.. + + +genunix`vfs_matchops (28 samples, 0.05%) + + + +unix`prunstop (36 samples, 0.06%) + + + +unix`mutex_exit (155 samples, 0.27%) + + + +unix`mutex_init (31 samples, 0.05%) + + + +unix`atomic_add_32_nv (100 samples, 0.17%) + + + +genunix`lookupnameat (69 samples, 0.12%) + + + +unix`_sys_rtt (6 samples, 0.01%) + + + +genunix`kmem_cache_alloc (49 samples, 0.09%) + + + +unix`tsc_gethrtimeunscaled (17 samples, 0.03%) + + + +genunix`fop_lookup (29,216 samples, 50.86%) +genunix`fop_lookup + + +unix`mutex_exit (142 samples, 0.25%) + + + +genunix`crgetmapped (31 samples, 0.05%) + + + +unix`do_splx (1,993 samples, 3.47%) +uni.. + + +genunix`kmem_cache_free (22 samples, 0.04%) + + + +unix`mutex_enter (95 samples, 0.17%) + + + +genunix`crhold (11 samples, 0.02%) + + + +unix`mutex_enter (823 samples, 1.43%) + + + +unix`mutex_exit (29 samples, 0.05%) + + + +genunix`vn_vfsrlock (3,342 samples, 5.82%) +genunix.. + + +unix`tsc_gethrtimeunscaled (13 samples, 0.02%) + + + +genunix`vn_rele (73 samples, 0.13%) + + + +unix`mutex_exit (337 samples, 0.59%) + + + +genunix`vn_vfslocks_getlock (973 samples, 1.69%) + + + +zfs`specvp_check (20 samples, 0.03%) + + + +genunix`vsd_free (14 samples, 0.02%) + + + +unix`mutex_enter (314 samples, 0.55%) + + + +genunix`cv_destroy (81 samples, 0.14%) + + + +genunix`cv_broadcast (25 samples, 0.04%) + + + +unix`mutex_enter (122 samples, 0.21%) + + + +unix`mutex_exit (55 samples, 0.10%) + + + +genunix`set_errno (24 samples, 0.04%) + + + +genunix`cv_destroy (42 samples, 0.07%) + + + +genunix`fd_find (13 samples, 0.02%) + + + +genunix`vn_invalid (47 samples, 0.08%) + + + +genunix`vfs_matchops (336 samples, 0.58%) + + + +unix`tsc_gethrtimeunscaled (59 samples, 0.10%) + + + +genunix`fop_inactive (39 samples, 0.07%) + + + +genunix`kmem_free (693 samples, 1.21%) + + + +genunix`syscall_mstate (412 samples, 0.72%) + + + +genunix`thread_lock (670 samples, 1.17%) + + + +lofs`lsave (162 samples, 0.28%) + + + +unix`atomic_add_64 (95 samples, 0.17%) + + + +genunix`audit_getstate (66 samples, 0.11%) + + + +genunix`dnlc_lookup (70 samples, 0.12%) + + + +genunix`vn_mountedvfs (30 samples, 0.05%) + + + +genunix`cv_broadcast (19 samples, 0.03%) + + + +genunix`kmem_alloc (533 samples, 0.93%) + + + +unix`mutex_exit (160 samples, 0.28%) + + + +genunix`memcmp (38 samples, 0.07%) + + + +unix`strlen (1,238 samples, 2.16%) +u.. + + +genunix`lookuppnatcred (12 samples, 0.02%) + + + +genunix`crfree (13 samples, 0.02%) + + + +lofs`table_lock_enter (43 samples, 0.07%) + + + +genunix`rwst_exit (18 samples, 0.03%) + + + +genunix`cv_destroy (31 samples, 0.05%) + + + +genunix`rwst_init (236 samples, 0.41%) + + + +genunix`vn_vfslocks_rele (1,420 samples, 2.47%) +ge.. + + +genunix`falloc (36 samples, 0.06%) + + + +genunix`setf (187 samples, 0.33%) + + + +zfs`zfs_fastaccesschk_execute (50 samples, 0.09%) + + + +genunix`vn_vfslocks_getlock (120 samples, 0.21%) + + + +genunix`fd_reserve (9 samples, 0.02%) + + + +genunix`vn_setops (160 samples, 0.28%) + + + +unix`sys_syscall (51,908 samples, 90.37%) +unix`sys_syscall + + +genunix`kmem_free (115 samples, 0.20%) + + + +genunix`vsd_free (48 samples, 0.08%) + + + +genunix`rexit (5 samples, 0.01%) + + + +genunix`vn_mountedvfs (11 samples, 0.02%) + + + +genunix`lookuppnatcred (44,681 samples, 77.79%) +genunix`lookuppnatcred + + +unix`splr (92 samples, 0.16%) + + + +genunix`vn_vfsrlock (13 samples, 0.02%) + + + +unix`mutex_exit (371 samples, 0.65%) + + + +genunix`kmem_cache_free (5 samples, 0.01%) + + + +genunix`dnlc_lookup (263 samples, 0.46%) + + + +genunix`audit_unfalloc (32 samples, 0.06%) + + + +unix`0xfffffffffb8001d6 (13 samples, 0.02%) + + + +genunix`rwst_destroy (146 samples, 0.25%) + + + +genunix`gethrtime_unscaled (182 samples, 0.32%) + + + +unix`mutex_enter (575 samples, 1.00%) + + + +unix`mutex_exit (148 samples, 0.26%) + + + +genunix`ufalloc_file (294 samples, 0.51%) + + + +unix`mutex_exit (163 samples, 0.28%) + + + +unix`membar_consumer (106 samples, 0.18%) + + + +genunix`crgetmapped (36 samples, 0.06%) + + + +genunix`memcmp (277 samples, 0.48%) + + + +genunix`cv_destroy (77 samples, 0.13%) + + + +genunix`kmem_cache_free (116 samples, 0.20%) + + + +genunix`kmem_cache_alloc (29 samples, 0.05%) + + + +genunix`fd_reserve (8 samples, 0.01%) + + + +zfs`zfs_lookup (946 samples, 1.65%) + + + +genunix`kmem_alloc (795 samples, 1.38%) + + + +unix`tsc_gethrtimeunscaled (11 samples, 0.02%) + + + +genunix`segvn_faultpage (7 samples, 0.01%) + + + +genunix`set_errno (9 samples, 0.02%) + + + +unix`splr (400 samples, 0.70%) + + + +genunix`rwst_destroy (32 samples, 0.06%) + + + +genunix`rwst_init (28 samples, 0.05%) + + + +unix`atomic_add_32 (292 samples, 0.51%) + + + +unix`0xfffffffffb800ca0 (517 samples, 0.90%) + + + +genunix`syscall_mstate (89 samples, 0.15%) + + + +genunix`kmem_alloc (73 samples, 0.13%) + + + +genunix`vn_vfsunlock (40 samples, 0.07%) + + + +unix`mutex_enter (1,202 samples, 2.09%) +u.. + + +lofs`makelfsnode (28 samples, 0.05%) + + + +unix`0xfffffffffb800c86 (472 samples, 0.82%) + + + +genunix`vn_rele (6,943 samples, 12.09%) +genunix`vn_rele + + +unix`mutex_exit (56 samples, 0.10%) + + + +genunix`kmem_cache_free (51 samples, 0.09%) + + + +genunix`gethrtime_unscaled (11 samples, 0.02%) + + + +unix`pagefault (13 samples, 0.02%) + + + +genunix`secpolicy_vnode_access2 (217 samples, 0.38%) + + + +genunix`vn_vfslocks_getlock (1,357 samples, 2.36%) +g.. + + +unix`bcmp (295 samples, 0.51%) + + + +unix`mutex_enter (97 samples, 0.17%) + + + +unix`membar_consumer (123 samples, 0.21%) + + + +genunix`audit_getstate (16 samples, 0.03%) + + + +unix`mutex_enter (455 samples, 0.79%) + + + +lofs`makelonode (4,212 samples, 7.33%) +lofs`makel.. + + +genunix`kmem_cache_alloc (168 samples, 0.29%) + + + +genunix`vn_vfslocks_getlock (62 samples, 0.11%) + + + +genunix`secpolicy_vnode_access2 (72 samples, 0.13%) + + + +genunix`kmem_cache_free (73 samples, 0.13%) + + + +genunix`vn_reinit (424 samples, 0.74%) + + + +genunix`pn_getcomponent (454 samples, 0.79%) + + + +genunix`fsop_root (297 samples, 0.52%) + + + +genunix`crgetuid (30 samples, 0.05%) + + + +genunix`kmem_free (785 samples, 1.37%) + + + +unix`mutex_exit (171 samples, 0.30%) + + + +genunix`crgetmapped (58 samples, 0.10%) + + + +unix`mutex_enter (299 samples, 0.52%) + + + +genunix`rwst_exit (167 samples, 0.29%) + + + +genunix`audit_falloc (8 samples, 0.01%) + + + +genunix`rwst_exit (110 samples, 0.19%) + + + +genunix`exit (5 samples, 0.01%) + + + +unix`mutex_exit (250 samples, 0.44%) + + + +lofs`freelonode (35 samples, 0.06%) + + + +genunix`rwst_tryenter (37 samples, 0.06%) + + + +ufs`ufs_iaccess (91 samples, 0.16%) + + + +unix`tsc_gethrtimeunscaled (12 samples, 0.02%) + + + +genunix`kmem_cache_alloc (241 samples, 0.42%) + + + +FSS`fss_preempt (8 samples, 0.01%) + + + +genunix`fd_reserve (15 samples, 0.03%) + + + +genunix`cv_broadcast (16 samples, 0.03%) + + + +genunix`crgetmapped (57 samples, 0.10%) + + + +unix`mutex_exit (379 samples, 0.66%) + + + +unix`mutex_destroy (31 samples, 0.05%) + + + +lofs`table_lock_enter (189 samples, 0.33%) + + + +genunix`rwst_enter_common (264 samples, 0.46%) + + + +genunix`kmem_free (11 samples, 0.02%) + + + +unix`atomic_add_32 (134 samples, 0.23%) + + + +genunix`ufalloc (551 samples, 0.96%) + + + +genunix`audit_falloc (313 samples, 0.54%) + + + +lofs`lo_lookup (19,887 samples, 34.62%) +lofs`lo_lookup + + +unix`atomic_add_64 (110 samples, 0.19%) + + + +genunix`vn_vfsunlock (2,372 samples, 4.13%) +genu.. + + +genunix`openat (17 samples, 0.03%) + + + +unix`bcmp (45 samples, 0.08%) + + + +genunix`audit_getstate (62 samples, 0.11%) + + + +genunix`crfree (9 samples, 0.02%) + + + +genunix`kmem_cache_free (18 samples, 0.03%) + + + +genunix`vn_vfslocks_rele (903 samples, 1.57%) + + + +genunix`vn_invalid (20 samples, 0.03%) + + + +genunix`vn_vfslocks_rele (50 samples, 0.09%) + + + +genunix`lookuppnvp (10 samples, 0.02%) + + + +genunix`fd_find (161 samples, 0.28%) + + + +ufs`ufs_lookup (5,399 samples, 9.40%) +ufs`ufs_lookup + + +unix`0xfffffffffb800c7c (42 samples, 0.07%) + + + +genunix`vn_openat (14 samples, 0.02%) + + + +genunix`setf (16 samples, 0.03%) + + + +genunix`traverse (7,243 samples, 12.61%) +genunix`traverse + + +genunix`rwst_tryenter (734 samples, 1.28%) + + + +unix`mutex_enter (366 samples, 0.64%) + + + +genunix`fop_lookup (6,470 samples, 11.26%) +genunix`fop_lookup + + +unix`mutex_exit (135 samples, 0.24%) + + + +lofs`makelfsnode (82 samples, 0.14%) + + + +genunix`copen (7 samples, 0.01%) + + + diff --git a/tests/benchmarks/_script/flamegraph/example-perf-stacks.txt.gz b/tests/benchmarks/_script/flamegraph/example-perf-stacks.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..e7b762b88bb679137c3796022e334dfefe79fc45 GIT binary patch literal 110532 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/benchmarks/_script/flamegraph/example-perf.svg b/tests/benchmarks/_script/flamegraph/example-perf.svg new file mode 100644 index 00000000000..d4896fc3503 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/example-perf.svg @@ -0,0 +1,4895 @@ + + + + + + + + + + + + + +Flame Graph + +Reset Zoom +Search + + +rw_verify_area (9 samples, 0.68%) + + + +_raw_spin_lock_irqsave (2 samples, 0.15%) + + + +sun/nio/ch/FileDispatcherImpl:.read0 (31 samples, 2.36%) +s.. + + +do_sync_read (22 samples, 1.67%) + + + +sun/nio/ch/SocketChannelImpl:.write (209 samples, 15.89%) +sun/nio/ch/SocketChannel.. + + +timerqueue_del (1 samples, 0.08%) + + + +io/netty/channel/AdaptiveRecvByteBufAllocator$HandleImpl:.record (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptRuntime:.setObjectProp (86 samples, 6.54%) +org/mozi.. + + +read_tsc (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (14 samples, 1.06%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (45 samples, 3.42%) +org.. + + +netdev_pick_tx (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.write (33 samples, 2.51%) +io.. + + +java/lang/String:.equals (1 samples, 0.08%) + + + +system_call_fastpath (7 samples, 0.53%) + + + +GCTaskManager::get_task (1 samples, 0.08%) + + + +security_file_free (1 samples, 0.08%) + + + +apparmor_socket_recvmsg (5 samples, 0.38%) + + + +itable stub (1 samples, 0.08%) + + + +skb_release_data (3 samples, 0.23%) + + + +hrtimer_try_to_cancel (3 samples, 0.23%) + + + +default_wake_function (25 samples, 1.90%) +d.. + + +__remove_hrtimer (3 samples, 0.23%) + + + +epoll_ctl (1 samples, 0.08%) + + + +fsnotify (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.nameOrFunction (4 samples, 0.30%) + + + +tcp_clean_rtx_queue (1 samples, 0.08%) + + + +tcp_send_delayed_ack (5 samples, 0.38%) + + + +org/mozilla/javascript/ScriptRuntime:.nameOrFunction (1 samples, 0.08%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +tcp_v4_rcv (87 samples, 6.62%) +tcp_v4_rcv + + +aeProcessEvents (1 samples, 0.08%) + + + +org/mozilla/javascript/NativeJavaObject:.initMembers (1 samples, 0.08%) + + + +schedule_preempt_disabled (2 samples, 0.15%) + + + +kfree (1 samples, 0.08%) + + + +sun/nio/ch/SocketChannelImpl:.write (1 samples, 0.08%) + + + +sk_reset_timer (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (6 samples, 0.46%) + + + +remote_function (4 samples, 0.30%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.skipControlCharacters (1 samples, 0.08%) + + + +intel_pmu_enable_all (4 samples, 0.30%) + + + +mod_timer (5 samples, 0.38%) + + + +io/netty/handler/codec/MessageToMessageEncoder:.write (31 samples, 2.36%) +i.. + + +io/netty/buffer/UnpooledHeapByteBuf:.init (1 samples, 0.08%) + + + +intel_pmu_enable_all (4 samples, 0.30%) + + + +io/netty/channel/AbstractChannelHandlerContext:.write (2 samples, 0.15%) + + + +enqueue_hrtimer (1 samples, 0.08%) + + + +itable stub (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject$Slot:.setAttributes (12 samples, 0.91%) + + + +cpuidle_idle_call (6 samples, 0.46%) + + + +system_call (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.get (2 samples, 0.15%) + + + +[unknown] (6 samples, 0.46%) + + + +Monitor::IWait (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.bind (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (40 samples, 3.04%) +org.. + + +__wake_up_sync_key (3 samples, 0.23%) + + + +system_call_fastpath (1 samples, 0.08%) + + + +vfs_write (85 samples, 6.46%) +vfs_write + + +mod_timer (2 samples, 0.15%) + + + +rcu_sysidle_enter (1 samples, 0.08%) + + + +oopDesc* PSPromotionManager::copy_to_survivor_spacefalse (1 samples, 0.08%) + + + +__wake_up_common (2 samples, 0.15%) + + + +io/netty/channel/AbstractChannelHandlerContext:.fireChannelRead (637 samples, 48.44%) +io/netty/channel/AbstractChannelHandlerContext:.fireChannelRead + + +_raw_spin_lock_irqsave (2 samples, 0.15%) + + + +ScavengeRootsTask::do_it (1 samples, 0.08%) + + + +tcp_urg (1 samples, 0.08%) + + + +aa_file_perm (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.setObjectProp (21 samples, 1.60%) + + + +__remove_hrtimer (1 samples, 0.08%) + + + +put_filp (1 samples, 0.08%) + + + +skb_free_head (1 samples, 0.08%) + + + +apparmor_file_permission (1 samples, 0.08%) + + + +ktime_get (1 samples, 0.08%) + + + +JavaCalls::call_virtual (956 samples, 72.70%) +JavaCalls::call_virtual + + +__copy_skb_header (1 samples, 0.08%) + + + +__slab_alloc (1 samples, 0.08%) + + + +cpuidle_idle_call (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.has (30 samples, 2.28%) +o.. + + +ip_queue_xmit (51 samples, 3.88%) +ip_q.. + + +org/mozilla/javascript/NativeCall:.init (15 samples, 1.14%) + + + +tcp_ack (9 samples, 0.68%) + + + +sys_ioctl (5 samples, 0.38%) + + + +fsnotify (2 samples, 0.15%) + + + +sk_reset_timer (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.addKnownAbsentSlot (1 samples, 0.08%) + + + +lapic_next_deadline (2 samples, 0.15%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_Server2_js_1:.call (79 samples, 6.01%) +org/mozi.. + + +sys_execve (1 samples, 0.08%) + + + +perf_event_enable (5 samples, 0.38%) + + + +sys_futex (1 samples, 0.08%) + + + +java/lang/String:.init (1 samples, 0.08%) + + + +inet_recvmsg (7 samples, 0.53%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (2 samples, 0.15%) + + + +io/netty/util/internal/AppendableCharSequence:.substring (4 samples, 0.30%) + + + +_raw_spin_lock_irqsave (1 samples, 0.08%) + + + +x86_pmu_enable (4 samples, 0.30%) + + + +__libc_read (1 samples, 0.08%) + + + +tcp_sendmsg (77 samples, 5.86%) +tcp_sen.. + + +cpuidle_enter_state (12 samples, 0.91%) + + + +flush_tlb_mm_range (1 samples, 0.08%) + + + +ksize (1 samples, 0.08%) + + + +cpu_startup_entry (44 samples, 3.35%) +cpu.. + + +pthread_self (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +_raw_spin_lock_bh (1 samples, 0.08%) + + + +io/netty/channel/DefaultChannelPipeline$HeadContext:.flush (2 samples, 0.15%) + + + +tcp_rcv_established (23 samples, 1.75%) + + + +org/mozilla/javascript/BaseFunction:.execIdCall (48 samples, 3.65%) +org/.. + + +lapic_next_deadline (1 samples, 0.08%) + + + +[unknown] (197 samples, 14.98%) +[unknown] + + +io/netty/channel/AbstractChannelHandlerContext:.fireChannelReadComplete (242 samples, 18.40%) +io/netty/channel/AbstractCha.. + + +bictcp_cong_avoid (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.nameOrFunction (5 samples, 0.38%) + + + +JavaCalls::call_virtual (956 samples, 72.70%) +JavaCalls::call_virtual + + +resched_task (2 samples, 0.15%) + + + +sock_wfree (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (4 samples, 0.30%) + + + +io/netty/buffer/AbstractByteBuf:.getByte (1 samples, 0.08%) + + + +check_preempt_curr (2 samples, 0.15%) + + + +io/netty/channel/ChannelOutboundBuffer:.progress (1 samples, 0.08%) + + + +tcp_current_mss (1 samples, 0.08%) + + + +__execve (1 samples, 0.08%) + + + +hrtimer_force_reprogram (1 samples, 0.08%) + + + +__GI___mprotect (1 samples, 0.08%) + + + +ep_send_events_proc (9 samples, 0.68%) + + + +schedule (11 samples, 0.84%) + + + +org/mozilla/javascript/IdScriptableObject:.put (3 samples, 0.23%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (409 samples, 31.10%) +org/mozilla/javascript/gen/file__root_vert_x_2_1_.. + + +io/netty/channel/ChannelOutboundBuffer:.decrementPendingOutboundBytes (2 samples, 0.15%) + + + +ktime_get_real (1 samples, 0.08%) + + + +aa_revalidate_sk (2 samples, 0.15%) + + + +stats_record (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +__perf_event_enable (4 samples, 0.30%) + + + +__alloc_skb (9 samples, 0.68%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (17 samples, 1.29%) + + + +socket_readable (2 samples, 0.15%) + + + +ns_to_timeval (1 samples, 0.08%) + + + +ip_rcv (33 samples, 2.51%) +ip.. + + +SafepointSynchronize::begin (1 samples, 0.08%) + + + +java/nio/DirectByteBuffer:.duplicate (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (2 samples, 0.15%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (20 samples, 1.52%) + + + +io/netty/channel/nio/AbstractNioByteChannel$NioByteUnsafe:.read (939 samples, 71.41%) +io/netty/channel/nio/AbstractNioByteChannel$NioByteUnsafe:.read + + +raw_local_deliver (1 samples, 0.08%) + + + +__dev_queue_xmit (4 samples, 0.30%) + + + +skb_copy_datagram_iovec (3 samples, 0.23%) + + + +apic_timer_interrupt (1 samples, 0.08%) + + + +do_vfs_ioctl (5 samples, 0.38%) + + + +do_sync_read (8 samples, 0.61%) + + + +system_call_after_swapgs (1 samples, 0.08%) + + + +_raw_spin_lock_irqsave (1 samples, 0.08%) + + + +call_function_single_interrupt (4 samples, 0.30%) + + + +io/netty/handler/codec/http/HttpHeaders:.hash (4 samples, 0.30%) + + + +io/netty/handler/codec/http/DefaultHttpMessage:.init (2 samples, 0.15%) + + + +rcu_sysidle_enter (1 samples, 0.08%) + + + +java/nio/channels/spi/AbstractInterruptibleChannel:.end (3 samples, 0.23%) + + + +clockevents_program_event (2 samples, 0.15%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (9 samples, 0.68%) + + + +tcp_try_rmem_schedule (2 samples, 0.15%) + + + +__schedule (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (10 samples, 0.76%) + + + +tcp_v4_md5_lookup (1 samples, 0.08%) + + + +CardTableExtension::scavenge_contents_parallel (20 samples, 1.52%) + + + +aa_revalidate_sk (1 samples, 0.08%) + + + +__fsnotify_parent (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.get (7 samples, 0.53%) + + + +sk_reset_timer (5 samples, 0.38%) + + + +__schedule (2 samples, 0.15%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.init (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +io/netty/channel/nio/AbstractNioByteChannel:.doWrite (225 samples, 17.11%) +io/netty/channel/nio/Abstr.. + + +timerqueue_add (1 samples, 0.08%) + + + +_raw_spin_unlock_irqrestore (2 samples, 0.15%) + + + +try_to_wake_up (24 samples, 1.83%) +t.. + + +org/mozilla/javascript/IdScriptableObject:.setAttributes (4 samples, 0.30%) + + + +io/netty/handler/codec/http/HttpResponseEncoder:.acceptOutboundMessage (1 samples, 0.08%) + + + +rw_verify_area (2 samples, 0.15%) + + + +x86_pmu_commit_txn (4 samples, 0.30%) + + + +alloc_pages_current (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_streams_j (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.setAttributes (7 samples, 0.53%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +tcp_transmit_skb (1 samples, 0.08%) + + + +sock_aio_read.part.8 (7 samples, 0.53%) + + + +sys_read (28 samples, 2.13%) +s.. + + +org/mozilla/javascript/ScriptRuntime:.setObjectProp (28 samples, 2.13%) +o.. + + +JavaCalls::call_helper (956 samples, 72.70%) +JavaCalls::call_helper + + +ttwu_do_wakeup (1 samples, 0.08%) + + + +generic_smp_call_function_single_interrupt (4 samples, 0.30%) + + + +mutex_unlock (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpHeaders:.hash (2 samples, 0.15%) + + + +http_parser_execute (1 samples, 0.08%) + + + +mod_timer (5 samples, 0.38%) + + + +system_call_fastpath (1 samples, 0.08%) + + + +tcp_recvmsg (13 samples, 0.99%) + + + +__slab_alloc (1 samples, 0.08%) + + + +__alloc_skb (7 samples, 0.53%) + + + +clockevents_program_event (1 samples, 0.08%) + + + +vfs_read (18 samples, 1.37%) + + + +__internal_add_timer (1 samples, 0.08%) + + + +epoll_wait (1 samples, 0.08%) + + + +lock_sock_nested (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +native_write_msr_safe (4 samples, 0.30%) + + + +Interpreter (956 samples, 72.70%) +Interpreter + + +org/mozilla/javascript/ScriptableObject:.getBase (4 samples, 0.30%) + + + +dev_hard_start_xmit (9 samples, 0.68%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +ip_output (46 samples, 3.50%) +ip_.. + + +account_entity_enqueue (1 samples, 0.08%) + + + +itable stub (1 samples, 0.08%) + + + +ip_rcv (1 samples, 0.08%) + + + +io/netty/buffer/AbstractByteBuf:.writeBytes (5 samples, 0.38%) + + + +tcp_clean_rtx_queue (14 samples, 1.06%) + + + +io/netty/channel/AbstractChannelHandlerContext:.flush (1 samples, 0.08%) + + + +sys_read (21 samples, 1.60%) + + + +[unknown] (10 samples, 0.76%) + + + +java/util/concurrent/ConcurrentHashMap:.get (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannel:.hashCode (4 samples, 0.30%) + + + +rcu_idle_enter (1 samples, 0.08%) + + + +gettimeofday@plt (1 samples, 0.08%) + + + +__do_softirq (103 samples, 7.83%) +__do_softirq + + +org/mozilla/javascript/ScriptRuntime:.nameOrFunction (8 samples, 0.61%) + + + +io/netty/buffer/AbstractByteBuf:.writeBytes (3 samples, 0.23%) + + + +inotify_add_watch (1 samples, 0.08%) + + + +fdval (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpHeaders:.encode (7 samples, 0.53%) + + + +unsafe_arraycopy (1 samples, 0.08%) + + + +sk_stream_alloc_skb (10 samples, 0.76%) + + + +lock_timer_base.isra.35 (1 samples, 0.08%) + + + +ip_local_out (121 samples, 9.20%) +ip_local_out + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +io/netty/util/internal/AppendableCharSequence:.substring (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptRuntime:.bind (1 samples, 0.08%) + + + +ep_poll (53 samples, 4.03%) +ep_p.. + + +lock_hrtimer_base.isra.19 (1 samples, 0.08%) + + + +InstanceKlass::oop_push_contents (1 samples, 0.08%) + + + +cpuacct_charge (1 samples, 0.08%) + + + +harmonize_features.isra.92.part.93 (1 samples, 0.08%) + + + +update_rq_clock.part.63 (1 samples, 0.08%) + + + +native_write_msr_safe (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.findNonWhitespace (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_streams_j (1 samples, 0.08%) + + + +org/mozilla/javascript/BaseFunction:.construct (156 samples, 11.86%) +org/mozilla/javas.. + + +_raw_spin_lock (2 samples, 0.15%) + + + +cpu_function_call (5 samples, 0.38%) + + + +fget_light (2 samples, 0.15%) + + + +start_kernel (24 samples, 1.83%) +s.. + + +native_write_msr_safe (2 samples, 0.15%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (511 samples, 38.86%) +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io.. + + +ipv4_mtu (1 samples, 0.08%) + + + +__schedule (11 samples, 0.84%) + + + +system_call_fastpath (88 samples, 6.69%) +system_ca.. + + +io/netty/channel/nio/NioEventLoop:.select (7 samples, 0.53%) + + + +org/mozilla/javascript/IdScriptableObject:.get (3 samples, 0.23%) + + + +org/mozilla/javascript/TopLevel:.getBuiltinPrototype (7 samples, 0.53%) + + + +sun/nio/ch/IOUtil:.readIntoNativeBuffer (31 samples, 2.36%) +s.. + + +itable stub (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.write (6 samples, 0.46%) + + + +timerqueue_del (1 samples, 0.08%) + + + +__tcp_v4_send_check (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.nameOrFunction (3 samples, 0.23%) + + + +io/netty/buffer/AbstractByteBuf:.writeBytes (4 samples, 0.30%) + + + +org/mozilla/javascript/WrapFactory:.wrapAsJavaObject (1 samples, 0.08%) + + + +io/netty/handler/codec/http/DefaultHttpMessage:.init (2 samples, 0.15%) + + + +_raw_spin_lock_irqsave (2 samples, 0.15%) + + + +org/mozilla/javascript/IdScriptableObject:.put (7 samples, 0.53%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.add0 (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (8 samples, 0.61%) + + + +java/util/ArrayList:.ensureCapacityInternal (1 samples, 0.08%) + + + +__wake_up_locked (25 samples, 1.90%) +_.. + + +java/util/HashMap:.getNode (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.toObjectOrNull (1 samples, 0.08%) + + + +__tcp_push_pending_frames (1 samples, 0.08%) + + + +[unknown] (61 samples, 4.64%) +[unkn.. + + +__slab_free (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.put (11 samples, 0.84%) + + + +sock_def_readable (5 samples, 0.38%) + + + +gmain (1 samples, 0.08%) + + + +_raw_spin_lock_irqsave (1 samples, 0.08%) + + + +__kmalloc_reserve.isra.26 (3 samples, 0.23%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (5 samples, 0.38%) + + + +org/mozilla/javascript/NativeCall:.init (20 samples, 1.52%) + + + +org/mozilla/javascript/WrapFactory:.wrap (1 samples, 0.08%) + + + +_raw_spin_lock_bh (1 samples, 0.08%) + + + +aeProcessEvents (3 samples, 0.23%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.executor (1 samples, 0.08%) + + + +fget_light (2 samples, 0.15%) + + + +io/netty/buffer/PooledByteBufAllocator:.newDirectBuffer (2 samples, 0.15%) + + + +menu_select (1 samples, 0.08%) + + + +generic_smp_call_function_single_interrupt (4 samples, 0.30%) + + + +org/mozilla/javascript/TopLevel:.getBuiltinPrototype (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.setAttributes (1 samples, 0.08%) + + + +schedule_hrtimeout_range_clock (20 samples, 1.52%) + + + +io/netty/buffer/UnreleasableByteBuf:.duplicate (1 samples, 0.08%) + + + +tick_program_event (2 samples, 0.15%) + + + +__netif_receive_skb_core (33 samples, 2.51%) +__.. + + +java/util/HashMap:.getNode (1 samples, 0.08%) + + + +io/netty/buffer/AbstractByteBuf:.forEachByteAsc0 (2 samples, 0.15%) + + + +get_next_timer_interrupt (2 samples, 0.15%) + + + +vtable stub (1 samples, 0.08%) + + + +start_secondary (44 samples, 3.35%) +sta.. + + +skb_release_all (3 samples, 0.23%) + + + +update_cfs_rq_blocked_load (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +call_function_single_interrupt (4 samples, 0.30%) + + + +sun/nio/ch/SocketChannelImpl:.read (40 samples, 3.04%) +sun.. + + +sys_epoll_wait (1 samples, 0.08%) + + + +tcp_check_space (1 samples, 0.08%) + + + +__wake_up_common (25 samples, 1.90%) +_.. + + +native_sched_clock (1 samples, 0.08%) + + + +fget_light (3 samples, 0.23%) + + + +sys_inotify_add_watch (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject$Slot:.getValue (1 samples, 0.08%) + + + +_raw_spin_lock (1 samples, 0.08%) + + + +smp_call_function_single_interrupt (4 samples, 0.30%) + + + +__kmalloc_node_track_caller (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject$RelinkedSlot:.getValue (1 samples, 0.08%) + + + +tcp_send_mss (6 samples, 0.46%) + + + +sched_clock (1 samples, 0.08%) + + + +kmem_cache_alloc_node (4 samples, 0.30%) + + + +_raw_spin_lock_irqsave (1 samples, 0.08%) + + + +tick_sched_handle.isra.17 (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getBase (1 samples, 0.08%) + + + +[unknown] (6 samples, 0.46%) + + + +io/netty/util/internal/AppendableCharSequence:.substring (2 samples, 0.15%) + + + +__inet_lookup_established (2 samples, 0.15%) + + + +apparmor_file_permission (1 samples, 0.08%) + + + +dst_release (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpObjectEncoder:.encode (1 samples, 0.08%) + + + +open_exec (1 samples, 0.08%) + + + +tcp_transmit_skb (132 samples, 10.04%) +tcp_transmit_skb + + +ttwu_do_wakeup (5 samples, 0.38%) + + + +idle_cpu (1 samples, 0.08%) + + + +__lll_unlock_wake (1 samples, 0.08%) + + + +[unknown] (7 samples, 0.53%) + + + +security_file_permission (2 samples, 0.15%) + + + +[unknown] (1 samples, 0.08%) + + + +__switch_to (1 samples, 0.08%) + + + +io/netty/channel/DefaultChannelPromise:.trySuccess (3 samples, 0.23%) + + + +org/mozilla/javascript/IdScriptableObject:.has (7 samples, 0.53%) + + + +native_write_msr_safe (3 samples, 0.23%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.add0 (2 samples, 0.15%) + + + +do_softirq (103 samples, 7.83%) +do_softirq + + +rw_verify_area (1 samples, 0.08%) + + + +tcp_poll (1 samples, 0.08%) + + + +tcp_rearm_rto (5 samples, 0.38%) + + + +io/netty/channel/AbstractChannelHandlerContext:.newPromise (1 samples, 0.08%) + + + +tick_nohz_idle_exit (5 samples, 0.38%) + + + +org/mozilla/javascript/BaseFunction:.execIdCall (60 samples, 4.56%) +org/m.. + + +org/mozilla/javascript/ScriptableObject:.putImpl (1 samples, 0.08%) + + + +_copy_from_user (1 samples, 0.08%) + + + +__netif_receive_skb (34 samples, 2.59%) +__.. + + +java/util/concurrent/ConcurrentHashMap:.get (3 samples, 0.23%) + + + +fput (1 samples, 0.08%) + + + +JavaThread::thread_main_inner (956 samples, 72.70%) +JavaThread::thread_main_inner + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +io/netty/util/Recycler:.get (2 samples, 0.15%) + + + +[unknown] (6 samples, 0.46%) + + + +__dev_queue_xmit (1 samples, 0.08%) + + + +common_file_perm (1 samples, 0.08%) + + + +org/mozilla/javascript/JavaMembers:.get (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.getPropFunctionAndThisHelper (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (6 samples, 0.46%) + + + +jiffies_to_timeval (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.setName (2 samples, 0.15%) + + + +PSRootsClosurefalse::do_oop (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +vtable stub (1 samples, 0.08%) + + + +skb_clone (4 samples, 0.30%) + + + +OldToYoungRootsTask::do_it (20 samples, 1.52%) + + + +io/netty/channel/ChannelDuplexHandler:.flush (237 samples, 18.02%) +io/netty/channel/ChannelDupl.. + + +org/mozilla/javascript/ScriptableObject:.putImpl (1 samples, 0.08%) + + + +mutex_unlock (1 samples, 0.08%) + + + +hrtimer_force_reprogram (1 samples, 0.08%) + + + +stub_execve (1 samples, 0.08%) + + + +sock_poll (3 samples, 0.23%) + + + +org/mozilla/javascript/IdScriptableObject:.setAttributes (5 samples, 0.38%) + + + +_raw_spin_lock_bh (1 samples, 0.08%) + + + +native_write_msr_safe (3 samples, 0.23%) + + + +sched_clock_cpu (1 samples, 0.08%) + + + +io/netty/channel/DefaultChannelPipeline$HeadContext:.flush (232 samples, 17.64%) +io/netty/channel/DefaultCha.. + + +org/mozilla/javascript/IdScriptableObject:.get (4 samples, 0.30%) + + + +rcu_idle_enter (1 samples, 0.08%) + + + +java (995 samples, 75.67%) +java + + +tcp_cleanup_rbuf (2 samples, 0.15%) + + + +org/mozilla/javascript/NativeJavaObject:.initMembers (4 samples, 0.30%) + + + +org/mozilla/javascript/NativeCall:.init (16 samples, 1.22%) + + + +http_parser_execute (2 samples, 0.15%) + + + +_raw_spin_unlock_irqrestore (1 samples, 0.08%) + + + +ThreadRootsTask::do_it (3 samples, 0.23%) + + + +mutex_lock (3 samples, 0.23%) + + + +cpu_startup_entry (23 samples, 1.75%) + + + +itable stub (1 samples, 0.08%) + + + +__srcu_read_lock (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (5 samples, 0.38%) + + + +org/vertx/java/core/impl/DefaultVertx:.setContext (1 samples, 0.08%) + + + +ip_rcv_finish (89 samples, 6.77%) +ip_rcv_fi.. + + +response_complete (13 samples, 0.99%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.skipControlCharacters (2 samples, 0.15%) + + + +tcp_v4_rcv (27 samples, 2.05%) +t.. + + +ktime_get_ts (2 samples, 0.15%) + + + +tick_nohz_restart (4 samples, 0.30%) + + + +io/netty/channel/ChannelOutboundHandlerAdapter:.flush (1 samples, 0.08%) + + + +sun/nio/ch/FileDispatcherImpl:.write0 (2 samples, 0.15%) + + + +GCTaskThread::run (28 samples, 2.13%) +G.. + + +io/netty/handler/codec/http/HttpHeaders:.encode (1 samples, 0.08%) + + + +__kmalloc_node_track_caller (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.put (25 samples, 1.90%) +o.. + + +org/mozilla/javascript/IdScriptableObject:.has (2 samples, 0.15%) + + + +atomic_notifier_call_chain (1 samples, 0.08%) + + + +remote_function (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +common_file_perm (1 samples, 0.08%) + + + +sun/nio/ch/SocketChannelImpl:.isConnected (2 samples, 0.15%) + + + +org/mozilla/javascript/IdScriptableObject:.has (9 samples, 0.68%) + + + +tcp_init_tso_segs (1 samples, 0.08%) + + + +org/mozilla/javascript/BaseFunction:.findInstanceIdInfo (1 samples, 0.08%) + + + +tcp_v4_do_rcv (77 samples, 5.86%) +tcp_v4_.. + + +__tcp_push_pending_frames (61 samples, 4.64%) +__tcp.. + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (1 samples, 0.08%) + + + +native_read_tsc (1 samples, 0.08%) + + + +tcp_md5_do_lookup (1 samples, 0.08%) + + + +do_sync_write (186 samples, 14.14%) +do_sync_write + + +cpuidle_enter_state (4 samples, 0.30%) + + + +ep_poll_callback (1 samples, 0.08%) + + + +x86_pmu_enable (4 samples, 0.30%) + + + +copy_user_generic_string (3 samples, 0.23%) + + + +perf_pmu_enable (4 samples, 0.30%) + + + +vfs_read (25 samples, 1.90%) +v.. + + +x86_64_start_reservations (24 samples, 1.83%) +x.. + + +security_file_permission (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.addKnownAbsentSlot (1 samples, 0.08%) + + + +nr_iowait_cpu (1 samples, 0.08%) + + + +__hrtimer_start_range_ns (2 samples, 0.15%) + + + +system_call_after_swapgs (1 samples, 0.08%) + + + +release_sock (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (11 samples, 0.84%) + + + +_raw_spin_unlock_irqrestore (1 samples, 0.08%) + + + +itable stub (1 samples, 0.08%) + + + +call_stub (956 samples, 72.70%) +call_stub + + +dev_hard_start_xmit (3 samples, 0.23%) + + + +dev_queue_xmit (11 samples, 0.84%) + + + +task_nice (2 samples, 0.15%) + + + +ip_finish_output (119 samples, 9.05%) +ip_finish_out.. + + +__remove_hrtimer (1 samples, 0.08%) + + + +sys_epoll_wait (4 samples, 0.30%) + + + +rcu_cpu_has_callbacks (1 samples, 0.08%) + + + +java/lang/ThreadLocal:.get (1 samples, 0.08%) + + + +rcu_idle_exit (1 samples, 0.08%) + + + +net_rx_action (97 samples, 7.38%) +net_rx_act.. + + +lock_sock_nested (1 samples, 0.08%) + + + +mod_timer (2 samples, 0.15%) + + + +apparmor_file_free_security (1 samples, 0.08%) + + + +__remove_hrtimer (1 samples, 0.08%) + + + +tcp_established_options (4 samples, 0.30%) + + + +sk_reset_timer (5 samples, 0.38%) + + + +io/netty/channel/ChannelOutboundHandlerAdapter:.flush (235 samples, 17.87%) +io/netty/channel/ChannelOut.. + + +org/mozilla/javascript/NativeFunction:.initScriptFunction (1 samples, 0.08%) + + + +menu_reflect (1 samples, 0.08%) + + + +__slab_alloc (3 samples, 0.23%) + + + +PSScavengeKlassClosure::do_klass (1 samples, 0.08%) + + + +__ip_local_out (1 samples, 0.08%) + + + +org/mozilla/javascript/TopLevel:.getBuiltinPrototype (5 samples, 0.38%) + + + +tcp_send_delayed_ack (3 samples, 0.23%) + + + +arch_local_irq_save (1 samples, 0.08%) + + + +__kmalloc_node_track_caller (1 samples, 0.08%) + + + +java/nio/channels/spi/AbstractInterruptibleChannel:.end (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.createSlot (15 samples, 1.14%) + + + +apparmor_file_permission (2 samples, 0.15%) + + + +mutex_lock (2 samples, 0.15%) + + + +sys_epoll_ctl (5 samples, 0.38%) + + + +hrtimer_interrupt (1 samples, 0.08%) + + + +ParallelTaskTerminator::offer_termination (2 samples, 0.15%) + + + +dequeue_entity (4 samples, 0.30%) + + + +io/netty/buffer/PooledByteBuf:.deallocate (5 samples, 0.38%) + + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (1 samples, 0.08%) + + + +wrk (240 samples, 18.25%) +wrk + + +perf_pmu_enable (4 samples, 0.30%) + + + +org/mozilla/javascript/IdScriptableObject:.get (2 samples, 0.15%) + + + +remote_function (4 samples, 0.30%) + + + +__GI___ioctl (5 samples, 0.38%) + + + +socket_readable (2 samples, 0.15%) + + + +epoll_ctl (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (21 samples, 1.60%) + + + +tick_nohz_stop_sched_tick (4 samples, 0.30%) + + + +io/netty/channel/DefaultChannelPipeline$HeadContext:.write (6 samples, 0.46%) + + + +tcp_write_xmit (147 samples, 11.18%) +tcp_write_xmit + + +org/mozilla/javascript/ScriptRuntime:.getPropFunctionAndThisHelper (5 samples, 0.38%) + + + +lock_hrtimer_base.isra.19 (1 samples, 0.08%) + + + +inet_recvmsg (17 samples, 1.29%) + + + +native_write_msr_safe (4 samples, 0.30%) + + + +ip_local_out (46 samples, 3.50%) +ip_.. + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.has (1 samples, 0.08%) + + + +local_bh_enable (42 samples, 3.19%) +loc.. + + +hrtimer_start_range_ns (3 samples, 0.23%) + + + +jlong_disjoint_arraycopy (1 samples, 0.08%) + + + +ep_send_events_proc (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptableObject:.getParentScope (3 samples, 0.23%) + + + +itable stub (1 samples, 0.08%) + + + +path_openat (1 samples, 0.08%) + + + +activate_task (7 samples, 0.53%) + + + +pick_next_task_fair (1 samples, 0.08%) + + + +security_file_permission (5 samples, 0.38%) + + + +io/netty/channel/ChannelOutboundBuffer:.decrementPendingOutboundBytes (1 samples, 0.08%) + + + +system_call_fastpath (56 samples, 4.26%) +syste.. + + +org/mozilla/javascript/NativeFunction:.initScriptFunction (6 samples, 0.46%) + + + +ip_local_deliver_finish (30 samples, 2.28%) +i.. + + +sock_read (2 samples, 0.15%) + + + +deactivate_task (7 samples, 0.53%) + + + +lock_sock_nested (1 samples, 0.08%) + + + +sock_put (1 samples, 0.08%) + + + +mod_timer (3 samples, 0.23%) + + + +aeProcessEvents (171 samples, 13.00%) +aeProcessEvents + + +io/netty/buffer/AbstractByteBuf:.ensureWritable (2 samples, 0.15%) + + + +tick_nohz_stop_sched_tick (5 samples, 0.38%) + + + +org/mozilla/javascript/NativeJavaMethod:.findCachedFunction (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpMethod:.valueOf (2 samples, 0.15%) + + + +hrtimer_try_to_cancel (1 samples, 0.08%) + + + +system_call (1 samples, 0.08%) + + + +hrtimer_cancel (1 samples, 0.08%) + + + +system_call_fastpath (196 samples, 14.90%) +system_call_fastpath + + +io/netty/channel/AbstractChannelHandlerContext:.read (2 samples, 0.15%) + + + +[unknown] (10 samples, 0.76%) + + + +io/netty/handler/codec/MessageToMessageEncoder:.write (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.put (47 samples, 3.57%) +org.. + + +jlong_disjoint_arraycopy (1 samples, 0.08%) + + + +[unknown] (1 samples, 0.08%) + + + +native_read_tsc (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.splitHeader (8 samples, 0.61%) + + + +intel_pmu_enable_all (4 samples, 0.30%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.set (3 samples, 0.23%) + + + +read_tsc (1 samples, 0.08%) + + + +_raw_spin_lock (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.toObjectOrNull (1 samples, 0.08%) + + + +_raw_spin_lock_irqsave (1 samples, 0.08%) + + + +dequeue_task_fair (6 samples, 0.46%) + + + +org/mozilla/javascript/ScriptRuntime:.getPropFunctionAndThisHelper (1 samples, 0.08%) + + + +do_softirq (38 samples, 2.89%) +do.. + + +response_complete (2 samples, 0.15%) + + + +get_next_timer_interrupt (3 samples, 0.23%) + + + +__perf_event_enable (4 samples, 0.30%) + + + +_raw_spin_lock_irqsave (1 samples, 0.08%) + + + +lapic_next_deadline (3 samples, 0.23%) + + + +org/mozilla/javascript/ScriptableObject:.createSlot (4 samples, 0.30%) + + + +fput (1 samples, 0.08%) + + + +tcp_rearm_rto (3 samples, 0.23%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (2 samples, 0.15%) + + + +group_sched_in (4 samples, 0.30%) + + + +__getnstimeofday (1 samples, 0.08%) + + + +java/util/Arrays:.copyOf (1 samples, 0.08%) + + + +local_bh_enable (104 samples, 7.91%) +local_bh_en.. + + +tcp_event_new_data_sent (3 samples, 0.23%) + + + +read_tsc (2 samples, 0.15%) + + + +system_call_fastpath (6 samples, 0.46%) + + + +tcp_prequeue (1 samples, 0.08%) + + + +call_function_single_interrupt (4 samples, 0.30%) + + + +get_page_from_freelist (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject$Slot:.setAttributes (5 samples, 0.38%) + + + +io/netty/channel/AbstractChannelHandlerContext:.read (4 samples, 0.30%) + + + +org/vertx/java/core/http/impl/VertxHttpHandler:.write (34 samples, 2.59%) +or.. + + +_raw_spin_lock_irqsave (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.splitInitialLine (5 samples, 0.38%) + + + +org/mozilla/javascript/ScriptableObject:.getParentScope (4 samples, 0.30%) + + + +org/mozilla/javascript/IdScriptableObject:.get (3 samples, 0.23%) + + + +org/mozilla/javascript/ScriptRuntime:.getObjectProp (1 samples, 0.08%) + + + +swapper (72 samples, 5.48%) +swapper + + +ktime_get (1 samples, 0.08%) + + + +_raw_spin_unlock_irqrestore (1 samples, 0.08%) + + + +java/lang/ThreadLocal:.get (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (416 samples, 31.63%) +org/mozilla/javascript/gen/file__root_vert_x_2_1_5.. + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +__schedule (4 samples, 0.30%) + + + +bictcp_cong_avoid (3 samples, 0.23%) + + + +tcp_rcv_space_adjust (2 samples, 0.15%) + + + +JavaThread::run (956 samples, 72.70%) +JavaThread::run + + +apparmor_socket_sendmsg (1 samples, 0.08%) + + + +InstanceKlass::oop_push_contents (8 samples, 0.61%) + + + +sun/nio/ch/SocketChannelImpl:.isConnected (1 samples, 0.08%) + + + +__libc_start_main (6 samples, 0.46%) + + + +tcp_is_cwnd_limited (2 samples, 0.15%) + + + +sun/nio/ch/FileDispatcherImpl:.write0 (203 samples, 15.44%) +sun/nio/ch/FileDispatch.. + + +internal_add_timer (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject$Slot:.setAttributes (2 samples, 0.15%) + + + +[unknown] (30 samples, 2.28%) +[.. + + +io/netty/buffer/AbstractByteBufAllocator:.heapBuffer (3 samples, 0.23%) + + + +__tcp_push_pending_frames (149 samples, 11.33%) +__tcp_push_pendi.. + + +ClassLoaderDataGraph::oops_do (1 samples, 0.08%) + + + +tick_nohz_stop_idle (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.executor (1 samples, 0.08%) + + + +__skb_clone (1 samples, 0.08%) + + + +tcp_ack (20 samples, 1.52%) + + + +__inet_lookup_established (4 samples, 0.30%) + + + +org/mozilla/javascript/NativeJavaMethod:.findFunction (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.createSlot (4 samples, 0.30%) + + + +enqueue_task (7 samples, 0.53%) + + + +sock_def_readable (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.addKnownAbsentSlot (1 samples, 0.08%) + + + +tcp_data_queue (39 samples, 2.97%) +tc.. + + +security_file_permission (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.executor (1 samples, 0.08%) + + + +sun/reflect/DelegatingMethodAccessorImpl:.invoke (66 samples, 5.02%) +sun/re.. + + +__skb_clone (1 samples, 0.08%) + + + +org/vertx/java/platform/impl/RhinoContextFactory:.onContextCreated (1 samples, 0.08%) + + + +tcp_poll (1 samples, 0.08%) + + + +netif_skb_dev_features (1 samples, 0.08%) + + + +ep_scan_ready_list.isra.9 (4 samples, 0.30%) + + + +native_write_msr_safe (4 samples, 0.30%) + + + +copy_user_generic_string (1 samples, 0.08%) + + + +intel_pmu_enable_all (4 samples, 0.30%) + + + +__switch_to (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.has (4 samples, 0.30%) + + + +__hrtimer_start_range_ns (3 samples, 0.23%) + + + +__srcu_read_lock (2 samples, 0.15%) + + + +io/netty/channel/AbstractChannelHandlerContext:.validatePromise (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.createSlot (11 samples, 0.84%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (8 samples, 0.61%) + + + +org/mozilla/javascript/NativeJavaMethod:.findCachedFunction (2 samples, 0.15%) + + + +sock_poll (1 samples, 0.08%) + + + +tick_program_event (3 samples, 0.23%) + + + +tcp_transmit_skb (55 samples, 4.18%) +tcp_.. + + +org/mozilla/javascript/NativeFunction:.initScriptFunction (1 samples, 0.08%) + + + +org/mozilla/javascript/WrapFactory:.wrap (5 samples, 0.38%) + + + +java/lang/String:.getBytes (3 samples, 0.23%) + + + +org/mozilla/javascript/NativeJavaObject:.initMembers (4 samples, 0.30%) + + + +bictcp_cong_avoid (1 samples, 0.08%) + + + +ktime_get_real (3 samples, 0.23%) + + + +java/lang/ThreadLocal:.get (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (21 samples, 1.60%) + + + +rcu_sysidle_force_exit (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject$Slot:.getValue (2 samples, 0.15%) + + + +aa_file_perm (1 samples, 0.08%) + + + +tick_sched_timer (1 samples, 0.08%) + + + +sk_reset_timer (3 samples, 0.23%) + + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (1 samples, 0.08%) + + + +msecs_to_jiffies (1 samples, 0.08%) + + + +ipv4_dst_check (1 samples, 0.08%) + + + +tcp_write_xmit (60 samples, 4.56%) +tcp_w.. + + +io/netty/util/Recycler:.recycle (1 samples, 0.08%) + + + +group_sched_in (4 samples, 0.30%) + + + +generic_exec_single (1 samples, 0.08%) + + + +menu_select (2 samples, 0.15%) + + + +org/mozilla/javascript/BaseFunction:.construct (1 samples, 0.08%) + + + +process_backlog (97 samples, 7.38%) +process_ba.. + + +__pthread_disable_asynccancel (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.decode (57 samples, 4.33%) +io/ne.. + + +schedule_preempt_disabled (4 samples, 0.30%) + + + +rcu_idle_exit (2 samples, 0.15%) + + + +tcp_send_mss (1 samples, 0.08%) + + + +[unknown] (26 samples, 1.98%) +[.. + + +org/mozilla/javascript/ScriptRuntime:.nameOrFunction (1 samples, 0.08%) + + + +inet_sendmsg (78 samples, 5.93%) +inet_se.. + + +__getnstimeofday (1 samples, 0.08%) + + + +kfree_skbmem (1 samples, 0.08%) + + + +smp_apic_timer_interrupt (1 samples, 0.08%) + + + +kmalloc_slab (2 samples, 0.15%) + + + +[unknown] (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.readHeaders (2 samples, 0.15%) + + + +ip_rcv_finish (32 samples, 2.43%) +ip.. + + +io/netty/channel/DefaultChannelPipeline$HeadContext:.read (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (8 samples, 0.61%) + + + +inet_ehashfn (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.createSlot (33 samples, 2.51%) +or.. + + +frame::oops_do_internal (1 samples, 0.08%) + + + +thread_entry (956 samples, 72.70%) +thread_entry + + +sun/nio/ch/SelectorImpl:.select (7 samples, 0.53%) + + + +_raw_spin_lock_irq (1 samples, 0.08%) + + + +ttwu_do_activate.constprop.74 (12 samples, 0.91%) + + + +skb_copy_datagram_iovec (1 samples, 0.08%) + + + +Interpreter (956 samples, 72.70%) +Interpreter + + +io/netty/handler/codec/http/HttpObjectDecoder:.readHeaders (22 samples, 1.67%) + + + +org/vertx/java/core/http/impl/DefaultHttpServer$ServerHandler:.doMessageReceived (540 samples, 41.06%) +org/vertx/java/core/http/impl/DefaultHttpServer$ServerHandler:.doM.. + + +_raw_spin_unlock_irqrestore (1 samples, 0.08%) + + + +fget_light (1 samples, 0.08%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.contains (1 samples, 0.08%) + + + +kfree_skbmem (1 samples, 0.08%) + + + +__alloc_pages_nodemask (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.addKnownAbsentSlot (1 samples, 0.08%) + + + +enqueue_task_fair (5 samples, 0.38%) + + + +perf_pmu_enable (4 samples, 0.30%) + + + +tcp_rcv_established (73 samples, 5.55%) +tcp_rcv.. + + +org/mozilla/javascript/NativeJavaObject:.initMembers (1 samples, 0.08%) + + + +vfs_write (192 samples, 14.60%) +vfs_write + + +fdval (1 samples, 0.08%) + + + +ip_queue_xmit (122 samples, 9.28%) +ip_queue_xmit + + +sock_aio_write (82 samples, 6.24%) +sock_aio.. + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_streams_j (1 samples, 0.08%) + + + +aeMain (236 samples, 17.95%) +aeMain + + +io/netty/channel/ChannelDuplexHandler:.read (3 samples, 0.23%) + + + +org/vertx/java/core/http/impl/AssembledFullHttpResponse:.toLastContent (2 samples, 0.15%) + + + +internal_add_timer (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +vtable stub (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.getParentScope (1 samples, 0.08%) + + + +io/netty/buffer/PooledByteBufAllocator:.newDirectBuffer (2 samples, 0.15%) + + + +SpinPause (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.has (3 samples, 0.23%) + + + +java/nio/charset/CharsetEncoder:.replaceWith (2 samples, 0.15%) + + + +tcp_queue_rcv (2 samples, 0.15%) + + + +stats_record (3 samples, 0.23%) + + + +org/mozilla/javascript/WrapFactory:.wrap (5 samples, 0.38%) + + + +__wake_up_sync_key (27 samples, 2.05%) +_.. + + +__acct_update_integrals (1 samples, 0.08%) + + + +fget_light (1 samples, 0.08%) + + + +local_bh_enable (1 samples, 0.08%) + + + +eth_type_trans (1 samples, 0.08%) + + + +org/vertx/java/core/net/impl/VertxHandler:.channelRead (555 samples, 42.21%) +org/vertx/java/core/net/impl/VertxHandler:.channelRead + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +sock_put (1 samples, 0.08%) + + + +__kfree_skb (3 samples, 0.23%) + + + +dequeue_task (7 samples, 0.53%) + + + +io/netty/channel/AbstractChannelHandlerContext:.executor (1 samples, 0.08%) + + + +ip_rcv_finish (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.getObjectProp (4 samples, 0.30%) + + + +__tick_nohz_idle_enter (4 samples, 0.30%) + + + +__tcp_ack_snd_check (3 samples, 0.23%) + + + +[unknown] (4 samples, 0.30%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +org/mozilla/javascript/NativeFunction:.initScriptFunction (2 samples, 0.15%) + + + +int_sqrt (1 samples, 0.08%) + + + +nmethod::fix_oop_relocations (1 samples, 0.08%) + + + +tcp_sendmsg (1 samples, 0.08%) + + + +java/lang/ThreadLocal:.get (1 samples, 0.08%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +org/mozilla/javascript/BaseFunction:.findPrototypeId (1 samples, 0.08%) + + + +native_write_msr_safe (3 samples, 0.23%) + + + +perf_pmu_enable (4 samples, 0.30%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (77 samples, 5.86%) +org/moz.. + + +__netif_receive_skb_core (94 samples, 7.15%) +__netif_r.. + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +hrtimer_start (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptRuntime:.setName (5 samples, 0.38%) + + + +__netif_receive_skb (94 samples, 7.15%) +__netif_r.. + + +change_protection (1 samples, 0.08%) + + + +io/netty/channel/ChannelOutboundBuffer:.current (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.flush (233 samples, 17.72%) +io/netty/channel/AbstractCh.. + + +do_softirq_own_stack (103 samples, 7.83%) +do_softirq_.. + + +do_filp_open (1 samples, 0.08%) + + + +x86_pmu_commit_txn (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +io/netty/util/Recycler:.get (1 samples, 0.08%) + + + +_raw_spin_lock (1 samples, 0.08%) + + + +sun/nio/ch/SocketChannelImpl:.isConnected (1 samples, 0.08%) + + + +change_protection_range (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (12 samples, 0.91%) + + + +__libc_write (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (513 samples, 39.01%) +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_.. + + +raw_local_deliver (1 samples, 0.08%) + + + +apparmor_file_permission (1 samples, 0.08%) + + + +VMThread::loop (1 samples, 0.08%) + + + +_raw_spin_unlock_irqrestore (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.newPromise (1 samples, 0.08%) + + + +epoll_ctl (7 samples, 0.53%) + + + +io/netty/handler/codec/http/HttpVersion:.compareTo (1 samples, 0.08%) + + + +io/netty/channel/nio/NioEventLoop:.processSelectedKeys (949 samples, 72.17%) +io/netty/channel/nio/NioEventLoop:.processSelectedKeys + + +io/netty/handler/codec/http/DefaultHttpHeaders:.init (1 samples, 0.08%) + + + +java/lang/String:.hashCode (2 samples, 0.15%) + + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (1 samples, 0.08%) + + + +effective_load.isra.35 (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (2 samples, 0.15%) + + + +rcu_sysidle_exit (1 samples, 0.08%) + + + +native_load_tls (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +org/mozilla/javascript/BaseFunction:.findPrototypeId (1 samples, 0.08%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_streams_j (6 samples, 0.46%) + + + +system_call_fastpath (22 samples, 1.67%) + + + +org/mozilla/javascript/TopLevel:.getBuiltinPrototype (1 samples, 0.08%) + + + +tcp_current_mss (5 samples, 0.38%) + + + +io/netty/channel/ChannelOutboundBuffer:.incrementPendingOutboundBytes (1 samples, 0.08%) + + + +oopDesc* PSPromotionManager::copy_to_survivor_spacefalse (2 samples, 0.15%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (156 samples, 11.86%) +org/mozilla/javas.. + + +StealTask::do_it (3 samples, 0.23%) + + + +Interpreter (956 samples, 72.70%) +Interpreter + + +PSPromotionManager::drain_stacks_depth (2 samples, 0.15%) + + + +sock_def_readable (32 samples, 2.43%) +so.. + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (1 samples, 0.08%) + + + +perf (6 samples, 0.46%) + + + +__wake_up_common (27 samples, 2.05%) +_.. + + +org/mozilla/javascript/IdScriptableObject:.has (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpObjectDecoder$HeaderParser:.process (1 samples, 0.08%) + + + +common_file_perm (1 samples, 0.08%) + + + +io/netty/buffer/AbstractReferenceCountedByteBuf:.release (5 samples, 0.38%) + + + +hrtimer_force_reprogram (3 samples, 0.23%) + + + +org/vertx/java/core/impl/DefaultVertx:.setContext (1 samples, 0.08%) + + + +msecs_to_jiffies (1 samples, 0.08%) + + + +arch_cpu_idle (7 samples, 0.53%) + + + +[unknown] (91 samples, 6.92%) +[unknown] + + +tcp_cleanup_rbuf (1 samples, 0.08%) + + + +release_sock (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.flush (235 samples, 17.87%) +io/netty/channel/AbstractCh.. + + +io/netty/channel/AbstractChannelHandlerContext:.fireChannelReadComplete (1 samples, 0.08%) + + + +fput (2 samples, 0.15%) + + + +bictcp_acked (1 samples, 0.08%) + + + +java/nio/DirectByteBuffer:.duplicate (1 samples, 0.08%) + + + +io/netty/buffer/AbstractByteBuf:.checkIndex (3 samples, 0.23%) + + + +java/util/HashMap:.getNode (2 samples, 0.15%) + + + +ttwu_stat (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpHeaders:.hash (1 samples, 0.08%) + + + +org/vertx/java/core/net/impl/ConnectionBase:.write (38 samples, 2.89%) +or.. + + +local_apic_timer_interrupt (1 samples, 0.08%) + + + +inet_ehashfn (1 samples, 0.08%) + + + +__srcu_read_unlock (1 samples, 0.08%) + + + +java/nio/channels/spi/AbstractInterruptibleChannel:.begin (1 samples, 0.08%) + + + +skb_clone (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.fireChannelRead (562 samples, 42.74%) +io/netty/channel/AbstractChannelHandlerContext:.fireChannelRead + + +ip_local_deliver (89 samples, 6.77%) +ip_local_.. + + +org/mozilla/javascript/ScriptableObject:.createSlot (8 samples, 0.61%) + + + +itable stub (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +__do_softirq (36 samples, 2.74%) +__.. + + +io/netty/handler/codec/http/HttpMethod:.valueOf (2 samples, 0.15%) + + + +clockevents_program_event (3 samples, 0.23%) + + + +tcp_set_skb_tso_segs (1 samples, 0.08%) + + + +io/netty/buffer/AbstractByteBuf:.checkSrcIndex (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpVersion:.compareTo (2 samples, 0.15%) + + + +ttwu_do_activate.constprop.74 (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject$Slot:.setAttributes (6 samples, 0.46%) + + + +cpuidle_idle_call (21 samples, 1.60%) + + + +__hrtimer_start_range_ns (2 samples, 0.15%) + + + +io/netty/channel/ChannelOutboundHandlerAdapter:.read (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptRuntime:.bind (7 samples, 0.53%) + + + +x86_pmu_enable (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +sun/nio/ch/EPollArrayWrapper:.poll (5 samples, 0.38%) + + + +org/mozilla/javascript/IdScriptableObject:.setAttributes (12 samples, 0.91%) + + + +sock_read (3 samples, 0.23%) + + + +HandleArea::oops_do (1 samples, 0.08%) + + + +tcp_v4_send_check (1 samples, 0.08%) + + + +tcp_wfree (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject$Slot:.getValue (1 samples, 0.08%) + + + +sun/nio/ch/FileDispatcherImpl:.read0 (1 samples, 0.08%) + + + +org/vertx/java/core/net/impl/VertxHandler:.channelReadComplete (240 samples, 18.25%) +org/vertx/java/core/net/impl.. + + +rcu_bh_qs (1 samples, 0.08%) + + + +lock_timer_base.isra.35 (1 samples, 0.08%) + + + +io/netty/buffer/PooledUnsafeDirectByteBuf:.setBytes (42 samples, 3.19%) +io/.. + + +sun/nio/cs/UTF_8$Encoder:.init (3 samples, 0.23%) + + + +io/netty/channel/ChannelDuplexHandler:.read (1 samples, 0.08%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +account_entity_dequeue (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.executor (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (17 samples, 1.29%) + + + +io/netty/handler/codec/http/HttpObjectEncoder:.encode (17 samples, 1.29%) + + + +org/mozilla/javascript/ScriptableObject:.addKnownAbsentSlot (2 samples, 0.15%) + + + +ksize (1 samples, 0.08%) + + + +[unknown] (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptRuntime:.toObjectOrNull (2 samples, 0.15%) + + + +fget_light (1 samples, 0.08%) + + + +sched_clock_idle_sleep_event (1 samples, 0.08%) + + + +sock_aio_write (185 samples, 14.07%) +sock_aio_write + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_streams_j (1 samples, 0.08%) + + + +smp_call_function_single (5 samples, 0.38%) + + + +org/mozilla/javascript/TopLevel:.getBuiltinPrototype (1 samples, 0.08%) + + + +ip_rcv (91 samples, 6.92%) +ip_rcv + + +tcp_sendmsg (176 samples, 13.38%) +tcp_sendmsg + + +release_sock (1 samples, 0.08%) + + + +ep_poll_callback (27 samples, 2.05%) +e.. + + +update_min_vruntime (1 samples, 0.08%) + + + +java/lang/Integer:.toString (1 samples, 0.08%) + + + +itable stub (1 samples, 0.08%) + + + +do_softirq_own_stack (37 samples, 2.81%) +do.. + + +io/netty/buffer/AbstractByteBufAllocator:.heapBuffer (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (3 samples, 0.23%) + + + +org/mozilla/javascript/ScriptableObject:.addKnownAbsentSlot (1 samples, 0.08%) + + + +sched_clock_cpu (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpHeaders:.encodeAscii0 (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptRuntime:.toObjectOrNull (1 samples, 0.08%) + + + +inet_sendmsg (1 samples, 0.08%) + + + +VMThread::run (1 samples, 0.08%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.init (1 samples, 0.08%) + + + +java/util/HashMap:.getNode (2 samples, 0.15%) + + + +__run_hrtimer (1 samples, 0.08%) + + + +java/nio/channels/spi/AbstractInterruptibleChannel:.begin (1 samples, 0.08%) + + + +io/netty/handler/codec/http/HttpHeaders:.hash (1 samples, 0.08%) + + + +sun/nio/ch/EPollSelectorImpl:.updateSelectedKeys (1 samples, 0.08%) + + + +x86_pmu_enable (4 samples, 0.30%) + + + +thread_main (237 samples, 18.02%) +thread_main + + +enqueue_hrtimer (1 samples, 0.08%) + + + +ep_poll (4 samples, 0.30%) + + + +sock_aio_read (7 samples, 0.53%) + + + +io/netty/buffer/AbstractByteBuf:.checkSrcIndex (3 samples, 0.23%) + + + +sock_aio_read (22 samples, 1.67%) + + + +io/netty/handler/codec/http/HttpObjectDecoder$LineParser:.parse (6 samples, 0.46%) + + + +sys_epoll_ctl (5 samples, 0.38%) + + + +java/lang/String:.init (4 samples, 0.30%) + + + +rb_erase (1 samples, 0.08%) + + + +select_estimate_accuracy (5 samples, 0.38%) + + + +link_path_walk (1 samples, 0.08%) + + + +sock_aio_read.part.8 (22 samples, 1.67%) + + + +local_bh_enable_ip (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (3 samples, 0.23%) + + + +__tcp_select_window (1 samples, 0.08%) + + + +fget_light (1 samples, 0.08%) + + + +io/netty/buffer/AbstractReferenceCountedByteBuf:.release (4 samples, 0.30%) + + + +acct_account_cputime (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.put (1 samples, 0.08%) + + + +__perf_event_enable (4 samples, 0.30%) + + + +ip_finish_output (46 samples, 3.50%) +ip_.. + + +__tick_nohz_idle_enter (6 samples, 0.46%) + + + +__skb_clone (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptableObject:.getPrototype (1 samples, 0.08%) + + + +__switch_to (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.write (35 samples, 2.66%) +io.. + + +_raw_spin_lock (1 samples, 0.08%) + + + +_raw_spin_unlock_irqrestore (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.setObjectProp (3 samples, 0.23%) + + + +org/mozilla/javascript/IdScriptableObject:.has (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (2 samples, 0.15%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +idle_cpu (2 samples, 0.15%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +io/netty/util/Recycler:.get (1 samples, 0.08%) + + + +native_write_msr_safe (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (2 samples, 0.15%) + + + +ip_output (119 samples, 9.05%) +ip_output + + +io/netty/buffer/AbstractByteBuf:.forEachByteAsc0 (3 samples, 0.23%) + + + +skb_network_protocol (1 samples, 0.08%) + + + +enqueue_entity (5 samples, 0.38%) + + + +tcp_established_options (1 samples, 0.08%) + + + +update_process_times (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.read (3 samples, 0.23%) + + + +update_rq_clock.part.63 (1 samples, 0.08%) + + + +sun/nio/ch/EPollArrayWrapper:.epollWait (4 samples, 0.30%) + + + +sock_poll (2 samples, 0.15%) + + + +io/netty/channel/nio/NioEventLoop:.processSelectedKeysOptimized (949 samples, 72.17%) +io/netty/channel/nio/NioEventLoop:.processSelectedKeysOptimized + + +java_start (985 samples, 74.90%) +java_start + + +mprotect_fixup (1 samples, 0.08%) + + + +ep_scan_ready_list.isra.9 (20 samples, 1.52%) + + + +tcp_v4_do_rcv (23 samples, 1.75%) + + + +sk_stream_alloc_skb (7 samples, 0.53%) + + + +update_curr (2 samples, 0.15%) + + + +tcp_wfree (2 samples, 0.15%) + + + +user_path_at_empty (1 samples, 0.08%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.init (1 samples, 0.08%) + + + +io/netty/buffer/AbstractByteBuf:.writeBytes (1 samples, 0.08%) + + + +sun/nio/ch/NativeThread:.current (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.get (1 samples, 0.08%) + + + +JavaThread::oops_do (3 samples, 0.23%) + + + +org/mozilla/javascript/ScriptableObject:.getBase (2 samples, 0.15%) + + + +ip_local_deliver (1 samples, 0.08%) + + + +org/vertx/java/core/http/impl/ServerConnection:.handleRequest (526 samples, 40.00%) +org/vertx/java/core/http/impl/ServerConnection:.handleRequest + + +__hrtimer_start_range_ns (3 samples, 0.23%) + + + +org/mozilla/javascript/NativeFunction:.initScriptFunction (10 samples, 0.76%) + + + +hrtimer_start (1 samples, 0.08%) + + + +intel_idle (11 samples, 0.84%) + + + +org/mozilla/javascript/IdScriptableObject:.has (3 samples, 0.23%) + + + +ktime_get (1 samples, 0.08%) + + + +update_cfs_rq_blocked_load (1 samples, 0.08%) + + + +org/mozilla/javascript/WrapFactory:.setJavaPrimitiveWrap (1 samples, 0.08%) + + + +sun/nio/ch/NativeThread:.current (1 samples, 0.08%) + + + +system_call_fastpath (28 samples, 2.13%) +s.. + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +sched_clock_cpu (1 samples, 0.08%) + + + +lapic_next_deadline (3 samples, 0.23%) + + + +io/netty/buffer/UnpooledHeapByteBuf:.init (1 samples, 0.08%) + + + +filename_lookup (1 samples, 0.08%) + + + +jni_fast_GetIntField (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.put (6 samples, 0.46%) + + + +x86_pmu_commit_txn (4 samples, 0.30%) + + + +__kfree_skb (1 samples, 0.08%) + + + +org/mozilla/javascript/NativeJavaMethod:.call (10 samples, 0.76%) + + + +process_backlog (34 samples, 2.59%) +pr.. + + +all (1,315 samples, 100%) + + + +io/netty/handler/codec/http/HttpHeaders:.encodeAscii0 (2 samples, 0.15%) + + + +system_call_after_swapgs (6 samples, 0.46%) + + + +_raw_spin_unlock_bh (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +tcp_event_new_data_sent (6 samples, 0.46%) + + + +_raw_spin_unlock_bh (1 samples, 0.08%) + + + +tcp_schedule_loss_probe (3 samples, 0.23%) + + + +tcp_check_space (3 samples, 0.23%) + + + +dev_queue_xmit (4 samples, 0.30%) + + + +tick_nohz_restart (6 samples, 0.46%) + + + +__tcp_ack_snd_check (5 samples, 0.38%) + + + +user_path_at (1 samples, 0.08%) + + + +socket_readable (60 samples, 4.56%) +socke.. + + +org/mozilla/javascript/ScriptableObject:.getSlot (4 samples, 0.30%) + + + +OopMapSet::all_do (1 samples, 0.08%) + + + +socket_writeable (1 samples, 0.08%) + + + +internal_add_timer (1 samples, 0.08%) + + + +select_task_rq_fair (4 samples, 0.30%) + + + +loopback_xmit (5 samples, 0.38%) + + + +sys_epoll_wait (56 samples, 4.26%) +sys_e.. + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +clockevents_program_event (3 samples, 0.23%) + + + +io/netty/buffer/PooledByteBuf:.deallocate (2 samples, 0.15%) + + + +io/netty/util/Recycler:.get (1 samples, 0.08%) + + + +fsnotify (1 samples, 0.08%) + + + +org/mozilla/javascript/NativeJavaMethod:.call (74 samples, 5.63%) +org/moz.. + + +org/mozilla/javascript/ScriptRuntime:.setObjectProp (37 samples, 2.81%) +or.. + + +schedule_preempt_disabled (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.flush (238 samples, 18.10%) +io/netty/channel/AbstractCha.. + + +tcp_queue_rcv (2 samples, 0.15%) + + + +org/mozilla/javascript/ScriptableObject:.createSlot (5 samples, 0.38%) + + + +tcp_recvmsg (7 samples, 0.53%) + + + +update_curr (1 samples, 0.08%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +tcp_md5_do_lookup (1 samples, 0.08%) + + + +smp_call_function_single_interrupt (4 samples, 0.30%) + + + +netif_rx (2 samples, 0.15%) + + + +enqueue_to_backlog (1 samples, 0.08%) + + + +_raw_spin_unlock_bh (1 samples, 0.08%) + + + +perf_ioctl (5 samples, 0.38%) + + + +tick_program_event (3 samples, 0.23%) + + + +io/netty/handler/codec/ByteToMessageDecoder:.channelRead (635 samples, 48.29%) +io/netty/handler/codec/ByteToMessageDecoder:.channelRead + + +put_prev_task_fair (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.createSlot (15 samples, 1.14%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +sys_mprotect (1 samples, 0.08%) + + + +Monitor::wait (1 samples, 0.08%) + + + +skb_push (1 samples, 0.08%) + + + +java/lang/ThreadLocal:.get (1 samples, 0.08%) + + + +vtable stub (1 samples, 0.08%) + + + +x86_64_start_kernel (24 samples, 1.83%) +x.. + + +[unknown] (1 samples, 0.08%) + + + +kfree (1 samples, 0.08%) + + + +io/netty/channel/AbstractChannelHandlerContext:.fireChannelReadComplete (241 samples, 18.33%) +io/netty/channel/AbstractCha.. + + +io/netty/buffer/AbstractByteBuf:.forEachByteAsc0 (3 samples, 0.23%) + + + +Java_sun_nio_ch_FileDispatcherImpl_write0 (1 samples, 0.08%) + + + +do_execve_common.isra.22 (1 samples, 0.08%) + + + +group_sched_in (4 samples, 0.30%) + + + +socket_writeable (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject$RelinkedSlot:.getValue (1 samples, 0.08%) + + + +java/lang/String:.hashCode (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getTopLevelScope (1 samples, 0.08%) + + + +kmem_cache_alloc_node (2 samples, 0.15%) + + + +org/mozilla/javascript/IdScriptableObject:.has (12 samples, 0.91%) + + + +getnstimeofday (1 samples, 0.08%) + + + +java/util/Arrays:.copyOf (1 samples, 0.08%) + + + +arch_cpu_idle (22 samples, 1.67%) + + + +http_parser_execute (30 samples, 2.28%) +h.. + + +new_slab (2 samples, 0.15%) + + + +io/netty/channel/ChannelDuplexHandler:.flush (1 samples, 0.08%) + + + +generic_smp_call_function_single_interrupt (4 samples, 0.30%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.contains (1 samples, 0.08%) + + + +java/lang/ThreadLocal:.get (1 samples, 0.08%) + + + +security_socket_sendmsg (1 samples, 0.08%) + + + +update_cpu_load_nohz (1 samples, 0.08%) + + + +__perf_event_enable (4 samples, 0.30%) + + + +skb_clone (1 samples, 0.08%) + + + +start_thread (237 samples, 18.02%) +start_thread + + +mod_timer (3 samples, 0.23%) + + + +tcp_data_queue (9 samples, 0.68%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (1 samples, 0.08%) + + + +java/lang/String:.trim (1 samples, 0.08%) + + + +net_rx_action (35 samples, 2.66%) +ne.. + + +inet_sendmsg (177 samples, 13.46%) +inet_sendmsg + + +getnstimeofday (3 samples, 0.23%) + + + +io/netty/buffer/AbstractByteBuf:.writeBytes (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getSlot (3 samples, 0.23%) + + + +[unknown] (1 samples, 0.08%) + + + +hrtimer_try_to_cancel (4 samples, 0.30%) + + + +java/nio/charset/Charset:.lookup (2 samples, 0.15%) + + + +org/mozilla/javascript/NativeJavaObject:.initMembers (1 samples, 0.08%) + + + +start_thread (985 samples, 74.90%) +start_thread + + +x86_pmu_commit_txn (4 samples, 0.30%) + + + +org/mozilla/javascript/ScriptableObject:.getParentScope (1 samples, 0.08%) + + + +system_call_fastpath (5 samples, 0.38%) + + + +_raw_spin_lock (1 samples, 0.08%) + + + +menu_select (4 samples, 0.30%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.add0 (3 samples, 0.23%) + + + +io/netty/buffer/PooledByteBuf:.deallocate (2 samples, 0.15%) + + + +org/mozilla/javascript/BaseFunction:.findInstanceIdInfo (4 samples, 0.30%) + + + +rest_init (24 samples, 1.83%) +r.. + + +ksoftirqd/3 (1 samples, 0.08%) + + + +group_sched_in (4 samples, 0.30%) + + + +account_user_time (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.name (8 samples, 0.61%) + + + +perf_event_for_each_child (5 samples, 0.38%) + + + +io/netty/handler/codec/http/HttpObjectDecoder:.findWhitespace (1 samples, 0.08%) + + + +java/lang/String:.init (1 samples, 0.08%) + + + +set_next_entity (2 samples, 0.15%) + + + +ip_local_deliver_finish (89 samples, 6.77%) +ip_local_.. + + +org/mozilla/javascript/NativeJavaMethod:.findCachedFunction (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.put (12 samples, 0.91%) + + + +hrtimer_start_range_ns (2 samples, 0.15%) + + + +__internal_add_timer (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.getPropFunctionAndThisHelper (9 samples, 0.68%) + + + +smp_call_function_single_interrupt (4 samples, 0.30%) + + + +_raw_spin_lock_bh (1 samples, 0.08%) + + + +__hrtimer_start_range_ns (1 samples, 0.08%) + + + +lock_sock_nested (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject$PrototypeValues:.ensureId (1 samples, 0.08%) + + + +sk_reset_timer (3 samples, 0.23%) + + + +org/mozilla/javascript/gen/file__root_vert_x_2_1_5_sys_mods_io_vertx_lang_js_1_1_0_vertx_http_js_2 (154 samples, 11.71%) +org/mozilla/javas.. + + +io/netty/handler/codec/ByteToMessageDecoder:.channelRead (1 samples, 0.08%) + + + +security_socket_sendmsg (2 samples, 0.15%) + + + +io/netty/handler/codec/http/DefaultHttpHeaders:.add0 (1 samples, 0.08%) + + + +system_call_after_swapgs (1 samples, 0.08%) + + + +hrtimer_cancel (4 samples, 0.30%) + + + +ObjArrayKlass::oop_push_contents (2 samples, 0.15%) + + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (1 samples, 0.08%) + + + +org/mozilla/javascript/IdScriptableObject:.has (1 samples, 0.08%) + + + +schedule_hrtimeout_range (20 samples, 1.52%) + + + +org/mozilla/javascript/ScriptableObject:.putImpl (24 samples, 1.83%) +o.. + + +__fsnotify_parent (1 samples, 0.08%) + + + +vtable stub (1 samples, 0.08%) + + + +__dev_queue_xmit (10 samples, 0.76%) + + + +sys_write (88 samples, 6.69%) +sys_write + + +detach_if_pending (1 samples, 0.08%) + + + +socket_writeable (99 samples, 7.53%) +socket_wri.. + + +org/mozilla/javascript/IdScriptableObject:.findInstanceIdInfo (2 samples, 0.15%) + + + +epoll_ctl (6 samples, 0.46%) + + + +org/vertx/java/core/http/impl/AssembledFullHttpResponse:.toLastContent (1 samples, 0.08%) + + + +org/mozilla/javascript/NativeJavaObject:.get (1 samples, 0.08%) + + + +lock_hrtimer_base.isra.19 (1 samples, 0.08%) + + + +intel_idle (3 samples, 0.23%) + + + +ip_local_deliver (31 samples, 2.36%) +i.. + + +org/mozilla/javascript/IdScriptableObject:.put (23 samples, 1.75%) + + + +io/netty/handler/codec/ByteToMessageDecoder:.channelReadComplete (242 samples, 18.40%) +io/netty/handler/codec/ByteT.. + + +tcp_event_data_recv (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptableObject:.getTopScopeValue (1 samples, 0.08%) + + + +tcp_rearm_rto (3 samples, 0.23%) + + + +org/mozilla/javascript/NativeCall:.init (48 samples, 3.65%) +org/.. + + +tick_nohz_idle_enter (5 samples, 0.38%) + + + +system_call_fastpath (4 samples, 0.30%) + + + +system_call (1 samples, 0.08%) + + + +tick_nohz_idle_enter (6 samples, 0.46%) + + + +tick_program_event (1 samples, 0.08%) + + + +org/mozilla/javascript/ScriptRuntime:.getPropFunctionAndThisHelper (1 samples, 0.08%) + + + +remote_function (4 samples, 0.30%) + + + +tcp_clean_rtx_queue (1 samples, 0.08%) + + + +tick_nohz_idle_exit (7 samples, 0.53%) + + + +org/mozilla/javascript/IdScriptableObject:.put (9 samples, 0.68%) + + + +fsnotify (1 samples, 0.08%) + + + +pick_next_task_fair (2 samples, 0.15%) + + + +do_sync_write (82 samples, 6.24%) +do_sync_.. + + +sys_write (195 samples, 14.83%) +sys_write + + +common_file_perm (1 samples, 0.08%) + + + +account_process_tick (1 samples, 0.08%) + + + diff --git a/tests/benchmarks/_script/flamegraph/files.pl b/tests/benchmarks/_script/flamegraph/files.pl new file mode 100755 index 00000000000..50426b2e47c --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/files.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -w +# +# files.pl Print file sizes in folded format, for a flame graph. +# +# This helps you understand storage consumed by a file system, by creating +# a flame graph visualization of space consumed. This is basically a Perl +# version of the "find" command, which emits in folded format for piping +# into flamegraph.pl. +# +# Copyright (c) 2017 Brendan Gregg. +# Licensed under the Apache License, Version 2.0 (the "License") +# +# 03-Feb-2017 Brendan Gregg Created this. + +use strict; +use File::Find; + +sub usage { + print STDERR "USAGE: $0 [--xdev] [DIRECTORY]...\n"; + print STDERR " eg, $0 /Users\n"; + print STDERR " To not descend directories on other filesystems:"; + print STDERR " eg, $0 --xdev /\n"; + print STDERR "Intended to be piped to flamegraph.pl. Full example:\n"; + print STDERR " $0 /Users | flamegraph.pl " . + "--hash --countname=bytes > files.svg\n"; + print STDERR " $0 /usr /home /root /etc | flamegraph.pl " . + "--hash --countname=bytes > files.svg\n"; + print STDERR " $0 --xdev / | flamegraph.pl " . + "--hash --countname=bytes > files.svg\n"; + exit 1; +} + +usage() if @ARGV == 0 or $ARGV[0] eq "--help" or $ARGV[0] eq "-h"; + +my $filter_xdev = 0; +my $xdev_id; + +foreach my $dir (@ARGV) { + if ($dir eq "--xdev") { + $filter_xdev = 1; + } else { + find(\&wanted, $dir); + } +} + +sub wanted { + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size) = lstat($_); + return unless defined $size; + if ($filter_xdev) { + if (!$xdev_id) { + $xdev_id = $dev; + } elsif ($xdev_id ne $dev) { + $File::Find::prune = 1; + return; + } + } + my $path = $File::Find::name; + $path =~ tr/\//;/; # delimiter + $path =~ tr/;.a-zA-Z0-9-/_/c; # ditch whitespace and other chars + $path =~ s/^;//; + print "$path $size\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/flamegraph.pl b/tests/benchmarks/_script/flamegraph/flamegraph.pl new file mode 100755 index 00000000000..ad35f6f7751 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/flamegraph.pl @@ -0,0 +1,1303 @@ +#!/usr/bin/perl -w +# +# flamegraph.pl flame stack grapher. +# +# This takes stack samples and renders a call graph, allowing hot functions +# and codepaths to be quickly identified. Stack samples can be generated using +# tools such as DTrace, perf, SystemTap, and Instruments. +# +# USAGE: ./flamegraph.pl [options] input.txt > graph.svg +# +# grep funcA input.txt | ./flamegraph.pl [options] > graph.svg +# +# Then open the resulting .svg in a web browser, for interactivity: mouse-over +# frames for info, click to zoom, and ctrl-F to search. +# +# Options are listed in the usage message (--help). +# +# The input is stack frames and sample counts formatted as single lines. Each +# frame in the stack is semicolon separated, with a space and count at the end +# of the line. These can be generated for Linux perf script output using +# stackcollapse-perf.pl, for DTrace using stackcollapse.pl, and for other tools +# using the other stackcollapse programs. Example input: +# +# swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 1 +# +# An optional extra column of counts can be provided to generate a differential +# flame graph of the counts, colored red for more, and blue for less. This +# can be useful when using flame graphs for non-regression testing. +# See the header comment in the difffolded.pl program for instructions. +# +# The input functions can optionally have annotations at the end of each +# function name, following a precedent by some tools (Linux perf's _[k]): +# _[k] for kernel +# _[i] for inlined +# _[j] for jit +# _[w] for waker +# Some of the stackcollapse programs support adding these annotations, eg, +# stackcollapse-perf.pl --kernel --jit. They are used merely for colors by +# some palettes, eg, flamegraph.pl --color=java. +# +# The output flame graph shows relative presence of functions in stack samples. +# The ordering on the x-axis has no meaning; since the data is samples, time +# order of events is not known. The order used sorts function names +# alphabetically. +# +# While intended to process stack samples, this can also process stack traces. +# For example, tracing stacks for memory allocation, or resource usage. You +# can use --title to set the title to reflect the content, and --countname +# to change "samples" to "bytes" etc. +# +# There are a few different palettes, selectable using --color. By default, +# the colors are selected at random (except for differentials). Functions +# called "-" will be printed gray, which can be used for stack separators (eg, +# between user and kernel stacks). +# +# HISTORY +# +# This was inspired by Neelakanth Nadgir's excellent function_call_graph.rb +# program, which visualized function entry and return trace events. As Neel +# wrote: "The output displayed is inspired by Roch's CallStackAnalyzer which +# was in turn inspired by the work on vftrace by Jan Boerhout". See: +# https://blogs.oracle.com/realneel/entry/visualizing_callstacks_via_dtrace_and +# +# Copyright 2016 Netflix, Inc. +# Copyright 2011 Joyent, Inc. All rights reserved. +# Copyright 2011 Brendan Gregg. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# 11-Oct-2014 Adrien Mahieux Added zoom. +# 21-Nov-2013 Shawn Sterling Added consistent palette file option +# 17-Mar-2013 Tim Bunce Added options and more tunables. +# 15-Dec-2011 Dave Pacheco Support for frames with whitespace. +# 10-Sep-2011 Brendan Gregg Created this. + +use strict; + +use Getopt::Long; + +use open qw(:std :utf8); + +# tunables +my $encoding; +my $fonttype = "Verdana"; +my $imagewidth = 1200; # max width, pixels +my $frameheight = 16; # max height is dynamic +my $fontsize = 12; # base text size +my $fontwidth = 0.59; # avg width relative to fontsize +my $minwidth = 0.1; # min function width, pixels or percentage of time +my $nametype = "Function:"; # what are the names in the data? +my $countname = "samples"; # what are the counts in the data? +my $colors = "hot"; # color theme +my $bgcolors = ""; # background color theme +my $nameattrfile; # file holding function attributes +my $timemax; # (override the) sum of the counts +my $factor = 1; # factor to scale counts by +my $hash = 0; # color by function name +my $rand = 0; # color randomly +my $palette = 0; # if we use consistent palettes (default off) +my %palette_map; # palette map hash +my $pal_file = "palette.map"; # palette map file name +my $stackreverse = 0; # reverse stack order, switching merge end +my $inverted = 0; # icicle graph +my $flamechart = 0; # produce a flame chart (sort by time, do not merge stacks) +my $negate = 0; # switch differential hues +my $titletext = ""; # centered heading +my $titledefault = "Flame Graph"; # overwritten by --title +my $titleinverted = "Icicle Graph"; # " " +my $searchcolor = "rgb(230,0,230)"; # color for search highlighting +my $notestext = ""; # embedded notes in SVG +my $subtitletext = ""; # second level title (optional) +my $help = 0; + +sub usage { + die < outfile.svg\n + --title TEXT # change title text + --subtitle TEXT # second level title (optional) + --width NUM # width of image (default 1200) + --height NUM # height of each frame (default 16) + --minwidth NUM # omit smaller functions. In pixels or use "%" for + # percentage of time (default 0.1 pixels) + --fonttype FONT # font type (default "Verdana") + --fontsize NUM # font size (default 12) + --countname TEXT # count type label (default "samples") + --nametype TEXT # name type label (default "Function:") + --colors PALETTE # set color palette. choices are: hot (default), mem, + # io, wakeup, chain, java, js, perl, red, green, blue, + # aqua, yellow, purple, orange + --bgcolors COLOR # set background colors. gradient choices are yellow + # (default), blue, green, grey; flat colors use "#rrggbb" + --hash # colors are keyed by function name hash + --random # colors are randomly generated + --cp # use consistent palette (palette.map) + --reverse # generate stack-reversed flame graph + --inverted # icicle graph + --flamechart # produce a flame chart (sort by time, do not merge stacks) + --negate # switch differential hues (blue<->red) + --notes TEXT # add notes comment in SVG (for debugging) + --help # this message + + eg, + $0 --title="Flame Graph: malloc()" trace.txt > graph.svg +USAGE_END +} + +GetOptions( + 'fonttype=s' => \$fonttype, + 'width=i' => \$imagewidth, + 'height=i' => \$frameheight, + 'encoding=s' => \$encoding, + 'fontsize=f' => \$fontsize, + 'fontwidth=f' => \$fontwidth, + 'minwidth=s' => \$minwidth, + 'title=s' => \$titletext, + 'subtitle=s' => \$subtitletext, + 'nametype=s' => \$nametype, + 'countname=s' => \$countname, + 'nameattr=s' => \$nameattrfile, + 'total=s' => \$timemax, + 'factor=f' => \$factor, + 'colors=s' => \$colors, + 'bgcolors=s' => \$bgcolors, + 'hash' => \$hash, + 'random' => \$rand, + 'cp' => \$palette, + 'reverse' => \$stackreverse, + 'inverted' => \$inverted, + 'flamechart' => \$flamechart, + 'negate' => \$negate, + 'notes=s' => \$notestext, + 'help' => \$help, +) or usage(); +$help && usage(); + +# internals +my $ypad1 = $fontsize * 3; # pad top, include title +my $ypad2 = $fontsize * 2 + 10; # pad bottom, include labels +my $ypad3 = $fontsize * 2; # pad top, include subtitle (optional) +my $xpad = 10; # pad lefm and right +my $framepad = 1; # vertical padding for frames +my $depthmax = 0; +my %Events; +my %nameattr; + +if ($flamechart && $titletext eq "") { + $titletext = "Flame Chart"; +} + +if ($titletext eq "") { + unless ($inverted) { + $titletext = $titledefault; + } else { + $titletext = $titleinverted; + } +} + +if ($nameattrfile) { + # The name-attribute file format is a function name followed by a tab then + # a sequence of tab separated name=value pairs. + open my $attrfh, $nameattrfile or die "Can't read $nameattrfile: $!\n"; + while (<$attrfh>) { + chomp; + my ($funcname, $attrstr) = split /\t/, $_, 2; + die "Invalid format in $nameattrfile" unless defined $attrstr; + $nameattr{$funcname} = { map { split /=/, $_, 2 } split /\t/, $attrstr }; + } +} + +if ($notestext =~ /[<>]/) { + die "Notes string can't contain < or >" +} + +# Ensure minwidth is a valid floating-point number, +# print usage string if not +my $minwidth_f; +if ($minwidth =~ /^([0-9.]+)%?$/) { + $minwidth_f = $1; +} else { + warn "Value '$minwidth' is invalid for minwidth, expected a float.\n"; + usage(); +} + +# background colors: +# - yellow gradient: default (hot, java, js, perl) +# - green gradient: mem +# - blue gradient: io, wakeup, chain +# - gray gradient: flat colors (red, green, blue, ...) +if ($bgcolors eq "") { + # choose a default + if ($colors eq "mem") { + $bgcolors = "green"; + } elsif ($colors =~ /^(io|wakeup|chain)$/) { + $bgcolors = "blue"; + } elsif ($colors =~ /^(red|green|blue|aqua|yellow|purple|orange)$/) { + $bgcolors = "grey"; + } else { + $bgcolors = "yellow"; + } +} +my ($bgcolor1, $bgcolor2); +if ($bgcolors eq "yellow") { + $bgcolor1 = "#eeeeee"; # background color gradient start + $bgcolor2 = "#eeeeb0"; # background color gradient stop +} elsif ($bgcolors eq "blue") { + $bgcolor1 = "#eeeeee"; $bgcolor2 = "#e0e0ff"; +} elsif ($bgcolors eq "green") { + $bgcolor1 = "#eef2ee"; $bgcolor2 = "#e0ffe0"; +} elsif ($bgcolors eq "grey") { + $bgcolor1 = "#f8f8f8"; $bgcolor2 = "#e8e8e8"; +} elsif ($bgcolors =~ /^#......$/) { + $bgcolor1 = $bgcolor2 = $bgcolors; +} else { + die "Unrecognized bgcolor option \"$bgcolors\"" +} + +# SVG functions +{ package SVG; + sub new { + my $class = shift; + my $self = {}; + bless ($self, $class); + return $self; + } + + sub header { + my ($self, $w, $h) = @_; + my $enc_attr = ''; + if (defined $encoding) { + $enc_attr = qq{ encoding="$encoding"}; + } + $self->{svg} .= < + + + + +SVG + } + + sub include { + my ($self, $content) = @_; + $self->{svg} .= $content; + } + + sub colorAllocate { + my ($self, $r, $g, $b) = @_; + return "rgb($r,$g,$b)"; + } + + sub group_start { + my ($self, $attr) = @_; + + my @g_attr = map { + exists $attr->{$_} ? sprintf(qq/$_="%s"/, $attr->{$_}) : () + } qw(id class); + push @g_attr, $attr->{g_extra} if $attr->{g_extra}; + if ($attr->{href}) { + my @a_attr; + push @a_attr, sprintf qq/xlink:href="%s"/, $attr->{href} if $attr->{href}; + # default target=_top else links will open within SVG + push @a_attr, sprintf qq/target="%s"/, $attr->{target} || "_top"; + push @a_attr, $attr->{a_extra} if $attr->{a_extra}; + $self->{svg} .= sprintf qq/\n/, join(' ', (@a_attr, @g_attr)); + } else { + $self->{svg} .= sprintf qq/\n/, join(' ', @g_attr); + } + + $self->{svg} .= sprintf qq/%s<\/title>/, $attr->{title} + if $attr->{title}; # should be first element within g container + } + + sub group_end { + my ($self, $attr) = @_; + $self->{svg} .= $attr->{href} ? qq/<\/a>\n/ : qq/<\/g>\n/; + } + + sub filledRectangle { + my ($self, $x1, $y1, $x2, $y2, $fill, $extra) = @_; + $x1 = sprintf "%0.1f", $x1; + $x2 = sprintf "%0.1f", $x2; + my $w = sprintf "%0.1f", $x2 - $x1; + my $h = sprintf "%0.1f", $y2 - $y1; + $extra = defined $extra ? $extra : ""; + $self->{svg} .= qq/\n/; + } + + sub stringTTF { + my ($self, $id, $x, $y, $str, $extra) = @_; + $x = sprintf "%0.2f", $x; + $id = defined $id ? qq/id="$id"/ : ""; + $extra ||= ""; + $self->{svg} .= qq/$str<\/text>\n/; + } + + sub svg { + my $self = shift; + return "$self->{svg}\n"; + } + 1; +} + +sub namehash { + # Generate a vector hash for the name string, weighting early over + # later characters. We want to pick the same colors for function + # names across different flame graphs. + my $name = shift; + my $vector = 0; + my $weight = 1; + my $max = 1; + my $mod = 10; + # if module name present, trunc to 1st char + $name =~ s/.(.*?)`//; + foreach my $c (split //, $name) { + my $i = (ord $c) % $mod; + $vector += ($i / ($mod++ - 1)) * $weight; + $max += 1 * $weight; + $weight *= 0.70; + last if $mod > 12; + } + return (1 - $vector / $max) +} + +sub sum_namehash { + my $name = shift; + return unpack("%32W*", $name); +} + +sub random_namehash { + # Generate a random hash for the name string. + # This ensures that functions with the same name have the same color, + # both within a flamegraph and across multiple flamegraphs without + # needing to set a palette and while preserving the original flamegraph + # optic, unlike what happens with --hash. + my $name = shift; + my $hash = sum_namehash($name); + srand($hash); + return rand(1) +} + +sub color { + my ($type, $hash, $name) = @_; + my ($v1, $v2, $v3); + + if ($hash) { + $v1 = namehash($name); + $v2 = $v3 = namehash(scalar reverse $name); + } elsif ($rand) { + $v1 = rand(1); + $v2 = rand(1); + $v3 = rand(1); + } else { + $v1 = random_namehash($name); + $v2 = random_namehash($name); + $v3 = random_namehash($name); + } + + # theme palettes + if (defined $type and $type eq "hot") { + my $r = 205 + int(50 * $v3); + my $g = 0 + int(230 * $v1); + my $b = 0 + int(55 * $v2); + return "rgb($r,$g,$b)"; + } + if (defined $type and $type eq "mem") { + my $r = 0; + my $g = 190 + int(50 * $v2); + my $b = 0 + int(210 * $v1); + return "rgb($r,$g,$b)"; + } + if (defined $type and $type eq "io") { + my $r = 80 + int(60 * $v1); + my $g = $r; + my $b = 190 + int(55 * $v2); + return "rgb($r,$g,$b)"; + } + + # multi palettes + if (defined $type and $type eq "java") { + # Handle both annotations (_[j], _[i], ...; which are + # accurate), as well as input that lacks any annotations, as + # best as possible. Without annotations, we get a little hacky + # and match on java|org|com, etc. + if ($name =~ m:_\[j\]$:) { # jit annotation + $type = "green"; + } elsif ($name =~ m:_\[i\]$:) { # inline annotation + $type = "aqua"; + } elsif ($name =~ m:^L?(java|javax|jdk|net|org|com|io|sun)/:) { # Java + $type = "green"; + } elsif ($name =~ /:::/) { # Java, typical perf-map-agent method separator + $type = "green"; + } elsif ($name =~ /::/) { # C++ + $type = "yellow"; + } elsif ($name =~ m:_\[k\]$:) { # kernel annotation + $type = "orange"; + } elsif ($name =~ /::/) { # C++ + $type = "yellow"; + } else { # system + $type = "red"; + } + # fall-through to color palettes + } + if (defined $type and $type eq "perl") { + if ($name =~ /::/) { # C++ + $type = "yellow"; + } elsif ($name =~ m:Perl: or $name =~ m:\.pl:) { # Perl + $type = "green"; + } elsif ($name =~ m:_\[k\]$:) { # kernel + $type = "orange"; + } else { # system + $type = "red"; + } + # fall-through to color palettes + } + if (defined $type and $type eq "js") { + # Handle both annotations (_[j], _[i], ...; which are + # accurate), as well as input that lacks any annotations, as + # best as possible. Without annotations, we get a little hacky, + # and match on a "/" with a ".js", etc. + if ($name =~ m:_\[j\]$:) { # jit annotation + if ($name =~ m:/:) { + $type = "green"; # source + } else { + $type = "aqua"; # builtin + } + } elsif ($name =~ /::/) { # C++ + $type = "yellow"; + } elsif ($name =~ m:/.*\.js:) { # JavaScript (match "/" in path) + $type = "green"; + } elsif ($name =~ m/:/) { # JavaScript (match ":" in builtin) + $type = "aqua"; + } elsif ($name =~ m/^ $/) { # Missing symbol + $type = "green"; + } elsif ($name =~ m:_\[k\]:) { # kernel + $type = "orange"; + } else { # system + $type = "red"; + } + # fall-through to color palettes + } + if (defined $type and $type eq "wakeup") { + $type = "aqua"; + # fall-through to color palettes + } + if (defined $type and $type eq "chain") { + if ($name =~ m:_\[w\]:) { # waker + $type = "aqua" + } else { # off-CPU + $type = "blue"; + } + # fall-through to color palettes + } + + # color palettes + if (defined $type and $type eq "red") { + my $r = 200 + int(55 * $v1); + my $x = 50 + int(80 * $v1); + return "rgb($r,$x,$x)"; + } + if (defined $type and $type eq "green") { + my $g = 200 + int(55 * $v1); + my $x = 50 + int(60 * $v1); + return "rgb($x,$g,$x)"; + } + if (defined $type and $type eq "blue") { + my $b = 205 + int(50 * $v1); + my $x = 80 + int(60 * $v1); + return "rgb($x,$x,$b)"; + } + if (defined $type and $type eq "yellow") { + my $x = 175 + int(55 * $v1); + my $b = 50 + int(20 * $v1); + return "rgb($x,$x,$b)"; + } + if (defined $type and $type eq "purple") { + my $x = 190 + int(65 * $v1); + my $g = 80 + int(60 * $v1); + return "rgb($x,$g,$x)"; + } + if (defined $type and $type eq "aqua") { + my $r = 50 + int(60 * $v1); + my $g = 165 + int(55 * $v1); + my $b = 165 + int(55 * $v1); + return "rgb($r,$g,$b)"; + } + if (defined $type and $type eq "orange") { + my $r = 190 + int(65 * $v1); + my $g = 90 + int(65 * $v1); + return "rgb($r,$g,0)"; + } + + return "rgb(0,0,0)"; +} + +sub color_scale { + my ($value, $max) = @_; + my ($r, $g, $b) = (255, 255, 255); + $value = -$value if $negate; + if ($value > 0) { + $g = $b = int(210 * ($max - $value) / $max); + } elsif ($value < 0) { + $r = $g = int(210 * ($max + $value) / $max); + } + return "rgb($r,$g,$b)"; +} + +sub color_map { + my ($colors, $func) = @_; + if (exists $palette_map{$func}) { + return $palette_map{$func}; + } else { + $palette_map{$func} = color($colors, $hash, $func); + return $palette_map{$func}; + } +} + +sub write_palette { + open(FILE, ">$pal_file"); + foreach my $key (sort keys %palette_map) { + print FILE $key."->".$palette_map{$key}."\n"; + } + close(FILE); +} + +sub read_palette { + if (-e $pal_file) { + open(FILE, $pal_file) or die "can't open file $pal_file: $!"; + while ( my $line = ) { + chomp($line); + (my $key, my $value) = split("->",$line); + $palette_map{$key}=$value; + } + close(FILE) + } +} + +my %Node; # Hash of merged frame data +my %Tmp; + +# flow() merges two stacks, storing the merged frames and value data in %Node. +sub flow { + my ($last, $this, $v, $d) = @_; + + my $len_a = @$last - 1; + my $len_b = @$this - 1; + + my $i = 0; + my $len_same; + for (; $i <= $len_a; $i++) { + last if $i > $len_b; + last if $last->[$i] ne $this->[$i]; + } + $len_same = $i; + + for ($i = $len_a; $i >= $len_same; $i--) { + my $k = "$last->[$i];$i"; + # a unique ID is constructed from "func;depth;etime"; + # func-depth isn't unique, it may be repeated later. + $Node{"$k;$v"}->{stime} = delete $Tmp{$k}->{stime}; + if (defined $Tmp{$k}->{delta}) { + $Node{"$k;$v"}->{delta} = delete $Tmp{$k}->{delta}; + } + delete $Tmp{$k}; + } + + for ($i = $len_same; $i <= $len_b; $i++) { + my $k = "$this->[$i];$i"; + $Tmp{$k}->{stime} = $v; + if (defined $d) { + $Tmp{$k}->{delta} += $i == $len_b ? $d : 0; + } + } + + return $this; +} + +# parse input +my @Data; +my @SortedData; +my $last = []; +my $time = 0; +my $delta = undef; +my $ignored = 0; +my $line; +my $maxdelta = 1; + +# reverse if needed +foreach (<>) { + chomp; + $line = $_; + if ($stackreverse) { + # there may be an extra samples column for differentials + # XXX todo: redo these REs as one. It's repeated below. + my($stack, $samples) = (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + my $samples2 = undef; + if ($stack =~ /^(.*)\s+?(\d+(?:\.\d*)?)$/) { + $samples2 = $samples; + ($stack, $samples) = $stack =~ (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + unshift @Data, join(";", reverse split(";", $stack)) . " $samples $samples2"; + } else { + unshift @Data, join(";", reverse split(";", $stack)) . " $samples"; + } + } else { + unshift @Data, $line; + } +} + +if ($flamechart) { + # In flame chart mode, just reverse the data so time moves from left to right. + @SortedData = reverse @Data; +} else { + @SortedData = sort @Data; +} + +# process and merge frames +foreach (@SortedData) { + chomp; + # process: folded_stack count + # eg: func_a;func_b;func_c 31 + my ($stack, $samples) = (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + unless (defined $samples and defined $stack) { + ++$ignored; + next; + } + + # there may be an extra samples column for differentials: + my $samples2 = undef; + if ($stack =~ /^(.*)\s+?(\d+(?:\.\d*)?)$/) { + $samples2 = $samples; + ($stack, $samples) = $stack =~ (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + } + $delta = undef; + if (defined $samples2) { + $delta = $samples2 - $samples; + $maxdelta = abs($delta) if abs($delta) > $maxdelta; + } + + # for chain graphs, annotate waker frames with "_[w]", for later + # coloring. This is a hack, but has a precedent ("_[k]" from perf). + if ($colors eq "chain") { + my @parts = split ";--;", $stack; + my @newparts = (); + $stack = shift @parts; + $stack .= ";--;"; + foreach my $part (@parts) { + $part =~ s/;/_[w];/g; + $part .= "_[w]"; + push @newparts, $part; + } + $stack .= join ";--;", @parts; + } + + # merge frames and populate %Node: + $last = flow($last, [ '', split ";", $stack ], $time, $delta); + + if (defined $samples2) { + $time += $samples2; + } else { + $time += $samples; + } +} +flow($last, [], $time, $delta); + +if ($countname eq "samples") { + # If $countname is used, it's likely that we're not measuring in stack samples + # (e.g. time could be the unit), so don't warn. + warn "Stack count is low ($time). Did something go wrong?\n" if $time < 100; +} + +warn "Ignored $ignored lines with invalid format\n" if $ignored; +unless ($time) { + warn "ERROR: No stack counts found\n"; + my $im = SVG->new(); + # emit an error message SVG, for tools automating flamegraph use + my $imageheight = $fontsize * 5; + $im->header($imagewidth, $imageheight); + $im->stringTTF(undef, int($imagewidth / 2), $fontsize * 2, + "ERROR: No valid input provided to flamegraph.pl."); + print $im->svg; + exit 2; +} +if ($timemax and $timemax < $time) { + warn "Specified --total $timemax is less than actual total $time, so ignored\n" + if $timemax/$time > 0.02; # only warn is significant (e.g., not rounding etc) + undef $timemax; +} +$timemax ||= $time; + +my $widthpertime = ($imagewidth - 2 * $xpad) / $timemax; + +# Treat as a percentage of time if the string ends in a "%". +my $minwidth_time; +if ($minwidth =~ /%$/) { + $minwidth_time = $timemax * $minwidth_f / 100; +} else { + $minwidth_time = $minwidth_f / $widthpertime; +} + +# prune blocks that are too narrow and determine max depth +while (my ($id, $node) = each %Node) { + my ($func, $depth, $etime) = split ";", $id; + my $stime = $node->{stime}; + die "missing start for $id" if not defined $stime; + + if (($etime-$stime) < $minwidth_time) { + delete $Node{$id}; + next; + } + $depthmax = $depth if $depth > $depthmax; +} + +# draw canvas, and embed interactive JavaScript program +my $imageheight = (($depthmax + 1) * $frameheight) + $ypad1 + $ypad2; +$imageheight += $ypad3 if $subtitletext ne ""; +my $titlesize = $fontsize + 5; +my $im = SVG->new(); +my ($black, $vdgrey, $dgrey) = ( + $im->colorAllocate(0, 0, 0), + $im->colorAllocate(160, 160, 160), + $im->colorAllocate(200, 200, 200), + ); +$im->header($imagewidth, $imageheight); +my $inc = < + + + + + + + +INC +$im->include($inc); +$im->filledRectangle(0, 0, $imagewidth, $imageheight, 'url(#background)'); +$im->stringTTF("title", int($imagewidth / 2), $fontsize * 2, $titletext); +$im->stringTTF("subtitle", int($imagewidth / 2), $fontsize * 4, $subtitletext) if $subtitletext ne ""; +$im->stringTTF("details", $xpad, $imageheight - ($ypad2 / 2), " "); +$im->stringTTF("unzoom", $xpad, $fontsize * 2, "Reset Zoom", 'class="hide"'); +$im->stringTTF("search", $imagewidth - $xpad - 100, $fontsize * 2, "Search"); +$im->stringTTF("ignorecase", $imagewidth - $xpad - 16, $fontsize * 2, "ic"); +$im->stringTTF("matched", $imagewidth - $xpad - 100, $imageheight - ($ypad2 / 2), " "); + +if ($palette) { + read_palette(); +} + +# draw frames +$im->group_start({id => "frames"}); +while (my ($id, $node) = each %Node) { + my ($func, $depth, $etime) = split ";", $id; + my $stime = $node->{stime}; + my $delta = $node->{delta}; + + $etime = $timemax if $func eq "" and $depth == 0; + + my $x1 = $xpad + $stime * $widthpertime; + my $x2 = $xpad + $etime * $widthpertime; + my ($y1, $y2); + unless ($inverted) { + $y1 = $imageheight - $ypad2 - ($depth + 1) * $frameheight + $framepad; + $y2 = $imageheight - $ypad2 - $depth * $frameheight; + } else { + $y1 = $ypad1 + $depth * $frameheight; + $y2 = $ypad1 + ($depth + 1) * $frameheight - $framepad; + } + + # Add commas per perlfaq5: + # https://perldoc.perl.org/perlfaq5#How-can-I-output-my-numbers-with-commas-added? + my $samples = sprintf "%.0f", ($etime - $stime) * $factor; + (my $samples_txt = $samples) + =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; + + my $info; + if ($func eq "" and $depth == 0) { + $info = "all ($samples_txt $countname, 100%)"; + } else { + my $pct = sprintf "%.2f", ((100 * $samples) / ($timemax * $factor)); + my $escaped_func = $func; + # clean up SVG breaking characters: + $escaped_func =~ s/&/&/g; + $escaped_func =~ s//>/g; + $escaped_func =~ s/"/"/g; + $escaped_func =~ s/_\[[kwij]\]$//; # strip any annotation + unless (defined $delta) { + $info = "$escaped_func ($samples_txt $countname, $pct%)"; + } else { + my $d = $negate ? -$delta : $delta; + my $deltapct = sprintf "%.2f", ((100 * $d) / ($timemax * $factor)); + $deltapct = $d > 0 ? "+$deltapct" : $deltapct; + $info = "$escaped_func ($samples_txt $countname, $pct%; $deltapct%)"; + } + } + + my $nameattr = { %{ $nameattr{$func}||{} } }; # shallow clone + $nameattr->{title} ||= $info; + $im->group_start($nameattr); + + my $color; + if ($func eq "--") { + $color = $vdgrey; + } elsif ($func eq "-") { + $color = $dgrey; + } elsif (defined $delta) { + $color = color_scale($delta, $maxdelta); + } elsif ($palette) { + $color = color_map($colors, $func); + } else { + $color = color($colors, $hash, $func); + } + $im->filledRectangle($x1, $y1, $x2, $y2, $color, 'rx="2" ry="2"'); + + my $chars = int( ($x2 - $x1) / ($fontsize * $fontwidth)); + my $text = ""; + if ($chars >= 3) { # room for one char plus two dots + $func =~ s/_\[[kwij]\]$//; # strip any annotation + $text = substr $func, 0, $chars; + substr($text, -2, 2) = ".." if $chars < length $func; + $text =~ s/&/&/g; + $text =~ s//>/g; + } + $im->stringTTF(undef, $x1 + 3, 3 + ($y1 + $y2) / 2, $text); + + $im->group_end($nameattr); +} +$im->group_end(); + +print $im->svg; + +if ($palette) { + write_palette(); +} + +# vim: ts=8 sts=8 sw=8 noexpandtab diff --git a/tests/benchmarks/_script/flamegraph/jmaps b/tests/benchmarks/_script/flamegraph/jmaps new file mode 100755 index 00000000000..f8014f5a82f --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/jmaps @@ -0,0 +1,104 @@ +#!/bin/bash +# +# jmaps - creates java /tmp/perf-PID.map symbol maps for all java processes. +# +# This is a helper script that finds all running "java" processes, then executes +# perf-map-agent on them all, creating symbol map files in /tmp. These map files +# are read by perf_events (aka "perf") when doing system profiles (specifically, +# the "report" and "script" subcommands). +# +# USAGE: jmaps [-u] +# -u # unfoldall: include inlined symbols +# +# My typical workflow is this: +# +# perf record -F 99 -a -g -- sleep 30; jmaps +# perf script > out.stacks +# ./stackcollapse-perf.pl out.stacks | ./flamegraph.pl --color=java --hash > out.stacks.svg +# +# The stackcollapse-perf.pl and flamegraph.pl programs come from: +# https://github.com/brendangregg/FlameGraph +# +# REQUIREMENTS: +# Tune two environment settings below. +# +# 13-Feb-2015 Brendan Gregg Created this. +# 20-Feb-2017 " " Added -u for unfoldall. + +JAVA_HOME=${JAVA_HOME:-/usr/lib/jvm/java-8-oracle} +AGENT_HOME=${AGENT_HOME:-/usr/lib/jvm/perf-map-agent} # from https://github.com/jvm-profiling-tools/perf-map-agent +debug=0 + +if [[ "$USER" != root ]]; then + echo "ERROR: not root user? exiting..." + exit +fi + +if [[ ! -x $JAVA_HOME ]]; then + echo "ERROR: JAVA_HOME not set correctly; edit $0 and fix" + exit +fi + +if [[ ! -x $AGENT_HOME ]]; then + echo "ERROR: AGENT_HOME not set correctly; edit $0 and fix" + exit +fi + +if [[ "$1" == "-u" ]]; then + opts=unfoldall +fi + +# figure out where the agent files are: +AGENT_OUT="" +AGENT_JAR="" +if [[ -e $AGENT_HOME/out/attach-main.jar ]]; then + AGENT_JAR=$AGENT_HOME/out/attach-main.jar +elif [[ -e $AGENT_HOME/attach-main.jar ]]; then + AGENT_JAR=$AGENT_HOME/attach-main.jar +fi +if [[ -e $AGENT_HOME/out/libperfmap.so ]]; then + AGENT_OUT=$AGENT_HOME/out +elif [[ -e $AGENT_HOME/libperfmap.so ]]; then + AGENT_OUT=$AGENT_HOME +fi +if [[ "$AGENT_OUT" == "" || "$AGENT_JAR" == "" ]]; then + echo "ERROR: Missing perf-map-agent files in $AGENT_HOME. Check installation." + exit +fi + +# Fetch map for all "java" processes +echo "Fetching maps for all java processes..." +for pid in $(pgrep -x java); do + mapfile=/tmp/perf-$pid.map + [[ -e $mapfile ]] && rm $mapfile + + cmd="cd $AGENT_OUT; $JAVA_HOME/bin/java -Xms32m -Xmx128m -cp $AGENT_JAR:$JAVA_HOME/lib/tools.jar net.virtualvoid.perf.AttachOnce $pid $opts" + (( debug )) && echo $cmd + + user=$(ps ho user -p $pid) + group=$(ps ho group -p $pid) + if [[ "$user" != root ]]; then + if [[ "$user" == [0-9]* ]]; then + # UID only, likely GID too, run sudo with #UID: + cmd="sudo -u '#'$user -g '#'$group sh -c '$cmd'" + else + cmd="sudo -u $user -g $group sh -c '$cmd'" + fi + fi + + echo "Mapping PID $pid (user $user):" + if (( debug )); then + time eval $cmd + else + eval $cmd + fi + if [[ -e "$mapfile" ]]; then + chown root $mapfile + chmod 666 $mapfile + else + echo "ERROR: $mapfile not created." + fi + + echo "wc(1): $(wc $mapfile)" + echo +done diff --git a/tests/benchmarks/_script/flamegraph/pkgsplit-perf.pl b/tests/benchmarks/_script/flamegraph/pkgsplit-perf.pl new file mode 100755 index 00000000000..3a9902da49f --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/pkgsplit-perf.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w +# +# pkgsplit-perf.pl Split IP samples on package names "/", eg, Java. +# +# This is for the creation of Java package flame graphs. Example steps: +# +# perf record -F 199 -a -- sleep 30; ./jmaps +# perf script | ./pkgsplit-perf.pl | ./flamegraph.pl > out.svg +# +# Note that stack traces are not sampled (no -g), as we split Java package +# names into frames rather than stack frames. +# +# (jmaps is a helper script for automating perf-map-agent: Java symbol dumps.) +# +# The default output of "perf script" varies between kernel versions, so we'll +# need to deal with that here. I could make people use the perf script option +# to pick fields, so our input is static, but A) I prefer the simplicity of +# just saying: run "perf script", and B) the option to choose fields itself +# changed between kernel versions! -f became -F. +# +# Copyright 2017 Netflix, Inc. +# Licensed under the Apache License, Version 2.0 (the "License") +# +# 20-Sep-2016 Brendan Gregg Created this. + +use strict; + +my $include_pname = 1; # include process names in stacks +my $include_pid = 0; # include process ID with process name +my $include_tid = 0; # include process & thread ID with process name + +while (<>) { + # filter comments + next if /^#/; + + # filter idle events + next if /xen_hypercall_sched_op|cpu_idle|native_safe_halt/; + + my ($pid, $tid, $pname); + + # Linux 3.13: + # java 13905 [000] 8048.096572: cpu-clock: 7fd781ac3053 Ljava/util/Arrays$ArrayList;::toArray (/tmp/perf-12149.map) + # java 8301 [050] 13527.392454: cycles: 7fa8a80d9bff Dictionary::find(int, unsigned int, Symbol*, ClassLoaderData*, Handle, Thread*) (/usr/lib/jvm/java-8-oracle-1.8.0.121/jre/lib/amd64/server/libjvm.so) + # java 4567/8603 [023] 13527.389886: cycles: 7fa863349895 Lcom/google/gson/JsonObject;::add (/tmp/perf-4567.map) + # + # Linux 4.8: + # java 30894 [007] 452884.077440: 10101010 cpu-clock: 7f0acc8eff67 Lsun/nio/ch/SocketChannelImpl;::read+0x27 (/tmp/perf-30849.map) + # bash 26858/26858 [006] 5440237.995639: cpu-clock: 433573 [unknown] (/bin/bash) + # + if (/^\s+(\S.+?)\s+(\d+)\/*(\d+)*\s.*?:.*:/) { + # parse process name and pid/tid + if ($3) { + ($pid, $tid) = ($2, $3); + } else { + ($pid, $tid) = ("?", $2); + } + + if ($include_tid) { + $pname = "$1-$pid/$tid"; + } elsif ($include_pid) { + $pname = "$1-$pid"; + } else { + $pname = $1; + } + $pname =~ tr/ /_/; + } else { + # not a match + next; + } + + # parse rest of line + s/^.*?:.*?:\s+//; + s/ \(.*?\)$//; + chomp; + my ($addr, $func) = split(' ', $_, 2); + + # strip Java's leading "L" + $func =~ s/^L//; + + # replace numbers with X + $func =~ s/[0-9]/X/g; + + # colon delimitered + $func =~ s:/:;:g; + print "$pname;$func 1\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/range-perf.pl b/tests/benchmarks/_script/flamegraph/range-perf.pl new file mode 100755 index 00000000000..0fca6decd23 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/range-perf.pl @@ -0,0 +1,137 @@ +#!/usr/bin/perl -w +# +# range-perf Extract a time range from Linux "perf script" output. +# +# USAGE EXAMPLE: +# +# perf record -F 100 -a -- sleep 60 +# perf script | ./perf2range.pl 10 20 # range 10 to 20 seconds only +# perf script | ./perf2range.pl 0 0.5 # first half second only +# +# MAKING A SERIES OF FLAME GRAPHS: +# +# Let's say you had the output of "perf script" in a file, out.stacks01, which +# was for a 180 second profile. The following command creates a series of +# flame graphs for each 10 second interval: +# +# for i in `seq 0 10 170`; do cat out.stacks01 | \ +# ./perf2range.pl $i $((i + 10)) | ./stackcollapse-perf.pl | \ +# grep -v cpu_idle | ./flamegraph.pl --hash --color=java \ +# --title="range $i $((i + 10))" > out.range_$i.svg; echo $i done; done +# +# In that example, I used "--color=java" for the Java palette, and excluded +# the idle CPU task. Customize as needed. +# +# Copyright 2017 Netflix, Inc. +# Licensed under the Apache License, Version 2.0 (the "License") +# +# 21-Feb-2017 Brendan Gregg Created this. + +use strict; +use Getopt::Long; +use POSIX 'floor'; + +sub usage { + die < \$timeraw, + 'timezerosecs' => \$timezerosecs, +) or usage(); + +if (@ARGV < 2 || $ARGV[0] eq "-h" || $ARGV[0] eq "--help") { + usage(); + exit; +} +my $begin = $ARGV[0]; +my $end = $ARGV[1]; + +# +# Parsing +# +# IP only examples: +# +# java 52025 [026] 99161.926202: cycles: +# java 14341 [016] 252732.474759: cycles: 7f36571947c0 nmethod::is_nmethod() const (/... +# java 14514 [022] 28191.353083: cpu-clock: 7f92b4fdb7d4 Ljava_util_List$size$0;::call (/tmp/perf-11936.map) +# swapper 0 [002] 6035557.056977: 10101010 cpu-clock: ffffffff810013aa xen_hypercall_sched_op+0xa (/lib/modules/4.9-virtual/build/vmlinux) +# bash 25370 603are 6036.991603: 10101010 cpu-clock: 4b931e [unknown] (/bin/bash) +# bash 25370/25370 6036036.799684: cpu-clock: 4b913b [unknown] (/bin/bash) +# other combinations are possible. +# +# Stack examples (-g): +# +# swapper 0 [021] 28648.467059: cpu-clock: +# ffffffff810013aa xen_hypercall_sched_op ([kernel.kallsyms]) +# ffffffff8101cb2f default_idle ([kernel.kallsyms]) +# ffffffff8101d406 arch_cpu_idle ([kernel.kallsyms]) +# ffffffff810bf475 cpu_startup_entry ([kernel.kallsyms]) +# ffffffff81010228 cpu_bringup_and_idle ([kernel.kallsyms]) +# +# java 14375 [022] 28648.467079: cpu-clock: +# 7f92bdd98965 Ljava/io/OutputStream;::write (/tmp/perf-11936.map) +# 7f8808cae7a8 [unknown] ([unknown]) +# +# swapper 0 [005] 5076.836336: cpu-clock: +# ffffffff81051586 native_safe_halt ([kernel.kallsyms]) +# ffffffff8101db4f default_idle ([kernel.kallsyms]) +# ffffffff8101e466 arch_cpu_idle ([kernel.kallsyms]) +# ffffffff810c2b31 cpu_startup_entry ([kernel.kallsyms]) +# ffffffff810427cd start_secondary ([kernel.kallsyms]) +# +# swapper 0 [002] 6034779.719110: 10101010 cpu-clock: +# 2013aa xen_hypercall_sched_op+0xfe20000a (/lib/modules/4.9-virtual/build/vmlinux) +# a72f0e default_idle+0xfe20001e (/lib/modules/4.9-virtual/build/vmlinux) +# 2392bf arch_cpu_idle+0xfe20000f (/lib/modules/4.9-virtual/build/vmlinux) +# a73333 default_idle_call+0xfe200023 (/lib/modules/4.9-virtual/build/vmlinux) +# 2c91a4 cpu_startup_entry+0xfe2001c4 (/lib/modules/4.9-virtual/build/vmlinux) +# 22b64a cpu_bringup_and_idle+0xfe20002a (/lib/modules/4.9-virtual/build/vmlinux) +# +# bash 25370/25370 6035935.188539: cpu-clock: +# b9218 [unknown] (/bin/bash) +# 2037fe8 [unknown] ([unknown]) +# other combinations are possible. +# +# This regexp matches the event line, and puts time in $1, and the event name +# in $2: +# +my $event_regexp = qr/ +([0-9\.]+): *\S* *(\S+):/; + +my $line; +my $start = 0; +my $ok = 0; +my $time; + +while (1) { + $line = ; + last unless defined $line; + next if $line =~ /^#/; # skip comments + + if ($line =~ $event_regexp) { + my ($ts, $event) = ($1, $2, $3); + $start = $ts if $start == 0; + + if ($timezerosecs) { + $time = $ts - floor($start); + } elsif (!$timeraw) { + $time = $ts - $start; + } else { + $time = $ts; # raw times + } + + $ok = 1 if $time >= $begin; + # assume samples are in time order: + exit if $time > $end; + } + + print $line if $ok; +} diff --git a/tests/benchmarks/_script/flamegraph/record-test.sh b/tests/benchmarks/_script/flamegraph/record-test.sh new file mode 100755 index 00000000000..569ecc966bb --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/record-test.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# record-test.sh - Overwrite flame graph test result files. +# +# See test.sh, which checks these resulting files. +# +# Currently only tests stackcollapse-perf.pl. + +set -v -x + +# ToDo: add some form of --inline, and --inline --context tests. These are +# tricky since they use addr2line, whose output will vary based on the test +# system's binaries and symbol tables. +for opt in pid tid kernel jit all addrs; do + for testfile in test/*.txt ; do + echo testing $testfile : $opt + outfile=${testfile#*/} + outfile=test/results/${outfile%.txt}"-collapsed-${opt}.txt" + ./stackcollapse-perf.pl --"${opt}" "${testfile}" 2> /dev/null > $outfile + done +done diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-aix.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-aix.pl new file mode 100755 index 00000000000..8456d56b918 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-aix.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl -ws +# +# stackcollapse-aix Collapse AIX /usr/bin/procstack backtraces +# +# Parse a list of backtraces as generated with the poor man's aix-perf.pl +# profiler +# + +use strict; + +my $process = ""; +my $current = ""; +my $previous_function = ""; + +my %stacks; + +while(<>) { + chomp; + if (m/^\d+:/) { + if(!($current eq "")) { + $current = $process . ";" . $current; + $stacks{$current} += 1; + $current = ""; + } + m/^\d+: ([^ ]*)/; + $process = $1; + $current = ""; + } + elsif(m/^---------- tid# \d+/){ + if(!($current eq "")) { + $current = $process . ";" . $current; + $stacks{$current} += 1; + } + $current = ""; + } + elsif(m/^(0x[0-9abcdef]*) *([^ ]*) ([^ ]*) ([^ ]*)/) { + my $function = $2; + my $alt = $1; + $function=~s/\(.*\)?//; + if($function =~ /^\[.*\]$/) { + $function = $alt; + } + if ($current) { + $current = $function . ";" . $current; + } + else { + $current = $function; + } + } +} + +if(!($current eq "")) { + $current = $process . ";" . $current; + $stacks{$current} += 1; + $current = ""; + $process = ""; +} + +foreach my $k (sort { $a cmp $b } keys %stacks) { + print "$k $stacks{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-bpftrace.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-bpftrace.pl new file mode 100755 index 00000000000..f458c3e3af1 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-bpftrace.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl -w +# +# stackcollapse-bpftrace.pl collapse bpftrace samples into single lines. +# +# USAGE ./stackcollapse-bpftrace.pl infile > outfile +# +# Example input: +# +# @[ +# _raw_spin_lock_bh+0 +# tcp_recvmsg+808 +# inet_recvmsg+81 +# sock_recvmsg+67 +# sock_read_iter+144 +# new_sync_read+228 +# __vfs_read+41 +# vfs_read+142 +# sys_read+85 +# do_syscall_64+115 +# entry_SYSCALL_64_after_hwframe+61 +# ]: 3 +# +# Example output: +# +# entry_SYSCALL_64_after_hwframe+61;do_syscall_64+115;sys_read+85;vfs_read+142;__vfs_read+41;new_sync_read+228;sock_read_iter+144;sock_recvmsg+67;inet_recvmsg+81;tcp_recvmsg+808;_raw_spin_lock_bh+0 3 +# +# Copyright 2018 Peter Sanford. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# (http://www.gnu.org/copyleft/gpl.html) +# + +use strict; + +my @stack; +my $in_stack = 0; + +foreach (<>) { + chomp; + if (!$in_stack) { + if (/^@\[$/) { + $in_stack = 1; + } elsif (/^@\[,\s(.*)\]: (\d+)/) { + print $1 . " $2\n"; + } + } else { + if (m/^,?\s?(.*)\]: (\d+)/) { + if (length $1) { + push(@stack, $1); + } + print join(';', reverse(@stack)) . " $2\n"; + $in_stack = 0; + @stack = (); + } else { + $_ =~ s/^\s+//; + push(@stack, $_); + } + } +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-chrome-tracing.py b/tests/benchmarks/_script/flamegraph/stackcollapse-chrome-tracing.py new file mode 100755 index 00000000000..b4869781d90 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-chrome-tracing.py @@ -0,0 +1,144 @@ +#!/usr/bin/python +# +# stackcolllapse-chrome-tracing.py collapse Trace Event Format [1] +# callstack events into single lines. +# +# [1] https://github.com/catapult-project/catapult/wiki/Trace-Event-Format +# +# USAGE: ./stackcollapse-chrome-tracing.py input_json [input_json...] > outfile +# +# Example input: +# +# {"traceEvents":[ +# {"pid":1,"tid":2,"ts":0,"ph":"X","name":"Foo","dur":50}, +# {"pid":1,"tid":2,"ts":10,"ph":"X","name":"Bar","dur":30} +# ]} +# +# Example output: +# +# Foo 20.0 +# Foo;Bar 30.0 +# +# Input may contain many stack trace events from many processes/threads. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# 4-Jan-2018 Marcin Kolny Created this. +import argparse +import json + +stack_identifiers = {} + + +class Event: + def __init__(self, label, timestamp, dur): + self.label = label + self.timestamp = timestamp + self.duration = dur + self.total_duration = dur + + def get_stop_timestamp(self): + return self.timestamp + self.duration + + +def cantor_pairing(a, b): + s = a + b + return s * (s + 1) / 2 + b + + +def get_trace_events(trace_file, events_dict): + json_data = json.load(trace_file) + + for entry in json_data['traceEvents']: + if entry['ph'] == 'X': + cantor_val = cantor_pairing(int(entry['tid']), int(entry['pid'])) + if 'dur' not in entry: + continue + if cantor_val not in events_dict: + events_dict[cantor_val] = [] + events_dict[cantor_val].append(Event(entry['name'], float(entry['ts']), float(entry['dur']))) + + +def load_events(trace_files): + events = {} + + for trace_file in trace_files: + get_trace_events(trace_file, events) + + for key in events: + events[key].sort(key=lambda x: x.timestamp) + + return events + + +def save_stack(stack): + first = True + event = None + identifier = '' + + for event in stack: + if first: + first = False + else: + identifier += ';' + identifier += event.label + + if not event: + return + + if identifier in stack_identifiers: + stack_identifiers[identifier] += event.total_duration + else: + stack_identifiers[identifier] = event.total_duration + + +def load_stack_identifiers(events): + event_stack = [] + + for e in events: + if not event_stack: + event_stack.append(e) + else: + while event_stack and event_stack[-1].get_stop_timestamp() <= e.timestamp: + save_stack(event_stack) + event_stack.pop() + + if event_stack: + event_stack[-1].total_duration -= e.duration + + event_stack.append(e) + + while event_stack: + save_stack(event_stack) + event_stack.pop() + + +parser = argparse.ArgumentParser() +parser.add_argument('input_file', nargs='+', + type=argparse.FileType('r'), + help='Chrome Tracing input files') +args = parser.parse_args() + +all_events = load_events(args.input_file) +for tid_pid in all_events: + load_stack_identifiers(all_events[tid_pid]) + +for identifiers, duration in stack_identifiers.items(): + print(identifiers + ' ' + str(duration)) diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-elfutils.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-elfutils.pl new file mode 100755 index 00000000000..c5e6b17e44b --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-elfutils.pl @@ -0,0 +1,98 @@ +#!/usr/bin/perl -w +# +# stackcollapse-elfutils Collapse elfutils stack (eu-stack) backtraces +# +# Parse a list of elfutils backtraces as generated with the poor man's +# profiler [1]: +# +# for x in $(seq 1 "$nsamples"); do +# eu-stack -p "$pid" "$@" +# sleep "$sleeptime" +# done +# +# [1] http://poormansprofiler.org/ +# +# Copyright 2014 Gabriel Corona. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END + +use strict; +use Getopt::Long; + +my $with_pid = 0; +my $with_tid = 0; + +GetOptions('pid' => \$with_pid, + 'tid' => \$with_tid) +or die < outfile\n + --pid # include PID + --tid # include TID +USAGE_END + +my $pid = ""; +my $tid = ""; +my $current = ""; +my $previous_function = ""; + +my %stacks; + +sub add_current { + if(!($current eq "")) { + my $entry; + if ($with_tid) { + $current = "TID=$tid;$current"; + } + if ($with_pid) { + $current = "PID=$pid;$current"; + } + $stacks{$current} += 1; + $current = ""; + } +} + +while(<>) { + chomp; + if (m/^PID ([0-9]*)/) { + add_current(); + $pid = $1; + } + elsif(m/^TID ([0-9]*)/) { + add_current(); + $tid = $1; + } elsif(m/^#[0-9]* *0x[0-9a-f]* (.*)/) { + if ($current eq "") { + $current = $1; + } else { + $current = "$1;$current"; + } + } elsif(m/^#[0-9]* *0x[0-9a-f]*/) { + if ($current eq "") { + $current = "[unknown]"; + } else { + $current = "[unknown];$current"; + } + } +} +add_current(); + +foreach my $k (sort { $a cmp $b } keys %stacks) { + print "$k $stacks{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-faulthandler.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-faulthandler.pl new file mode 100755 index 00000000000..4fe74ffa7b8 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-faulthandler.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl -ws +# +# stackcollapse-faulthandler Collapse Python faulthandler backtraces +# +# Parse a list of Python faulthandler backtraces as generated with +# faulthandler.dump_traceback_later. +# +# Copyright 2014 Gabriel Corona. All rights reserved. +# Copyright 2017 Jonathan Kolb. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END + +use strict; + +my $current = ""; + +my %stacks; + +while(<>) { + chomp; + if (m/^Thread/) { + $current="" + } + elsif(m/^ File "([^"]*)", line ([0-9]*) in (.*)/) { + my $function = $1 . ":" . $2 . ":" . $3; + if ($current eq "") { + $current = $function; + } else { + $current = $function . ";" . $current; + } + } elsif(!($current eq "")) { + $stacks{$current} += 1; + $current = ""; + } +} + +if(!($current eq "")) { + $stacks{$current} += 1; + $current = ""; +} + +foreach my $k (sort { $a cmp $b } keys %stacks) { + print "$k $stacks{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-gdb.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-gdb.pl new file mode 100755 index 00000000000..8e9831b22e5 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-gdb.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl -ws +# +# stackcollapse-gdb Collapse GDB backtraces +# +# Parse a list of GDB backtraces as generated with the poor man's +# profiler [1]: +# +# for x in $(seq 1 500); do +# gdb -ex "set pagination 0" -ex "thread apply all bt" -batch -p $pid 2> /dev/null +# sleep 0.01 +# done +# +# [1] http://poormansprofiler.org/ +# +# Copyright 2014 Gabriel Corona. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END + +use strict; + +my $current = ""; +my $previous_function = ""; + +my %stacks; + +while(<>) { + chomp; + if (m/^Thread/) { + $current="" + } + elsif(m/^#[0-9]* *([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)/) { + my $function = $3; + my $alt = $1; + if(not($1 =~ /0x[a-zA-Z0-9]*/)) { + $function = $alt; + } + if ($current eq "") { + $current = $function; + } else { + $current = $function . ";" . $current; + } + } elsif(!($current eq "")) { + $stacks{$current} += 1; + $current = ""; + } +} + +if(!($current eq "")) { + $stacks{$current} += 1; + $current = ""; +} + +foreach my $k (sort { $a cmp $b } keys %stacks) { + print "$k $stacks{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-go.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-go.pl new file mode 100755 index 00000000000..3b2ce3c552f --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-go.pl @@ -0,0 +1,150 @@ +#!/usr/bin/perl -w +# +# stackcollapse-go.pl collapse golang samples into single lines. +# +# Parses golang smaples generated by "go tool pprof" and outputs stacks as +# single lines, with methods separated by semicolons, and then a space and an +# occurrence count. For use with flamegraph.pl. +# +# USAGE: ./stackcollapse-go.pl infile > outfile +# +# Example Input: +# ... +# Samples: +# samples/count cpu/nanoseconds +# 1 10000000: 1 2 +# 2 10000000: 3 2 +# 1 10000000: 4 2 +# ... +# Locations +# 1: 0x58b265 scanblock :0 s=0 +# 2: 0x599530 GC :0 s=0 +# 3: 0x58a999 flushptrbuf :0 s=0 +# 4: 0x58d6a8 runtime.MSpan_Sweep :0 s=0 +# ... +# Mappings +# ... +# +# Example Output: +# +# GC;flushptrbuf 2 +# GC;runtime.MSpan_Sweep 1 +# GC;scanblock 1 +# +# Input may contain many stacks as generated from go tool pprof: +# +# go tool pprof -seconds=60 -raw -output=a.pprof http://$ADDR/debug/pprof/profile +# +# For format of text profile, See golang/src/internal/pprof/profile/profile.go +# +# Copyright 2017 Sijie Yang (yangsijie@baidu.com). All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# (http://www.gnu.org/copyleft/gpl.html) +# +# 16-Jan-2017 Sijie Yang Created this. + +use strict; + +use Getopt::Long; + +# tunables +my $help = 0; + +sub usage { + die < outfile\n +USAGE_END +} + +GetOptions( + 'help' => \$help, +) or usage(); +$help && usage(); + +# internals +my $state = "ignore"; +my %stacks; +my %frames; +my %collapsed; + +sub remember_stack { + my ($stack, $count) = @_; + $stacks{$stack} += $count; +} + +# +# Output stack string in required format. For example, for the following samples, +# format_statck() would return GC;runtime.MSpan_Sweep for stack "4 2" +# +# Locations +# 1: 0x58b265 scanblock :0 s=0 +# 2: 0x599530 GC :0 s=0 +# 3: 0x58a999 flushptrbuf :0 s=0 +# 4: 0x58d6a8 runtime.MSpan_Sweep :0 s=0 +# +sub format_statck { + my ($stack) = @_; + my @loc_list = split(/ /, $stack); + + for (my $i=0; $i<=$#loc_list; $i++) { + my $loc_name = $frames{$loc_list[$i]}; + $loc_list[$i] = $loc_name if ($loc_name); + } + return join(";", reverse(@loc_list)); +} + +foreach (<>) { + next if m/^#/; + chomp; + + if ($state eq "ignore") { + if (/Samples:/) { + $state = "sample"; + next; + } + + } elsif ($state eq "sample") { + if (/^\s*([0-9]+)\s*[0-9]+: ([0-9 ]+)/) { + my $samples = $1; + my $stack = $2; + remember_stack($stack, $samples); + } elsif (/Locations/) { + $state = "location"; + next; + } + + } elsif ($state eq "location") { + if (/^\s*([0-9]*): 0x[0-9a-f]+ (M=[0-9]+ )?([^ ]+) .*/) { + my $loc_id = $1; + my $loc_name = $3; + $frames{$loc_id} = $loc_name; + } elsif (/Mappings/) { + $state = "mapping"; + last; + } + } +} + +foreach my $k (keys %stacks) { + my $stack = format_statck($k); + my $count = $stacks{$k}; + $collapsed{$stack} += $count; +} + +foreach my $k (sort { $a cmp $b } keys %collapsed) { + print "$k $collapsed{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-ibmjava.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-ibmjava.pl new file mode 100644 index 00000000000..f8ffa8bd4d7 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-ibmjava.pl @@ -0,0 +1,145 @@ +#!/usr/bin/perl -w +# +# stackcollapse-ibmjava.pl collapse jstack samples into single lines. +# +# Parses Java stacks generated by IBM Java with methods separated by semicolons, +# and then a space and an occurrence count. +# +# USAGE: ./stackcollapse-ibmjava.pl infile > outfile +# +# Example input: +# +# NULL +# 1XMTHDINFO Thread Details +# NULL +# NULL +# 3XMTHREADINFO "Default Executor-thread-149164" J9VMThread:0x0000000008132B00, j9thread_t:0x000000001A810B90, java/lang/Thread:0x0000000712BE8E48, state:R, prio=5 +# 3XMJAVALTHREAD (java/lang/Thread getId:0x3493E, isDaemon:true) +# 3XMTHREADINFO1 (native thread ID:0x3158, native priority:0x5, native policy:UNKNOWN, vmstate:R, vm thread flags:0x00000001) +# 3XMCPUTIME CPU usage total: 0.421875000 secs, user: 0.343750000 secs, system: 0.078125000 secs, current category="Application" +# 3XMHEAPALLOC Heap bytes allocated since last GC cycle=0 (0x0) +# 3XMTHREADINFO3 Java callstack: +# 4XESTACKTRACE at java/net/SocketInputStream.socketRead0(Native Method) +# 4XESTACKTRACE at java/net/SocketInputStream.socketRead(SocketInputStream.java:127(Compiled Code)) +# 4XESTACKTRACE at java/net/SocketInputStream.read(SocketInputStream.java:182(Compiled Code)) +# 4XESTACKTRACE at java/net/SocketInputStream.read(SocketInputStream.java:152(Compiled Code)) +# 4XESTACKTRACE at java/io/FilterInputStream.read(FilterInputStream.java:144(Compiled Code)) +# ... +# 4XESTACKTRACE at java/lang/Thread.run(Thread.java:785(Compiled Code)) +# +# Example output: +# +# Default Executor-thread-149164;java/lang/Thread.run;java/net/SocketInputStream/read;java/net/SocketInputStream.socketRead0 1 +# +# +# Copyright 2014 Federico Juinio. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# (http://www.gnu.org/copyleft/gpl.html) +# +# 23-Aug-2023 Federico Juinio created this based from stackcollapse-jstack.pl + +use strict; + +use Getopt::Long; + +# tunables +my $include_tname = 1; # include thread names in stacks +my $include_tid = 0; # include thread IDs in stacks +my $shorten_pkgs = 0; # shorten package names +my $help = 0; + +sub usage { + die < outfile\n + --include-tname + --no-include-tname # include/omit thread names in stacks (default: include) + --include-tid + --no-include-tid # include/omit thread IDs in stacks (default: omit) + --shorten-pkgs + --no-shorten-pkgs # (don't) shorten package names (default: don't shorten) + + eg, + $0 --no-include-tname stacks.txt > collapsed.txt +USAGE_END +} + +GetOptions( + 'include-tname!' => \$include_tname, + 'include-tid!' => \$include_tid, + 'shorten-pkgs!' => \$shorten_pkgs, + 'help' => \$help, +) or usage(); +$help && usage(); + + +# internals +my %collapsed; + +sub remember_stack { + my ($stack, $count) = @_; + $collapsed{$stack} += $count; +} + +my @stack; +my $tname; +my $state = "?"; + +foreach (<>) { + next if m/^#/; + chomp; + + if (m/^3XMTHREADINFO3 Native callstack:/) { + # save stack + if (defined $tname) { unshift @stack, $tname; } + remember_stack(join(";", @stack), 1) if @stack; + undef @stack; + undef $tname; + $state = "?"; + next; + } + + # look for thread header line and parse thread name and state + if (/^3XMTHREADINFO "([^"]*).* state:(.*), /) { + my $name = $1; + if ($include_tname) { + $tname = $name; + } + $state = $2; + # special handling for "Anonymous native threads" + } elsif (/3XMTHREADINFO Anonymous native thread/) { + $tname = "Anonymous native thread"; + # look for thread id + } elsif (/^3XMTHREADINFO1 \(native thread ID:([^ ]*), native priority/) { + if ($include_tname && $include_tid) { + $tname = $tname . "-" . $1 + } + # collect stack frames + } elsif (/^4XESTACKTRACE at ([^\(]*)/) { + my $func = $1; + if ($shorten_pkgs) { + my ($pkgs, $clsFunc) = ( $func =~ m/(.*\.)([^.]+\.[^.]+)$/ ); + $pkgs =~ s/(\w)\w*/$1/g; + $func = $pkgs . $clsFunc; + } + unshift @stack, $func; + + } +} + +foreach my $k (sort { $a cmp $b } keys %collapsed) { + print "$k $collapsed{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-instruments.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-instruments.pl new file mode 100755 index 00000000000..3cbaa87bc27 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-instruments.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w +# +# stackcollapse-instruments.pl +# +# Parses a file containing a call tree as produced by XCode Instruments +# (Edit > Deep Copy) and produces output suitable for flamegraph.pl. +# +# USAGE: ./stackcollapse-instruments.pl infile > outfile + +use strict; + +my @stack = (); + +<>; +foreach (<>) { + chomp; + /\d+\.\d+ (?:min|s|ms)\s+\d+\.\d+%\s+(\d+(?:\.\d+)?) (min|s|ms)\t \t(\s*)(.+)/ or die; + my $func = $4; + my $depth = length ($3); + $stack [$depth] = $4; + foreach my $i (0 .. $depth - 1) { + print $stack [$i]; + print ";"; + } + + my $time = 0 + $1; + if ($2 eq "min") { + $time *= 60*1000; + } elsif ($2 eq "s") { + $time *= 1000; + } + + printf("%s %.0f\n", $func, $time); +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-java-exceptions.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-java-exceptions.pl new file mode 100755 index 00000000000..19badbca6cb --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-java-exceptions.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl -w +# +# stackcolllapse-java-exceptions.pl collapse java exceptions (found in logs) into single lines. +# +# Parses Java error stacks found in a log file and outputs them as +# single lines, with methods separated by semicolons, and then a space and an +# occurrence count. Inspired by stackcollapse-jstack.pl except that it does +# not act as a performance profiler. +# +# It can be useful if a Java process dumps a lot of different stacks in its logs +# and you want to quickly identify the biggest culprits. +# +# USAGE: ./stackcollapse-java-exceptions.pl infile > outfile +# +# Copyright 2018 Paul de Verdiere. All rights reserved. + +use strict; +use Getopt::Long; + +# tunables +my $shorten_pkgs = 0; # shorten package names +my $no_pkgs = 0; # really shorten package names!! +my $help = 0; + +sub usage { + die < outfile\n + --shorten-pkgs : shorten package names + --no-pkgs : suppress package names (makes SVG much more readable) + +USAGE_END +} + +GetOptions( + 'shorten-pkgs!' => \$shorten_pkgs, + 'no-pkgs!' => \$no_pkgs, + 'help' => \$help, +) or usage(); +$help && usage(); + +my %collapsed; + +sub remember_stack { + my ($stack, $count) = @_; + $collapsed{$stack} += $count; +} + +my @stack; + +foreach (<>) { + chomp; + + if (/^\s*at ([^\(]*)/) { + my $func = $1; + if ($shorten_pkgs || $no_pkgs) { + my ($pkgs, $clsFunc) = ( $func =~ m/(.*\.)([^.]+\.[^.]+)$/ ); + $pkgs =~ s/(\w)\w*/$1/g; + $func = $no_pkgs ? $clsFunc: $pkgs . $clsFunc; + } + unshift @stack, $func; + } elsif (@stack ) { + next if m/.*waiting on .*/; + remember_stack(join(";", @stack), 1) if @stack; + undef @stack; + } +} + +remember_stack(join(";", @stack), 1) if @stack; + +foreach my $k (sort { $a cmp $b } keys %collapsed) { + print "$k $collapsed{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-jstack.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-jstack.pl new file mode 100755 index 00000000000..da5740b6ee6 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-jstack.pl @@ -0,0 +1,176 @@ +#!/usr/bin/perl -w +# +# stackcollapse-jstack.pl collapse jstack samples into single lines. +# +# Parses Java stacks generated by jstack(1) and outputs RUNNABLE stacks as +# single lines, with methods separated by semicolons, and then a space and an +# occurrence count. This also filters some other "RUNNABLE" states that we +# know are probably not running, such as epollWait. For use with flamegraph.pl. +# +# You want this to process the output of at least 100 jstack(1)s. ie, run it +# 100 times with a sleep interval, and append to a file. This is really a poor +# man's Java profiler, due to the overheads of jstack(1), and how it isn't +# capturing stacks asynchronously. For a better profiler, see: +# http://www.brendangregg.com/blog/2014-06-12/java-flame-graphs.html +# +# USAGE: ./stackcollapse-jstack.pl infile > outfile +# +# Example input: +# +# "MyProg" #273 daemon prio=9 os_prio=0 tid=0x00007f273c038800 nid=0xe3c runnable [0x00007f28a30f2000] +# java.lang.Thread.State: RUNNABLE +# at java.net.SocketInputStream.socketRead0(Native Method) +# at java.net.SocketInputStream.read(SocketInputStream.java:121) +# ... +# at java.lang.Thread.run(Thread.java:744) +# +# Example output: +# +# MyProg;java.lang.Thread.run;java.net.SocketInputStream.read;java.net.SocketInputStream.socketRead0 1 +# +# Input may be created and processed using: +# +# i=0; while (( i++ < 200 )); do jstack PID >> out.jstacks; sleep 10; done +# cat out.jstacks | ./stackcollapse-jstack.pl > out.stacks-folded +# +# WARNING: jstack(1) incurs overheads. Test before use, or use a real profiler. +# +# Copyright 2014 Brendan Gregg. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# (http://www.gnu.org/copyleft/gpl.html) +# +# 14-Sep-2014 Brendan Gregg Created this. + +use strict; + +use Getopt::Long; + +# tunables +my $include_tname = 1; # include thread names in stacks +my $include_tid = 0; # include thread IDs in stacks +my $shorten_pkgs = 0; # shorten package names +my $help = 0; + +sub usage { + die < outfile\n + --include-tname + --no-include-tname # include/omit thread names in stacks (default: include) + --include-tid + --no-include-tid # include/omit thread IDs in stacks (default: omit) + --shorten-pkgs + --no-shorten-pkgs # (don't) shorten package names (default: don't shorten) + + eg, + $0 --no-include-tname stacks.txt > collapsed.txt +USAGE_END +} + +GetOptions( + 'include-tname!' => \$include_tname, + 'include-tid!' => \$include_tid, + 'shorten-pkgs!' => \$shorten_pkgs, + 'help' => \$help, +) or usage(); +$help && usage(); + + +# internals +my %collapsed; + +sub remember_stack { + my ($stack, $count) = @_; + $collapsed{$stack} += $count; +} + +my @stack; +my $tname; +my $state = "?"; + +foreach (<>) { + next if m/^#/; + chomp; + + if (m/^$/) { + # only include RUNNABLE states + goto clear if $state ne "RUNNABLE"; + + # save stack + if (defined $tname) { unshift @stack, $tname; } + remember_stack(join(";", @stack), 1) if @stack; +clear: + undef @stack; + undef $tname; + $state = "?"; + next; + } + + # + # While parsing jstack output, the $state variable may be altered from + # RUNNABLE to other states. This causes the stacks to be filtered later, + # since only RUNNABLE stacks are included. + # + + if (/^"([^"]*)/) { + my $name = $1; + + if ($include_tname) { + $tname = $name; + unless ($include_tid) { + $tname =~ s/-\d+$//; + } + } + + # set state for various background threads + $state = "BACKGROUND" if $name =~ /C. CompilerThread/; + $state = "BACKGROUND" if $name =~ /Signal Dispatcher/; + $state = "BACKGROUND" if $name =~ /Service Thread/; + $state = "BACKGROUND" if $name =~ /Attach Listener/; + + } elsif (/java.lang.Thread.State: (\S+)/) { + $state = $1 if $state eq "?"; + } elsif (/^\s*at ([^\(]*)/) { + my $func = $1; + if ($shorten_pkgs) { + my ($pkgs, $clsFunc) = ( $func =~ m/(.*\.)([^.]+\.[^.]+)$/ ); + $pkgs =~ s/(\w)\w*/$1/g; + $func = $pkgs . $clsFunc; + } + unshift @stack, $func; + + # fix state for epollWait + $state = "WAITING" if $func =~ /epollWait/; + $state = "WAITING" if $func =~ /EPoll\.wait/; + + + # fix state for various networking functions + $state = "NETWORK" if $func =~ /socketAccept$/; + $state = "NETWORK" if $func =~ /Socket.*accept0$/; + $state = "NETWORK" if $func =~ /socketRead0$/; + + } elsif (/^\s*-/ or /^2\d\d\d-/ or /^Full thread dump/ or + /^JNI global references:/) { + # skip these info lines + next; + } else { + warn "Unrecognized line: $_"; + } +} + +foreach my $k (sort { $a cmp $b } keys %collapsed) { + print "$k $collapsed{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-ljp.awk b/tests/benchmarks/_script/flamegraph/stackcollapse-ljp.awk new file mode 100755 index 00000000000..59aaae3d73b --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-ljp.awk @@ -0,0 +1,74 @@ +#!/usr/bin/awk -f +# +# stackcollapse-ljp.awk collapse lightweight java profile reports +# into single lines stacks. +# +# Parses a list of multiline stacks generated by: +# +# https://code.google.com/p/lightweight-java-profiler +# +# and outputs a semicolon separated stack followed by a space and a count. +# +# USAGE: ./stackcollapse-ljp.pl infile > outfile +# +# Example input: +# +# 42 3 my_func_b(prog.java:455) +# my_func_a(prog.java:123) +# java.lang.Thread.run(Thread.java:744) +# [...] +# +# Example output: +# +# java.lang.Thread.run;my_func_a;my_func_b 42 +# +# The unused number is the number of frames in each stack. +# +# Copyright 2014 Brendan Gregg. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# 12-Jun-2014 Brendan Gregg Created this. + +$1 == "Total" { + # We're done. Print last stack and exit. + print stack, count + exit +} + +{ + # Strip file location. Comment this out to keep. + gsub(/\(.*\)/, "") +} + +NF == 3 { + # New stack begins. Print previous buffered stack. + if (count) + print stack, count + + # Begin a new stack. + count = $1 + stack = $3 +} + +NF == 1 { + # Build stack. + stack = $1 ";" stack +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-perf-sched.awk b/tests/benchmarks/_script/flamegraph/stackcollapse-perf-sched.awk new file mode 100755 index 00000000000..e1a122d459e --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-perf-sched.awk @@ -0,0 +1,228 @@ +#!/usr/bin/awk -f + +# +# This program generates collapsed off-cpu stacks fit for use by flamegraph.pl +# from scheduler data collected via perf_events. +# +# Outputs the cumulative time off cpu in us for each distinct stack observed. +# +# Some awk variables further control behavior: +# +# record_tid If truthy, causes all stack traces to include the +# command and LWP id. +# +# record_wake_stack If truthy, stacks include the frames from the wakeup +# event in addition to the sleep event. +# See http://www.brendangregg.com/FlameGraphs/offcpuflamegraphs.html#Wakeup +# +# recurse If truthy, attempt to recursively identify and +# visualize the full wakeup stack chain. +# See http://www.brendangregg.com/FlameGraphs/offcpuflamegraphs.html#ChainGraph +# +# Note that this is only an approximation, as only the +# last sleep event is recorded (e.g. if a thread slept +# multiple times before waking another thread, only the +# last sleep event is used). Implies record_wake_stack=1 +# +# To set any of these variables from the command line, run via: +# +# stackcollapse-perf-sched.awk -v recurse=1 +# +# == Important warning == +# +# WARNING: tracing all scheduler events is very high overhead in perf. Even +# more alarmingly, there appear to be bugs in perf that prevent it from reliably +# getting consistent traces (even with large trace buffers), causing it to +# produce empty perf.data files with error messages of the form: +# +# 0x952790 [0x736d]: failed to process type: 3410 +# +# This failure is not determinisitic, so re-executing perf record will +# eventually succeed. +# +# == Usage == +# +# First, record data via perf_events: +# +# sudo perf record -g -e 'sched:sched_switch' \ +# -e 'sched:sched_stat_sleep' -e 'sched:sched_stat_blocked' \ +# -p -o perf.data -- sleep 1 +# +# Then post process with this script: +# +# sudo perf script -f time,comm,pid,tid,event,ip,sym,dso,trace -i perf.data | \ +# stackcollapse-perf-sched.awk -v recurse=1 | \ +# flamegraph.pl --color=io --countname=us >out.svg +# + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2015 by MemSQL. All rights reserved. +# + +# +# Match a perf captured variable, returning just the contents. For example, for +# the following line, get_perf_captured_variable("pid") would return "27235": +# +# swapper 0 [006] 708189.626415: sched:sched_stat_sleep: comm=memsqld pid=27235 delay=100078421 [ns +# +function get_perf_captured_variable(variable) +{ + match($0, variable "=[^[:space:]]+") + return substr($0, RSTART + length(variable) + 1, + RLENGTH - length(variable) - 1) +} + +# +# The timestamp is the first field that ends in a colon, e.g.: +# +# swapper 0 [006] 708189.626415: sched:sched_stat_sleep: comm=memsqld pid=27235 delay=100078421 [ns +# +# or +# +# swapper 0/0 708189.626415: sched:sched_stat_sleep: comm=memsqld pid=27235 delay=100078421 [ns] +# +function get_perf_timestamp() +{ + match($0, " [^ :]+:") + return substr($0, RSTART + 1, RLENGTH - 2) +} + +!/^#/ && /sched:sched_switch/ { + switchcommand = get_perf_captured_variable("comm") + + switchpid = get_perf_captured_variable("prev_pid") + + switchtime=get_perf_timestamp() + + switchstack="" +} + +# +# Strip the function name from a stack entry +# +# Stack entry is expected to be formatted like: +# c60849 MyClass::Foo(unsigned long) (/home/areece/a.out) +# +function get_function_name() +{ + # We start from 2 since we don't need the hex offset. + # We stop at NF - 1 since we don't need the library path. + funcname = $2 + for (i = 3; i <= NF - 1; i++) { + funcname = funcname " " $i + } + return funcname +} + +(switchpid != 0 && /^\s/) { + if (switchstack == "") { + switchstack = get_function_name() + } else { + switchstack = get_function_name() ";" switchstack + } +} + +(switchpid != 0 && /^$/) { + switch_stacks[switchpid] = switchstack + delete last_switch_stacks[switchpid] + switch_time[switchpid] = switchtime + + switchpid=0 + switchcommand="" + switchstack="" +} + +!/^#/ && (/sched:sched_stat_sleep/ || /sched:sched_stat_blocked/) { + wakecommand=$1 + wakepid=$2 + + waketime=get_perf_timestamp() + + stat_next_command = get_perf_captured_variable("comm") + + stat_next_pid = get_perf_captured_variable("pid") + + stat_delay_ns = int(get_perf_captured_variable("delay")) + + wakestack="" +} + +(stat_next_pid != 0 && /^\s/) { + if (wakestack == "") { + wakestack = get_function_name() + } else { + # We build the wakestack in reverse order. + wakestack = wakestack ";" get_function_name() + } +} + +(stat_next_pid != 0 && /^$/) { + # + # For some reason, perf appears to output duplicate + # sched:sched_stat_sleep and sched:sched_stat_blocked events. We only + # handle the first event. + # + if (stat_next_pid in switch_stacks) { + last_wake_time[stat_next_pid] = waketime + + stack = switch_stacks[stat_next_pid] + if (recurse || record_wake_stack) { + stack = stack ";" wakestack + if (record_tid) { + stack = stack ";" wakecommand "-" wakepid + } else { + stack = stack ";" wakecommand + } + } + + if (recurse) { + if (last_wake_time[wakepid] > last_switch_time[stat_next_pid]) { + stack = stack ";-;" last_switch_stacks[wakepid] + } + last_switch_stacks[stat_next_pid] = stack + } + + delete switch_stacks[stat_next_pid] + + if (record_tid) { + stack_times[stat_next_command "-" stat_next_pid ";" stack] += stat_delay_ns + } else { + stack_times[stat_next_command ";" stack] += stat_delay_ns + } + } + + wakecommand="" + wakepid=0 + stat_next_pid=0 + stat_next_command="" + stat_delay_ms=0 +} + +END { + for (stack in stack_times) { + if (int(stack_times[stack] / 1000) > 0) { + print stack, int(stack_times[stack] / 1000) + } + } +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-perf.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-perf.pl new file mode 100755 index 00000000000..3ff39bfb87f --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-perf.pl @@ -0,0 +1,435 @@ +#!/usr/bin/perl -w +# +# stackcollapse-perf.pl collapse perf samples into single lines. +# +# Parses a list of multiline stacks generated by "perf script", and +# outputs a semicolon separated stack followed by a space and a count. +# If memory addresses (+0xd) are present, they are stripped, and resulting +# identical stacks are colased with their counts summed. +# +# USAGE: ./stackcollapse-perf.pl [options] infile > outfile +# +# Run "./stackcollapse-perf.pl -h" to list options. +# +# Example input: +# +# swapper 0 [000] 158665.570607: cpu-clock: +# ffffffff8103ce3b native_safe_halt ([kernel.kallsyms]) +# ffffffff8101c6a3 default_idle ([kernel.kallsyms]) +# ffffffff81013236 cpu_idle ([kernel.kallsyms]) +# ffffffff815bf03e rest_init ([kernel.kallsyms]) +# ffffffff81aebbfe start_kernel ([kernel.kallsyms].init.text) +# [...] +# +# Example output: +# +# swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 1 +# +# Input may be created and processed using: +# +# perf record -a -g -F 997 sleep 60 +# perf script | ./stackcollapse-perf.pl > out.stacks-folded +# +# The output of "perf script" should include stack traces. If these are missing +# for you, try manually selecting the perf script output; eg: +# +# perf script -f comm,pid,tid,cpu,time,event,ip,sym,dso,trace | ... +# +# This is also required for the --pid or --tid options, so that the output has +# both the PID and TID. +# +# Copyright 2012 Joyent, Inc. All rights reserved. +# Copyright 2012 Brendan Gregg. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# 02-Mar-2012 Brendan Gregg Created this. +# 02-Jul-2014 " " Added process name to stacks. + +use strict; +use Getopt::Long; + +my %collapsed; + +sub remember_stack { + my ($stack, $count) = @_; + $collapsed{$stack} += $count; +} +my $annotate_kernel = 0; # put an annotation on kernel function +my $annotate_jit = 0; # put an annotation on jit symbols +my $annotate_all = 0; # enale all annotations +my $include_pname = 1; # include process names in stacks +my $include_pid = 0; # include process ID with process name +my $include_tid = 0; # include process & thread ID with process name +my $include_addrs = 0; # include raw address where a symbol can't be found +my $tidy_java = 1; # condense Java signatures +my $tidy_generic = 1; # clean up function names a little +my $target_pname; # target process name from perf invocation +my $event_filter = ""; # event type filter, defaults to first encountered event +my $event_defaulted = 0; # whether we defaulted to an event (none provided) +my $event_warning = 0; # if we printed a warning for the event + +my $show_inline = 0; +my $show_context = 0; + +my $srcline_in_input = 0; # if there are extra lines with source location (perf script -F+srcline) +GetOptions('inline' => \$show_inline, + 'context' => \$show_context, + 'srcline' => \$srcline_in_input, + 'pid' => \$include_pid, + 'kernel' => \$annotate_kernel, + 'jit' => \$annotate_jit, + 'all' => \$annotate_all, + 'tid' => \$include_tid, + 'addrs' => \$include_addrs, + 'event-filter=s' => \$event_filter) +or die < outfile\n + --pid # include PID with process names [1] + --tid # include TID and PID with process names [1] + --inline # un-inline using addr2line + --all # all annotations (--kernel --jit) + --kernel # annotate kernel functions with a _[k] + --jit # annotate jit functions with a _[j] + --context # adds source context to --inline + --srcline # parses output of 'perf script -F+srcline' and adds source context + --addrs # include raw addresses where symbols can't be found + --event-filter=EVENT # event name filter\n +[1] perf script must emit both PID and TIDs for these to work; eg, Linux < 4.1: + perf script -f comm,pid,tid,cpu,time,event,ip,sym,dso,trace + for Linux >= 4.1: + perf script -F comm,pid,tid,cpu,time,event,ip,sym,dso,trace + If you save this output add --header on Linux >= 3.14 to include perf info. +USAGE_END + +if ($annotate_all) { + $annotate_kernel = $annotate_jit = 1; +} + +my %inlineCache; + +my %nmCache; + +sub inlineCacheAdd { + my ($pc, $mod, $result) = @_; + if (defined($inlineCache{$pc})) { + $inlineCache{$pc}{$mod} = $result; + } else { + $inlineCache{$pc} = {$mod => $result}; + } +} + +# for the --inline option +sub inline { + my ($pc, $rawfunc, $mod) = @_; + + return $inlineCache{$pc}{$mod} if defined($inlineCache{$pc}{$mod}); + + # capture addr2line output + my $a2l_output = `addr2line -a $pc -e $mod -i -f -s -C`; + + # remove first line + $a2l_output =~ s/^(.*\n){1}//; + + if ($a2l_output =~ /\?\?\n\?\?:0/) { + # if addr2line fails and rawfunc is func+offset, then fall back to it + if ($rawfunc =~ /^(.+)\+0x([0-9a-f]+)$/) { + my $func = $1; + my $addr = hex $2; + + $nmCache{$mod}=`nm $mod` unless defined $nmCache{$mod}; + + if ($nmCache{$mod} =~ /^([0-9a-f]+) . \Q$func\E$/m) { + my $base = hex $1; + my $newPc = sprintf "0x%x", $base+$addr; + my $result = inline($newPc, '', $mod); + inlineCacheAdd($pc, $mod, $result); + return $result; + } + } + } + + my @fullfunc; + my $one_item = ""; + for (split /^/, $a2l_output) { + chomp $_; + + # remove discriminator info if exists + $_ =~ s/ \(discriminator \S+\)//; + + if ($one_item eq "") { + $one_item = $_; + } else { + if ($show_context == 1) { + unshift @fullfunc, $one_item . ":$_"; + } else { + unshift @fullfunc, $one_item; + } + $one_item = ""; + } + } + + my $result = join ";" , @fullfunc; + + inlineCacheAdd($pc, $mod, $result); + + return $result; +} + +my @stack; +my $pname; +my $m_pid; +my $m_tid; +my $m_period; + +# +# Main loop +# +while (defined($_ = <>)) { + + # find the name of the process launched by perf, by stepping backwards + # over the args to find the first non-option (no dash): + if (/^# cmdline/) { + my @args = split ' ', $_; + foreach my $arg (reverse @args) { + if ($arg !~ /^-/) { + $target_pname = $arg; + $target_pname =~ s:.*/::; # strip pathname + last; + } + } + } + + # skip remaining comments + next if m/^#/; + chomp; + + # end of stack. save cached data. + if (m/^$/) { + # ignore filtered samples + next if not $pname; + + if ($include_pname) { + if (defined $pname) { + unshift @stack, $pname; + } else { + unshift @stack, ""; + } + } + remember_stack(join(";", @stack), $m_period) if @stack; + undef @stack; + undef $pname; + next; + } + + # + # event record start + # + if (/^(\S.+?)\s+(\d+)\/*(\d+)*\s+/) { + # default "perf script" output has TID but not PID + # eg, "java 25607 4794564.109216: 1 cycles:" + # eg, "java 12688 [002] 6544038.708352: 235 cpu-clock:" + # eg, "V8 WorkerThread 25607 4794564.109216: 104345 cycles:" + # eg, "java 24636/25607 [000] 4794564.109216: 1 cycles:" + # eg, "java 12688/12764 6544038.708352: 10309278 cpu-clock:" + # eg, "V8 WorkerThread 24636/25607 [000] 94564.109216: 100 cycles:" + # other combinations possible + my ($comm, $pid, $tid, $period) = ($1, $2, $3, ""); + if (not $tid) { + $tid = $pid; + $pid = "?"; + } + + if (/:\s*(\d+)*\s+(\S+):\s*$/) { + $period = $1; + my $event = $2; + + if ($event_filter eq "") { + # By default only show events of the first encountered + # event type. Merging together different types, such as + # instructions and cycles, produces misleading results. + $event_filter = $event; + $event_defaulted = 1; + } elsif ($event ne $event_filter) { + if ($event_defaulted and $event_warning == 0) { + # only print this warning if necessary: + # when we defaulted and there was + # multiple event types. + print STDERR "Filtering for events of type: $event\n"; + $event_warning = 1; + } + next; + } + } + + if (not $period) { + $period = 1 + } + ($m_pid, $m_tid, $m_period) = ($pid, $tid, $period); + + if ($include_tid) { + $pname = "$comm-$m_pid/$m_tid"; + } elsif ($include_pid) { + $pname = "$comm-$m_pid"; + } else { + $pname = "$comm"; + } + $pname =~ tr/ /_/; + + # + # stack line + # + } elsif (/^\s*(\w+)\s*(.+) \((.*)\)/) { + # ignore filtered samples + next if not $pname; + + my ($pc, $rawfunc, $mod) = ($1, $2, $3); + + if ($show_inline == 1 && $mod !~ m/(perf-\d+.map|kernel\.|\[[^\]]+\])/) { + my $inlineRes = inline($pc, $rawfunc, $mod); + # - empty result this happens e.g., when $mod does not exist or is a path to a compressed kernel module + # if this happens, the user will see error message from addr2line written to stderr + # - if addr2line results in "??" , then it's much more sane to fall back than produce a '??' in graph + if($inlineRes ne "" and $inlineRes ne "??" and $inlineRes ne "??:??:0" ) { + unshift @stack, $inlineRes; + next; + } + } + + # Linux 4.8 included symbol offsets in perf script output by default, eg: + # 7fffb84c9afc cpu_startup_entry+0x800047c022ec ([kernel.kallsyms]) + # strip these off: + $rawfunc =~ s/\+0x[\da-f]+$//; + + next if $rawfunc =~ /^\(/; # skip process names + + my $is_unknown=0; + my @inline; + for (split /\->/, $rawfunc) { + my $func = $_; + + if ($func eq "[unknown]") { + if ($mod ne "[unknown]") { # use module name instead, if known + $func = $mod; + $func =~ s/.*\///; + } else { + $func = "unknown"; + $is_unknown=1; + } + + if ($include_addrs) { + $func = "\[$func \<$pc\>\]"; + } else { + $func = "\[$func\]"; + } + } + + if ($tidy_generic) { + $func =~ s/;/:/g; + if ($func !~ m/\.\(.*\)\./) { + # This doesn't look like a Go method name (such as + # "net/http.(*Client).Do"), so everything after the first open + # paren (that is not part of an "(anonymous namespace)") is + # just noise. + $func =~ s/\((?!anonymous namespace\)).*//; + } + # now tidy this horrible thing: + # 13a80b608e0a RegExp:[&<>\"\'] (/tmp/perf-7539.map) + $func =~ tr/"\'//d; + # fall through to $tidy_java + } + + if ($tidy_java and $pname =~ m/^java/) { + # along with $tidy_generic, converts the following: + # Lorg/mozilla/javascript/ContextFactory;.call(Lorg/mozilla/javascript/ContextAction;)Ljava/lang/Object; + # Lorg/mozilla/javascript/ContextFactory;.call(Lorg/mozilla/javascript/C + # Lorg/mozilla/javascript/MemberBox;.(Ljava/lang/reflect/Method;)V + # into: + # org/mozilla/javascript/ContextFactory:.call + # org/mozilla/javascript/ContextFactory:.call + # org/mozilla/javascript/MemberBox:.init + $func =~ s/^L// if $func =~ m:/:; + } + + # + # Annotations + # + # detect inlined from the @inline array + # detect kernel from the module name; eg, frames to parse include: + # ffffffff8103ce3b native_safe_halt ([kernel.kallsyms]) + # 8c3453 tcp_sendmsg (/lib/modules/4.3.0-rc1-virtual/build/vmlinux) + # 7d8 ipv4_conntrack_local+0x7f8f80b8 ([nf_conntrack_ipv4]) + # detect jit from the module name; eg: + # 7f722d142778 Ljava/io/PrintStream;::print (/tmp/perf-19982.map) + if (scalar(@inline) > 0) { + $func .= "_[i]" unless $func =~ m/\_\[i\]/; # inlined + } elsif ($annotate_kernel == 1 && $mod =~ m/(^\[|vmlinux$)/ && $mod !~ /unknown/) { + $func .= "_[k]"; # kernel + } elsif ($annotate_jit == 1 && $mod =~ m:/tmp/perf-\d+\.map:) { + $func .= "_[j]" unless $func =~ m/\_\[j\]/; # jitted + } + + # + # Source lines + # + # + # Sample outputs: + # | a.out 35081 252436.005167: 667783 cycles: + # | 408ebb some_method_name+0x8b (/full/path/to/a.out) + # | uniform_int_dist.h:300 + # | 4069f5 main+0x935 (/full/path/to/a.out) + # | file.cpp:137 + # | 7f6d2148eb25 __libc_start_main+0xd5 (/lib64/libc-2.33.so) + # | libc-2.33.so[27b25] + # + # | a.out 35081 252435.738165: 306459 cycles: + # | 7f6d213c2750 [unknown] (/usr/lib64/libkmod.so.2.3.6) + # | libkmod.so.2.3.6[6750] + # + # | a.out 35081 252435.738373: 315813 cycles: + # | 7f6d215ca51b __strlen_avx2+0x4b (/lib64/libc-2.33.so) + # | libc-2.33.so[16351b] + # | 7ffc71ee9580 [unknown] ([unknown]) + # | + # + # | a.out 35081 252435.718940: 247984 cycles: + # | ffffffff814f9302 up_write+0x32 ([kernel.kallsyms]) + # | [kernel.kallsyms][ffffffff814f9302] + if($srcline_in_input and not $is_unknown){ + $_ = <>; + chomp; + s/\[.*?\]//g; + s/^\s*//g; + s/\s*$//g; + $func.=':'.$_ unless $_ eq ""; + } + + push @inline, $func; + } + + unshift @stack, @inline; + } else { + warn "Unrecognized line: $_"; + } +} + +foreach my $k (sort { $a cmp $b } keys %collapsed) { + print "$k $collapsed{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-pmc.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-pmc.pl new file mode 100755 index 00000000000..5bd7c2dada4 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-pmc.pl @@ -0,0 +1,74 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2014 Ed Maste. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# stackcollapse-pmc.pl collapse hwpmc samples into single lines. +# +# Parses a list of multiline stacks generated by "hwpmc -G", and outputs a +# semicolon-separated stack followed by a space and a count. +# +# Usage: +# pmcstat -S unhalted-cycles -O pmc.out +# pmcstat -R pmc.out -z16 -G pmc.graph +# stackcollapse-pmc.pl pmc.graph > pmc.stack +# +# Example input: +# +# 03.07% [17] witness_unlock @ /boot/kernel/kernel +# 70.59% [12] __mtx_unlock_flags +# 16.67% [2] selfdfree +# 100.0% [2] sys_poll +# 100.0% [2] amd64_syscall +# 08.33% [1] pmap_ts_referenced +# 100.0% [1] vm_pageout +# 100.0% [1] fork_exit +# ... +# +# Example output: +# +# amd64_syscall;sys_poll;selfdfree;__mtx_unlock_flags;witness_unlock 2 +# amd64_syscall;sys_poll;pmap_ts_referenced;__mtx_unlock_flagsgeout;fork_exit 1 +# ... + +use warnings; +use strict; + +my @stack; +my $prev_count; +my $prev_indent = -1; + +while (defined($_ = <>)) { + if (m/^( *)[0-9.]+% \[([0-9]+)\]\s*(\S+)/) { + my $indent = length($1); + if ($indent <= $prev_indent) { + print join(';', reverse(@stack[0 .. $prev_indent])) . + " $prev_count\n"; + } + $stack[$indent] = $3; + $prev_count = $2; + $prev_indent = $indent; + } +} +print join(';', reverse(@stack[0 .. $prev_indent])) . " $prev_count\n"; diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-recursive.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-recursive.pl new file mode 100755 index 00000000000..9eae54592c4 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-recursive.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl -ws +# +# stackcollapse-recursive Collapse direct recursive backtraces +# +# Post-process a stack list and merge direct recursive calls: +# +# Example input: +# +# main;recursive;recursive;recursive;helper 1 +# +# Output: +# +# main;recursive;helper 1 +# +# Copyright 2014 Gabriel Corona. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END + +my %stacks; + +while(<>) { + chomp; + my ($stack_, $value) = (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + if ($stack_) { + my @stack = split(/;/, $stack_); + + my @result = (); + my $i; + my $last=""; + for($i=0; $i!=@stack; ++$i) { + if(!($stack[$i] eq $last)) { + $result[@result] = $stack[$i]; + $last = $stack[$i]; + } + } + + $stacks{join(";", @result)} += $value; + } +} + +foreach my $k (sort { $a cmp $b } keys %stacks) { + print "$k $stacks{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-sample.awk b/tests/benchmarks/_script/flamegraph/stackcollapse-sample.awk new file mode 100755 index 00000000000..bafc4af3468 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-sample.awk @@ -0,0 +1,231 @@ +#!/usr/bin/awk -f +# +# Uses MacOS' /usr/bin/sample to generate a flamegraph of a process +# +# Usage: +# +# sudo sample [pid] -file /dev/stdout | stackcollapse-sample.awk | flamegraph.pl +# +# Options: +# +# The output will show the name of the library/framework at the call-site +# with the form AppKit`NSApplication or libsystem`start_wqthread. +# +# If showing the framework or library name is not required, pass +# MODULES=0 as an argument of the sample program. +# +# The generated SVG will be written to the output stream, and can be piped +# into flamegraph.pl directly, or written to a file for conversion later. +# +# --- +# +# Copyright (c) 2017, Apple Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +BEGIN { + + # Command line options + MODULES = 1 # Allows the user to enable/disable printing of modules. + + # Internal variables + _FOUND_STACK = 0 # Found the stack traces in the output. + _LEVEL = -1 # The current level of indentation we are running. + + # The set of symbols to ignore for 'waiting' threads, for ease of use. + # This will hide waiting threads from the view, making it easier to + # see what is actually running in the sample. These may be adjusted + # as necessary or appended to if other symbols need to be filtered out. + + _IGNORE["libsystem_kernel`__psynch_cvwait"] = 1 + _IGNORE["libsystem_kernel`__select"] = 1 + _IGNORE["libsystem_kernel`__semwait_signal"] = 1 + _IGNORE["libsystem_kernel`__ulock_wait"] = 1 + _IGNORE["libsystem_kernel`__wait4"] = 1 + _IGNORE["libsystem_kernel`__workq_kernreturn"] = 1 + _IGNORE["libsystem_kernel`kevent"] = 1 + _IGNORE["libsystem_kernel`mach_msg_trap"] = 1 + _IGNORE["libsystem_kernel`read"] = 1 + _IGNORE["libsystem_kernel`semaphore_wait_trap"] = 1 + + # The same set of symbols as above, without the module name. + _IGNORE["__psynch_cvwait"] = 1 + _IGNORE["__select"] = 1 + _IGNORE["__semwait_signal"] = 1 + _IGNORE["__ulock_wait"] = 1 + _IGNORE["__wait4"] = 1 + _IGNORE["__workq_kernreturn"] = 1 + _IGNORE["kevent"] = 1 + _IGNORE["mach_msg_trap"] = 1 + _IGNORE["read"] = 1 + _IGNORE["semaphore_wait_trap"] = 1 + +} + +# This is the first line in the /usr/bin/sample output that indicates the +# samples follow subsequently. Until we see this line, the rest is ignored. + +/^Call graph/ { + _FOUND_STACK = 1 +} + +# This is found when we have reached the end of the stack output. +# Identified by the string "Total number in stack (...)". + +/^Total number/ { + _FOUND_STACK = 0 + printStack(_NEST,0) +} + +# Prints the stack from FROM to TO (where FROM > TO) +# Called when indenting back from a previous level, or at the end +# of processing to flush the last recorded sample + +function printStack(FROM,TO) { + + # We ignore certain blocking wait states, in the absence of being + # able to filter these threads from collection, otherwise + # we'll end up with many threads of equal length that represent + # the total time the sample was collected. + # + # Note that we need to collect the information to ensure that the + # timekeeping for the parental functions is appropriately adjusted + # so we just avoid printing it out when that occurs. + _PRINT_IT = !_IGNORE[_NAMES[FROM]] + + # We run through all the names, from the root to the leaf, so that + # we generate a line that flamegraph.pl will like, of the form: + # Thread1234;example`main;example`otherFn 1234 + + for(l = FROM; l>=TO; l--) { + if (_PRINT_IT) { + printf("%s", _NAMES[0]) + for(i=1; i<=l; i++) { + printf(";%s", _NAMES[i]) + } + print " " _TIMES[l] + } + + # We clean up our current state to avoid bugs. + delete _NAMES[l] + delete _TIMES[l] + } +} + +# This is where we process each line, of the form: +# 5130 Thread_8749954 +# + 5130 start_wqthread (in libsystem_pthread.dylib) ... +# + 4282 _pthread_wqthread (in libsystem_pthread.dylib) ... +# + ! 4282 __doworkq_kernreturn (in libsystem_kernel.dylib) ... +# + 848 _pthread_wqthread (in libsystem_pthread.dylib) ... +# + 848 __doworkq_kernreturn (in libsystem_kernel.dylib) ... + +_FOUND_STACK && match($0,/^ [^0-9]*[0-9]/) { + + # We maintain two counters: + # _LEVEL: the high water mark of the indentation level we have seen. + # _NEST: the current indentation level. + # + # We keep track of these two levels such that when the nesting level + # decreases, we print out the current state of where we are. + + _NEST=(RLENGTH-5)/2 + sub(/^[^0-9]*/,"") # Normalise the leading content so we start with time. + _TIME=$1 # The time recorded by 'sample', first integer value. + + # The function name is in one or two parts, depending on what kind of + # function it is. + # + # If it is a standard C or C++ function, it will be of the form: + # exampleFunction + # Example::Function + # + # If it is an Objective-C funtion, it will be of the form: + # -[NSExample function] + # +[NSExample staticFunction] + # -[NSExample function:withParameter] + # +[NSExample staticFunction:withParameter:andAnother] + + _FN1 = $2 + _FN2 = $3 + + # If it is a standard C or C++ function then the following word will + # either be blank, or the text '(in', so we jut use the first one: + + if (_FN2 == "(in" || _FN2 == "") { + _FN =_FN1 + } else { + # Otherwise we concatenate the first two parts with . + _FN = _FN1 "." _FN2 + } + + # Modules are shown with '(in libfoo.dylib)' or '(in AppKit)' + + _MODULE = "" + match($0, /\(in [^)]*\)/) + + if (RSTART > 0 && MODULES) { + + # Strip off the '(in ' (4 chars) and the final ')' char (1 char) + _MODULE = substr($0, RSTART+4, RLENGTH-5) + + # Remove the .dylib function, since it adds no value. + gsub(/\.dylib/, "", _MODULE) + + # The function name is 'module`functionName' + _FN = _MODULE "`" _FN + } + + # Now we have set up the variables, we can decide how to apply it + # If we are descending in the nesting, we don't print anything out: + # a + # ab + # abc + # + # We only print out something when we go back a level, or hit the end: + # abcd + # abe < prints out the stack up until this point, i.e. abcd + + # We store a pair of arrays, indexed by the nesting level: + # + # _TIMES - a list of the time reported to that function + # _NAMES - a list of the function names for each current stack trace + + # If we are backtracking, we need to flush the current output. + if (_NEST <= _LEVEL) { + printStack(_LEVEL,_NEST) + } + + # Record the name and time of the function where we are. + _NAMES[_NEST] = _FN + _TIMES[_NEST] = _TIME + + # We subtract the time we took from our parent so we don't double count. + if (_NEST > 0) { + _TIMES[_NEST-1] -= _TIME + } + + # Raise the high water mark of the level we have reached. + _LEVEL = _NEST +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-stap.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-stap.pl new file mode 100755 index 00000000000..bca4046192f --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-stap.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl -w +# +# stackcollapse-stap.pl collapse multiline SystemTap stacks +# into single lines. +# +# Parses a multiline stack followed by a number on a separate line, and +# outputs a semicolon separated stack followed by a space and the number. +# If memory addresses (+0xd) are present, they are stripped, and resulting +# identical stacks are colased with their counts summed. +# +# USAGE: ./stackcollapse.pl infile > outfile +# +# Example input: +# +# 0xffffffff8103ce3b : native_safe_halt+0xb/0x10 [kernel] +# 0xffffffff8101c6a3 : default_idle+0x53/0x1d0 [kernel] +# 0xffffffff81013236 : cpu_idle+0xd6/0x120 [kernel] +# 0xffffffff815bf03e : rest_init+0x72/0x74 [kernel] +# 0xffffffff81aebbfe : start_kernel+0x3ba/0x3c5 [kernel] +# 2404 +# +# Example output: +# +# start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 2404 +# +# Input may contain many stacks as generated from SystemTap. +# +# Copyright 2011 Joyent, Inc. All rights reserved. +# Copyright 2011 Brendan Gregg. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# 16-Feb-2012 Brendan Gregg Created this. + +use strict; + +my %collapsed; + +sub remember_stack { + my ($stack, $count) = @_; + $collapsed{$stack} += $count; +} + +my @stack; + +foreach (<>) { + chomp; + + if (m/^\s*(\d+)+$/) { + remember_stack(join(";", @stack), $1); + @stack = (); + next; + } + + next if (m/^\s*$/); + + my $frame = $_; + $frame =~ s/^\s*//; + $frame =~ s/\+[^+]*$//; + $frame =~ s/.* : //; + $frame = "-" if $frame eq ""; + unshift @stack, $frame; +} + +foreach my $k (sort { $a cmp $b } keys %collapsed) { + printf "$k $collapsed{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-vsprof.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-vsprof.pl new file mode 100755 index 00000000000..a13c1daab35 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-vsprof.pl @@ -0,0 +1,98 @@ +#!/usr/bin/perl -w +# +# stackcollapse-vsprof.pl +# +# Parses the CSV file containing a call tree from a visual studio profiler and produces an output suitable for flamegraph.pl. +# +# USAGE: perl stackcollapse-vsprof.pl infile > outfile +# +# WORKFLOW: +# +# This example assumes you have visual studio 2015 installed. +# +# 1. Profile C++ your application using visual studio +# 2. On visual studio, choose export the call tree as csv +# 3. Generate a flamegraph: perl stackcollapse-vsprof CallTreeSummary.csv | perl flamegraph.pl > result_vsprof.svg +# +# INPUT EXAMPLE : +# +# Level,Function Name,Inclusive Samples,Exclusive Samples,Inclusive Samples %,Exclusive Samples %,Module Name, +# 1,"main","8,735",0,100.00,0.00,"an_executable.exe", +# 2,"testing::UnitTest::Run","8,735",0,100.00,0.00,"an_executable.exe", +# 3,"boost::trim_end_iter_select > >,boost::is_classifiedF>",306,16,3.50,0.18,"an_executable.exe", +# +# OUTPUT EXAMPLE : +# +# main;testing::UnitTest::Run;boost::trim_end_iter_select>>,boost::is_classifiedF> 306 + +use strict; + +sub massage_function_names; +sub parse_integer; +sub print_stack_trace; + +# data initialization +my @stack = (); +my $line_number = 0; +my $previous_samples = 0; + +my $num_args = $#ARGV + 1; +if ($num_args != 1) { + print "$ARGV[0]\n"; + print "Usage : stackcollapse-vsprof.pl > out.txt\n"; + exit; +} + +my $input_csv_file = $ARGV[0]; +my $line_parser_rx = qr{ + ^\s*(\d+?), # level in the stack + ("[^"]+" | [^,]+), # function name (beware of spaces) + ("[^"]+" | [^,]+), # number of samples (beware of locale number formatting) +}ox; + +open(my $fh, '<', $input_csv_file) or die "Can't read file '$input_csv_file' [$!]\n"; + +while (my $current_line = <$fh>){ + $line_number = $line_number + 1; + + # to discard first line which typically contains headers + next if $line_number == 1; + next if $current_line =~ /^\s*$/o; + + ($current_line =~ $line_parser_rx) or die "Error in regular expression at line $line_number : $current_line\n"; + + my $level = int $1; + my $function = massage_function_names($2); + my $samples = parse_integer($3); + my $stack_len = @stack; + + #print "[DEBUG] $line_number : $level $function $samples $stack_len\n"; + + next if not $level; + ($level <= $stack_len + 1) or die "Error in stack at line $line_number : $current_line\n"; + + if ($level <= $stack_len) { + print_stack_trace(\@stack, $previous_samples); + my $to_remove = $level - $stack_len - 1; + splice(@stack, $to_remove); + } + + $stack_len < 1000 or die "Stack overflow at line $line_number"; + push(@stack, $function); + $previous_samples = $samples; +} +print_stack_trace(\@stack, $previous_samples); + +sub massage_function_names { + return ($_[0] =~ s/\s*|^"|"$//gro); +} + +sub parse_integer { + return int ($_[0] =~ s/[., ]|^"|"$//gro); +} + +sub print_stack_trace { + my ($stack_ref, $sample) = @_; + my $stack_trace = join(";", @$stack_ref); + print "$stack_trace $sample\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-vtune-mc.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-vtune-mc.pl new file mode 100755 index 00000000000..e132ab08cf3 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-vtune-mc.pl @@ -0,0 +1,103 @@ +#!/usr/bin/perl -w +# +# stackcollapse-vtune-mc.pl +# +# Parses the CSV file containing a call tree from Intel VTune memory-consumption profiler and produces an output suitable for flamegraph.pl. +# +# USAGE: perl stackcollapse-vtune-mc.pl [options] infile > outfile +# +# WORKFLOW: +# +# This assumes you have Intel VTune installed and on path (using Command Line) +# +# 1. Profile C++ application tachyon (example shipped with Intel VTune 2019): +# +# amplxe-cl -collect memory-consumption -r mc_tachyon -- ./tachyon +# +# 2. Export raw VTune data to csv file: +# ### for Intel VTune 2019 +# amplxe-cl -R top-down -call-stack-mode all \ +# -column="Allocations:Self","Allocation Size:Self","Module" \ +# -report-out allocations.csv -format csv \ +# -csv-delimiter comma -r mc_tachyon +# +# 3. Generate a flamegraph: +# ## Generate for allocations amount. +# perl stackcollapse-vtune-mc.pl allocations.csv > out.folded +# perl flamegraph.pl --countname=allocations out.folded > vtune_tachyon_mc.svg +# +# ## Or you can generate for allocation size in bytes. +# perl stackcollapse-vtune-mc.pl -s allocations.csv > out.folded +# perl flamegraph.pl --countname=allocations out.folded > vtune_tachyon_mc_size.svg +# +# AUTHOR: Rohith Bakkannagari +# 27-Nov-2019 UnpluggedCoder Forked from stackcollapse-vtune.pl, for memory-consumption flamegraph + +use strict; +use Getopt::Long; + +sub usage { + die < out.folded\n + --size # Accumulate allocation size in bytes instead of allocation counts.\n +NOTE : The csv file should exported by `amplxe-cl` tool with the exact -column parameter shows below. + amplxe-cl -R top-down -call-stack-mode all \ + -column="Allocations:Self","Allocation Size:Self","Module" \ + -report-out allocations.csv -format csv \ + -csv-delimiter comma -r mc_tachyon +USAGE_END +} + +# data initialization +my @stack = (); +my $rowCounter = 0; # flag for row number + +my $accSize = ''; +GetOptions ('size' => \$accSize) +or usage(); + +my $numArgs = $#ARGV + 1; +if ($numArgs != 1){ + usage(); + exit; +} + +my $inputCSVFile = $ARGV[0]; +open(my $fh, '<', $inputCSVFile) or die "Can't read file '$inputCSVFile' [$!]\n"; + +while (my $currLine = <$fh>){ + # discard warning line + next if $rowCounter == 0 && rindex($currLine, "war:", 0) == 0; + $rowCounter = $rowCounter + 1; + # to discard first row which typically contains headers + next if $rowCounter == 1; + chomp $currLine; + #VTune - sometimes the call stack information is enclosed in double quotes (?). To remove double quotes. + $currLine =~ s/\"//g; + + ### for Intel VTune 2019 + ### CSV header should be like below + ### Function Stack,Allocation Size:Self,Deallocation Size:Self,Allocations:Self,Module + $currLine =~ /(\s*)(.*?),([0-9]*?\.?[0-9]*?),([0-9]*?\.?[0-9]*?),([0-9]*?\.?[0-9]*?),(.*)/ or die "Error in regular expression on the current line $currLine\n"; + my $func = $2.'('.$6.')'; # function(module) + my $depth = length ($1); + my $allocBytes = $3; # allocation size + my $allocs = $5; # allocations + + my $tempString = ''; + $stack [$depth] = $func; + if ($accSize){ + next if $allocBytes eq ''; + foreach my $i (0 .. $depth - 1) { + $tempString = $tempString.$stack[$i].";"; + } + $tempString = $tempString.$func." $allocBytes\n"; + } else { + next if $allocs == 0; + foreach my $i (0 .. $depth - 1) { + $tempString = $tempString.$stack[$i].";"; + } + $tempString = $tempString.$func." $allocs\n"; + } + print "$tempString"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-vtune.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-vtune.pl new file mode 100644 index 00000000000..2a13e3b2d95 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-vtune.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl -w +# +# stackcollapse-vtune.pl +# +# Parses the CSV file containing a call tree from Intel VTune hotspots profiler and produces an output suitable for flamegraph.pl. +# +# USAGE: perl stackcollapse-vtune.pl infile > outfile +# +# WORKFLOW: +# +# This assumes you have Intel VTune installed and on path (using Command Line) +# +# 1. Profile C++ application tachyon_find_hotspots (example shipped with Intel VTune 2013): +# +# amplxe-cl -collect hotspots -r result_vtune_tachyon -- ./tachyon_find_hotspots +# +# 2. Export raw VTune data to csv file: +# +##### VTune 2013 & 2015 +# amplxe-cl -R top-down -report-out result_vtune_tachyon.csv -filter "Function Stack" -format csv -csv-delimiter comma -r result_vtune_tachyon +#### VTune 2016 +# amplxe-cl.exe -R top-down -call-stack-mode all -column="CPU Time:Self","Module" -report-output result_vtune_tachyon.csv -filter "Function Stack" -format csv -csv-delimiter comma -r result_vtune_tachyon +# +# 3. Generate a flamegraph: +# +# perl stackcollapse-vtune result_vtune_tachyon.csv | perl flamegraph.pl > result_vtune_tachyon.svg +# +# AUTHOR: Rohith Bakkannagari + +use strict; + +# data initialization +my @stack = (); +my $rowCounter = 0; #flag for row number + +my $numArgs = $#ARGV + 1; +if ($numArgs != 1) +{ +print "$ARGV[0]\n"; +print "Usage : stackcollapse-vtune.pl > out.txt\n"; +exit; +} + +my $inputCSVFile = $ARGV[0]; +my $funcOnly = ''; +my $depth = 0; +my $selfTime = 0; +my $dllName = ''; + +open(my $fh, '<', $inputCSVFile) or die "Can't read file '$inputCSVFile' [$!]\n"; + +while (my $currLine = <$fh>){ + $rowCounter = $rowCounter + 1; + # to discard first row which typically contains headers + next if $rowCounter == 1; + chomp $currLine; + + ### VTune 2013 & 2015 + #VTune - sometimes the call stack information is enclosed in double quotes (?). To remove double quotes. Not necessary for XCode instruments (MAC) + $currLine =~ s/\"//g; + $currLine =~ /(\s*)(.*),(.*),.*,([0-9]*\.?[0-9]+)/ or die "Error in regular expression on the current line\n"; + $dllName = $3; + $func = $dllName.'!'.$2; # Eg : m_lxe.dll!MathWorks::lxe::IrEngineDecorator::Apply + $depth = length ($1); + $selfTime = $4*1000; # selfTime in msec + ### VTune 2013 & 2015 + + ### VTune 2016 + # $currLine =~ /(\s*)(.*?),([0-9]*\.?[0-9]+?),(.*)/ or die "Error in regular expression on the current line $currLine\n"; + # if ($2 =~ /\"/) + # { + # $currLine =~ /(\s*)\"(.*?)\",([0-9]*\.?[0-9]+?),(.*)/ or die "Error in regular expression on the current line $currLine\n"; + # $funcOnly = $2; + # $depth = length ($1); + # $selfTime = $3*1000; # selfTime in msec + # $dllName = $4; + # } + # else + # { + # $funcOnly = $2; + # $depth = length ($1); + # $selfTime = $3*1000; # selfTime in msec + # $dllName = $4; + # } + # my $func = $dllName.'!'.$funcOnly; # Eg : m_lxe.dll!MathWorks::lxe::IrEngineDecorator::Apply + ### VTune 2016 + + my $tempString = ''; + $stack [$depth] = $func; + foreach my $i (0 .. $depth - 1) { + $tempString = $tempString.$stack[$i].";"; + } + $tempString = $tempString.$func." $selfTime\n"; + if ($selfTime != 0){ + print "$tempString"; + } +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-wcp.pl b/tests/benchmarks/_script/flamegraph/stackcollapse-wcp.pl new file mode 100755 index 00000000000..4d1d58434a0 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-wcp.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl -ws +# +# stackcollapse-wcp Collapse wallClockProfiler backtraces +# +# Parse a list of GDB backtraces as generated by https://github.com/jasonrohrer/wallClockProfiler +# +# Copyright 2014 Gabriel Corona. All rights reserved. +# Portions Copyright 2020 Ștefan Talpalaru +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END + +use strict; + +my $current = ""; +my $start_processing = 0; +my $samples = 0; +my %stacks; + +while(<>) { + s/^\s+|\s+$//g; + + if (m/^Full stacks/) { + $start_processing = 1; + next; + } + + if (not $start_processing) { + next; + } + + if(m/^\d+\.\d+% =+ \((\d+) samples\)/) { + # 99.791% ===================================== (17194 samples) + $samples = $1; + next; + } elsif (m/^\d+: (.*)$/) { + # 1: poll__YNjd8fE6xG8CRNwfLnrx0g_2 (at /mnt/sde1/storage/nim-beacon-chain-clean/vendor/nim-chronos/chronos/asyncloop.nim:343) + my $function = $1; + if ($current eq "") { + $current = $function; + } else { + $current = $function . ";" . $current; + } + } elsif (m/^$/ and $current ne "") { + $stacks{$current} += $samples; + $current = ""; + } +} + +foreach my $k (sort { $a cmp $b } keys %stacks) { + print "$k $stacks{$k}\n"; +} + diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse-xdebug.php b/tests/benchmarks/_script/flamegraph/stackcollapse-xdebug.php new file mode 100755 index 00000000000..52cc3d65a0c --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse-xdebug.php @@ -0,0 +1,197 @@ +#!/usr/bin/php + outfile + -h --help Show this message + -t Weight stack counts by duration using the time index in the trace (default) + -c Invocation counts only. Simply count stacks in the trace and sum duplicates, don't weight by duration. + +Example input: +For more info on xdebug and generating traces see +https://xdebug.org/docs/execution_trace. + +Version: 2.0.0RC4-dev +TRACE START [2007-05-06 18:29:01] +1 0 0 0.010870 114112 {main} 1 ../trace.php 0 +2 1 0 0.032009 114272 str_split 0 ../trace.php 8 +2 1 1 0.032073 116632 +2 2 0 0.033505 117424 ret_ord 1 ../trace.php 10 +3 3 0 0.033531 117584 ord 0 ../trace.php 5 +3 3 1 0.033551 117584 +... +TRACE END [2007-05-06 18:29:01] + +Example output: + +- c +{main};str_split 1 +{main};ret_ord;ord 6 + +-t +{main} 23381 +{main};str_split 64 +{main};ret_ord 215 +{main};ret_ord;ord 106 + +EOT; + + exit($exit); +} + +function collapseStack(array $stack, string $func_name_key): string { + return implode(';', array_column($stack, $func_name_key)); +} + +function addCurrentStackToStacks(array $stack, float $dur, array &$stacks) { + $collapsed = implode(';', $stack); + $duration = SCALE_FACTOR * $dur; + + if (array_key_exists($collapsed, $stacks)) { + $stacks[$collapsed] += $duration; + } else { + $stacks[$collapsed] = $duration; + } +} + +function isEOTrace(string $l) { + $pattern = "/^(\\t|TRACE END)/"; + return preg_match($pattern, $l); +} + +$filename = $argv[$optind] ?? null; +if ($filename === null) { + usage(1); +} + +$do_time = !isset($args['c']); + +// First make sure our file is consistently formatted with only one \t delimiting each field +$out = []; +$retval = null; +exec("sed -in 's/\t\+/\t/g' " . escapeshellarg($filename), $out, $retval); +if ($retval !== 0) { + usage(1); +} + +$handle = fopen($filename, 'r'); + +if ($handle === false) { + echo "Unable to open $filename \n\n"; + usage(1); +} + +// Loop till we find TRACE START +while ($l = fgets($handle)) { + if (strpos($l, "TRACE START") === 0) { + break; + } +} + +const SCALE_FACTOR = 1000000; +$stacks = []; +$current_stack = []; +$was_exit = false; +$prev_start_time = 0; + +if ($do_time) { + // Weight counts by duration + // Xdebug trace time indices have 6 sigfigs of precision + // We have a perfect trace, but let's instead pretend that + // this was collected by sampling at 10^6 Hz + // then each millionth of a second this stack took to execute is 1 count + while ($l = fgets($handle)) { + if (isEOTrace($l)) { + break; + } + + $parts = explode("\t", $l); + list($level, $fn_no, $is_exit, $time) = $parts; + + if ($is_exit) { + if (empty($current_stack)) { + echo "[WARNING] Found function exit without corresponding entrance. Discarding line. Check your input.\n"; + continue; + } + + addCurrentStackToStacks($current_stack, $time - $prev_start_time, $stacks); + array_pop($current_stack); + } else { + $func_name = $parts[5]; + + if (!empty($current_stack)) { + addCurrentStackToStacks($current_stack, $time - $prev_start_time, $stacks); + } + + $current_stack[] = $func_name; + } + $prev_start_time = $time; + } +} else { + // Counts only + while ($l = fgets($handle)) { + if (isEOTrace($l)) { + break; + } + + $parts = explode("\t", $l); + list($level, $fn_no, $is_exit) = $parts; + + if ($is_exit === "1") { + if (!$was_exit) { + $collapsed = implode(";", $current_stack); + if (array_key_exists($collapsed, $stacks)) { + $stacks[$collapsed]++; + } else { + $stacks[$collapsed] = 1; + } + } + + array_pop($current_stack); + $was_exit = true; + } else { + $func_name = $parts[5]; + $current_stack[] = $func_name; + $was_exit = false; + } + } +} + +foreach ($stacks as $stack => $count) { + echo "$stack $count\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/stackcollapse.pl b/tests/benchmarks/_script/flamegraph/stackcollapse.pl new file mode 100755 index 00000000000..1e00c521368 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/stackcollapse.pl @@ -0,0 +1,109 @@ +#!/usr/bin/perl -w +# +# stackcollapse.pl collapse multiline stacks into single lines. +# +# Parses a multiline stack followed by a number on a separate line, and +# outputs a semicolon separated stack followed by a space and the number. +# If memory addresses (+0xd) are present, they are stripped, and resulting +# identical stacks are colased with their counts summed. +# +# USAGE: ./stackcollapse.pl infile > outfile +# +# Example input: +# +# unix`i86_mwait+0xd +# unix`cpu_idle_mwait+0xf1 +# unix`idle+0x114 +# unix`thread_start+0x8 +# 1641 +# +# Example output: +# +# unix`thread_start;unix`idle;unix`cpu_idle_mwait;unix`i86_mwait 1641 +# +# Input may contain many stacks, and can be generated using DTrace. The +# first few lines of input are skipped (see $headerlines). +# +# Copyright 2011 Joyent, Inc. All rights reserved. +# Copyright 2011 Brendan Gregg. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# 14-Aug-2011 Brendan Gregg Created this. + +use strict; + +my $headerlines = 3; # number of input lines to skip +my $includeoffset = 0; # include function offset (except leafs) +my %collapsed; + +sub remember_stack { + my ($stack, $count) = @_; + $collapsed{$stack} += $count; +} + +my $nr = 0; +my @stack; + +foreach (<>) { + next if $nr++ < $headerlines; + chomp; + + if (m/^\s*(\d+)+$/) { + my $count = $1; + my $joined = join(";", @stack); + + # trim leaf offset if these were retained: + $joined =~ s/\+[^+]*$// if $includeoffset; + + remember_stack($joined, $count); + @stack = (); + next; + } + + next if (m/^\s*$/); + + my $frame = $_; + $frame =~ s/^\s*//; + $frame =~ s/\+[^+]*$// unless $includeoffset; + + # Remove arguments from C++ function names: + $frame =~ s/(::.*)[(<].*/$1/; + + $frame = "-" if $frame eq ""; + + my @inline; + for (split /\->/, $frame) { + my $func = $_; + + # Strip out L and ; included in java stacks + $func =~ tr/\;/:/; + $func =~ s/^L//; + $func .= "_[i]" if scalar(@inline) > 0; #inlined + + push @inline, $func; + } + + unshift @stack, @inline; +} + +foreach my $k (sort { $a cmp $b } keys %collapsed) { + print "$k $collapsed{$k}\n"; +} diff --git a/tests/benchmarks/_script/flamegraph/test.sh b/tests/benchmarks/_script/flamegraph/test.sh new file mode 100755 index 00000000000..3592f351f10 --- /dev/null +++ b/tests/benchmarks/_script/flamegraph/test.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# +# test.sh - Check flame graph software vs test result files. +# +# This is used to detect regressions in the flame graph software. +# See record-test.sh, which refreshes these files after intended software +# changes. +# +# Currently only tests stackcollapse-perf.pl. + +set -euo pipefail +set -x +set -v + +# ToDo: add some form of --inline, and --inline --context tests. These are +# tricky since they use addr2line, whose output will vary based on the test +# system's binaries and symbol tables. +for opt in pid tid kernel jit all addrs; do + for testfile in test/*.txt ; do + echo testing $testfile : $opt + outfile=${testfile#*/} + outfile=test/results/${outfile%.txt}"-collapsed-${opt}.txt" + perl ./stackcollapse-perf.pl --"${opt}" "${testfile}" 2> /dev/null | diff -u - "${outfile}" + perl ./flamegraph.pl "${outfile}" > /dev/null + done +done diff --git a/tests/benchmarks/benchmark_helpers.sh b/tests/benchmarks/benchmark_helpers.sh index 0ff6b03ef35..1f15976b95f 100644 --- a/tests/benchmarks/benchmark_helpers.sh +++ b/tests/benchmarks/benchmark_helpers.sh @@ -7,15 +7,17 @@ set -eo pipefail # command-line parsing # -usage() { echo "usage: $(basename "$0") [--cli ] [--baseline-cli ] [--output-style