diff options
82 files changed, 1476 insertions, 687 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 916a64b673..9301a1edd6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -113,13 +113,15 @@ jobs: cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v4 - - uses: git-for-windows/setup-git-for-windows-sdk@v1 + - name: setup SDK + shell: powershell + run: ci/install-sdk.ps1 - name: build - shell: bash + shell: powershell env: HOME: ${{runner.workspace}} NO_PERL: 1 - run: . /etc/profile && ci/make-test-artifacts.sh artifacts + run: git-sdk/usr/bin/bash.exe -l -c 'ci/make-test-artifacts.sh artifacts' - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts @@ -147,10 +149,12 @@ jobs: - name: extract tracked files and build artifacts shell: bash run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz - - uses: git-for-windows/setup-git-for-windows-sdk@v1 + - name: setup SDK + shell: powershell + run: ci/install-sdk.ps1 - name: test - shell: bash - run: . /etc/profile && ci/run-test-slice.sh ${{matrix.nr}} 10 + shell: powershell + run: git-sdk/usr/bin/bash.exe -l -c 'ci/run-test-slice.sh ${{matrix.nr}} 10' - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != '' shell: bash diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4abfbc3e20..526ecfe030 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,11 @@ default: timeout: 2h +stages: + - build + - test + - analyze + workflow: rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" @@ -9,6 +14,8 @@ workflow: test:linux: image: $image + stage: test + needs: [ ] tags: - saas-linux-medium-amd64 variables: @@ -67,6 +74,8 @@ test:linux: test:osx: image: $image + stage: test + needs: [ ] tags: - saas-macos-medium-m1 variables: @@ -100,8 +109,42 @@ test:osx: - t/failed-test-artifacts when: on_failure +build:mingw64: + stage: build + tags: + - saas-windows-medium-amd64 + variables: + NO_PERL: 1 + before_script: + - ./ci/install-sdk.ps1 -directory "git-sdk" + script: + - git-sdk/usr/bin/bash.exe -l -c 'ci/make-test-artifacts.sh artifacts' + artifacts: + paths: + - artifacts + - git-sdk + +test:mingw64: + stage: test + tags: + - saas-windows-medium-amd64 + needs: + - job: "build:mingw64" + artifacts: true + before_script: + - git-sdk/usr/bin/bash.exe -l -c 'tar xf artifacts/artifacts.tar.gz' + - New-Item -Path .git/info -ItemType Directory + - New-Item .git/info/exclude -ItemType File -Value "/git-sdk" + script: + - git-sdk/usr/bin/bash.exe -l -c "ci/run-test-slice.sh $CI_NODE_INDEX $CI_NODE_TOTAL" + after_script: + - git-sdk/usr/bin/bash.exe -l -c 'ci/print-test-failures.sh' + parallel: 10 + test:fuzz-smoke-tests: image: ubuntu:latest + stage: test + needs: [ ] variables: CC: clang before_script: @@ -111,6 +154,8 @@ test:fuzz-smoke-tests: static-analysis: image: ubuntu:22.04 + stage: analyze + needs: [ ] variables: jobname: StaticAnalysis before_script: @@ -121,6 +166,8 @@ static-analysis: check-whitespace: image: ubuntu:latest + stage: analyze + needs: [ ] before_script: - ./ci/install-dependencies.sh # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged @@ -135,6 +182,8 @@ check-whitespace: check-style: image: ubuntu:latest + stage: analyze + needs: [ ] allow_failure: true variables: CC: clang @@ -153,6 +202,8 @@ check-style: documentation: image: ubuntu:latest + stage: analyze + needs: [ ] variables: jobname: Documentation before_script: diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index 0fecb8de27..ec05f45fb3 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -25,6 +25,17 @@ Performance, Internal Implementation, Development Support etc. allocation function given to it may fail to allocate and to deal with such an error. + * An extra worktree attached to a repository points at each other to + allow finding the repository from the worktree and vice versa + possible. Turn this linkage to relative paths. + + * Enable Windows-based CI in GitLab. + + * Commands that can also work outside Git have learned to take the + repository instance "repo" when we know we are in a repository, and + NULL when we are not, in a parameter. The uses of the_repository + variable in a few of them have been removed using the new calling + convention. Fixes since v2.47 ----------------- @@ -46,6 +57,22 @@ Fixes since v2.47 reference, which has been corrected. (merge c95547a394 ps/maintenance-start-crash-fix later to maint). + * Fail gracefully instead of crashing when attempting to write the + contents of a corrupt in-core index as a tree object. + (merge ecb5c4318c ps/cache-tree-w-broken-index-entry later to maint). + + * A "git fetch" from the superproject going down to a submodule used + a wrong remote when the default remote names are set differently + between them. + (merge 0c1a9987da db/submodule-fetch-with-remote-name-fix later to maint). + + * Fixes compile time warnings with 64-bit MSVC. + (merge 386d372031 sk/msvc-warnings later to maint). + + * Teaches 'shortlog' to explicitly use SHA-1 when operating outside + of a repository. + (merge b33001645e wm/shortlog-hash later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 66893a14d0 ps/leakfixes-part-8 later to maint). (merge 1164e270b5 jk/output-prefix-cleanup later to maint). @@ -58,3 +85,6 @@ Fixes since v2.47 (merge b8139c8f4e kh/checkout-ignore-other-docfix later to maint). (merge 6dab49b9fb tc/bundle-uri-leakfix later to maint). (merge f1ed39987b xx/protocol-v2-doc-markup-fix later to maint). + (merge 41869f7447 ak/typofixes later to maint). + (merge f1eea0b620 ak/typofix later to maint). + (merge dcd590a39d bf/t-readme-mention-reftable later to maint). diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index d8a8caa791..db17bc7fe2 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -412,13 +412,13 @@ Also notice that a real name is used in the `Signed-off-by` trailer. Please don't hide your real name. [[commit-trailers]] -If you like, you can put extra tags at the end: +If you like, you can put extra trailers at the end: . `Reported-by:` is used to credit someone who found the bug that the patch attempts to fix. . `Acked-by:` says that the person who is more familiar with the area the patch attempts to modify liked the patch. -. `Reviewed-by:`, unlike the other tags, can only be offered by the +. `Reviewed-by:`, unlike the other trailers, can only be offered by the reviewers themselves when they are completely satisfied with the patch after a detailed analysis. . `Tested-by:` is used to indicate that the person applied the patch @@ -436,7 +436,7 @@ While you can also create your own trailer if the situation warrants it, we encourage you to instead use one of the common trailers in this project highlighted above. -Only capitalize the very first letter of tags, i.e. favor +Only capitalize the very first letter of the trailer, i.e. favor "Signed-off-by" over "Signed-Off-By" and "Acked-by:" over "Acked-By". [[git-tools]] diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 2a240f53ba..70437c815f 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -157,7 +157,7 @@ will reestablish the connection. If multiple linked worktrees are moved, running `repair` from any worktree with each tree's new `<path>` as an argument, will reestablish the connection to all the specified paths. + -If both the main worktree and linked worktrees have been moved manually, +If both the main worktree and linked worktrees have been moved or copied manually, then running `repair` in the main worktree and specifying the new `<path>` of each linked worktree will reestablish all connections in both directions. @@ -3909,6 +3909,7 @@ $(UNIT_TEST_DIR)/clar-decls.h: $(patsubst %,$(UNIT_TEST_DIR)/%.c,$(CLAR_TEST_SUI done >$@ $(UNIT_TEST_DIR)/clar.suite: $(UNIT_TEST_DIR)/clar-decls.h $(QUIET_GEN)awk -f $(UNIT_TEST_DIR)/clar-generate.awk $< >$(UNIT_TEST_DIR)/clar.suite +$(UNIT_TEST_DIR)/clar/clar.o: $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS): $(UNIT_TEST_DIR)/clar-decls.h $(CLAR_TEST_OBJS): EXTRA_CPPFLAGS = -I$(UNIT_TEST_DIR) $(CLAR_TEST_PROG): $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS) $(GITLIBS) GIT-LDFLAGS diff --git a/builtin/add.c b/builtin/add.c index 773b7224a4..7d35307792 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -385,7 +385,8 @@ int cmd_add(int argc, char *ps_matched = NULL; struct lock_file lock_file = LOCK_INIT; - repo_config(repo, add_config, NULL); + if (repo) + repo_config(repo, add_config, NULL); argc = parse_options(argc, argv, prefix, builtin_add_options, builtin_add_usage, PARSE_OPT_KEEP_ARGV0); diff --git a/builtin/annotate.c b/builtin/annotate.c index 03413c7df8..7f754f2309 100644 --- a/builtin/annotate.c +++ b/builtin/annotate.c @@ -4,7 +4,6 @@ * Copyright (C) 2006 Ryan Anderson */ -#define USE_THE_REPOSITORY_VARIABLE #include "git-compat-util.h" #include "builtin.h" #include "strvec.h" @@ -12,7 +11,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { struct strvec args = STRVEC_INIT; const char **args_copy; @@ -29,7 +28,7 @@ int cmd_annotate(int argc, CALLOC_ARRAY(args_copy, args.nr + 1); COPY_ARRAY(args_copy, args.v, args.nr); - ret = cmd_blame(args.nr, args_copy, prefix, the_repository); + ret = cmd_blame(args.nr, args_copy, prefix, repo); strvec_clear(&args); free(args_copy); diff --git a/builtin/archive.c b/builtin/archive.c index dc926d1a3d..13ea7308c8 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -2,7 +2,6 @@ * Copyright (c) 2006 Franck Bui-Huu * Copyright (c) 2006 Rene Scharfe */ -#define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "archive.h" #include "gettext.h" @@ -79,7 +78,7 @@ static int run_remote_archiver(int argc, const char **argv, int cmd_archive(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { const char *exec = "git-upload-archive"; char *output = NULL; @@ -110,7 +109,7 @@ int cmd_archive(int argc, setvbuf(stderr, NULL, _IOLBF, BUFSIZ); - ret = write_archive(argc, argv, prefix, the_repository, output, 0); + ret = write_archive(argc, argv, prefix, repo, output, 0); out: free(output); diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 3ed5c46078..c86b75d981 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -407,6 +407,18 @@ int cmd_shortlog(int argc, struct parse_opt_ctx_t ctx; + /* + * NEEDSWORK: Later on we'll call parse_revision_opt which relies on + * the hash algorithm being set but since we are operating outside of a + * Git repository we cannot determine one. This is only needed because + * parse_revision_opt expects hexsz for --abbrev which is irrelevant + * for shortlog outside of a git repository. For now explicitly set + * SHA1, but ideally the parsing machinery would be split between + * git/nongit so that we do not have to do this. + */ + if (nongit && !the_hash_algo) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + git_config(git_default_config, NULL); shortlog_init(&log); repo_init_revisions(the_repository, &rev, prefix); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index dc89488a7d..b6b5f1ebde 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -2333,7 +2333,14 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, strvec_pushf(&cp.args, "--depth=%d", depth); if (oid) { char *hex = oid_to_hex(oid); - char *remote = get_default_remote(); + char *remote; + int code; + + code = get_default_remote_submodule(module_path, &remote); + if (code) { + child_process_clear(&cp); + return code; + } strvec_pushl(&cp.args, remote, hex, NULL); free(remote); diff --git a/builtin/worktree.c b/builtin/worktree.c index fc31d072a6..dae63dedf4 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -414,7 +414,8 @@ static int add_worktree(const char *path, const char *refname, const struct add_opts *opts) { struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; - struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT; + struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT; + struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT; const char *name; struct strvec child_env = STRVEC_INIT; unsigned int counter = 0; @@ -490,11 +491,10 @@ static int add_worktree(const char *path, const char *refname, strbuf_reset(&sb); strbuf_addf(&sb, "%s/gitdir", sb_repo.buf); - strbuf_realpath(&realpath, sb_git.buf, 1); - write_file(sb.buf, "%s", realpath.buf); - strbuf_realpath(&realpath, repo_get_common_dir(the_repository), 1); - write_file(sb_git.buf, "gitdir: %s/worktrees/%s", - realpath.buf, name); + strbuf_realpath(&sb_path_realpath, path, 1); + strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1); + write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp)); + write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp)); strbuf_reset(&sb); strbuf_addf(&sb, "%s/commondir", sb_repo.buf); write_file(sb.buf, "../.."); @@ -578,11 +578,13 @@ done: strvec_clear(&child_env); strbuf_release(&sb); + strbuf_release(&sb_tmp); strbuf_release(&symref); strbuf_release(&sb_repo); + strbuf_release(&sb_repo_realpath); strbuf_release(&sb_git); + strbuf_release(&sb_path_realpath); strbuf_release(&sb_name); - strbuf_release(&realpath); free_worktree(wt); return ret; } diff --git a/cache-tree.c b/cache-tree.c index b482167a69..c595e86120 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "git-compat-util.h" +#include "gettext.h" #include "hex.h" #include "lockfile.h" #include "tree.h" @@ -865,15 +866,15 @@ int cache_tree_matches_traversal(struct cache_tree *root, return 0; } -static void verify_one_sparse(struct index_state *istate, - struct strbuf *path, - int pos) +static int verify_one_sparse(struct index_state *istate, + struct strbuf *path, + int pos) { struct cache_entry *ce = istate->cache[pos]; - if (!S_ISSPARSEDIR(ce->ce_mode)) - BUG("directory '%s' is present in index, but not sparse", - path->buf); + return error(_("directory '%s' is present in index, but not sparse"), + path->buf); + return 0; } /* @@ -882,6 +883,7 @@ static void verify_one_sparse(struct index_state *istate, * 1 - Restart verification - a call to ensure_full_index() freed the cache * tree that is being verified and verification needs to be restarted from * the new toplevel cache tree. + * -1 - Verification failed. */ static int verify_one(struct repository *r, struct index_state *istate, @@ -891,18 +893,23 @@ static int verify_one(struct repository *r, int i, pos, len = path->len; struct strbuf tree_buf = STRBUF_INIT; struct object_id new_oid; + int ret; for (i = 0; i < it->subtree_nr; i++) { strbuf_addf(path, "%s/", it->down[i]->name); - if (verify_one(r, istate, it->down[i]->cache_tree, path)) - return 1; + ret = verify_one(r, istate, it->down[i]->cache_tree, path); + if (ret) + goto out; + strbuf_setlen(path, len); } if (it->entry_count < 0 || /* no verification on tests (t7003) that replace trees */ - lookup_replace_object(r, &it->oid) != &it->oid) - return 0; + lookup_replace_object(r, &it->oid) != &it->oid) { + ret = 0; + goto out; + } if (path->len) { /* @@ -912,12 +919,14 @@ static int verify_one(struct repository *r, */ int is_sparse = istate->sparse_index; pos = index_name_pos(istate, path->buf, path->len); - if (is_sparse && !istate->sparse_index) - return 1; + if (is_sparse && !istate->sparse_index) { + ret = 1; + goto out; + } if (pos >= 0) { - verify_one_sparse(istate, path, pos); - return 0; + ret = verify_one_sparse(istate, path, pos); + goto out; } pos = -pos - 1; @@ -925,6 +934,11 @@ static int verify_one(struct repository *r, pos = 0; } + if (it->entry_count + pos > istate->cache_nr) { + ret = error(_("corrupted cache-tree has entries not present in index")); + goto out; + } + i = 0; while (i < it->entry_count) { struct cache_entry *ce = istate->cache[pos + i]; @@ -935,16 +949,23 @@ static int verify_one(struct repository *r, unsigned mode; int entlen; - if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE)) - BUG("%s with flags 0x%x should not be in cache-tree", - ce->name, ce->ce_flags); + if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE)) { + ret = error(_("%s with flags 0x%x should not be in cache-tree"), + ce->name, ce->ce_flags); + goto out; + } + name = ce->name + path->len; slash = strchr(name, '/'); if (slash) { entlen = slash - name; + sub = find_subtree(it, ce->name + path->len, entlen, 0); - if (!sub || sub->cache_tree->entry_count < 0) - BUG("bad subtree '%.*s'", entlen, name); + if (!sub || sub->cache_tree->entry_count < 0) { + ret = error(_("bad subtree '%.*s'"), entlen, name); + goto out; + } + oid = &sub->cache_tree->oid; mode = S_IFDIR; i += sub->cache_tree->entry_count; @@ -957,27 +978,50 @@ static int verify_one(struct repository *r, strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0'); strbuf_add(&tree_buf, oid->hash, r->hash_algo->rawsz); } + hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, OBJ_TREE, &new_oid); - if (!oideq(&new_oid, &it->oid)) - BUG("cache-tree for path %.*s does not match. " - "Expected %s got %s", len, path->buf, - oid_to_hex(&new_oid), oid_to_hex(&it->oid)); + + if (!oideq(&new_oid, &it->oid)) { + ret = error(_("cache-tree for path %.*s does not match. " + "Expected %s got %s"), len, path->buf, + oid_to_hex(&new_oid), oid_to_hex(&it->oid)); + goto out; + } + + ret = 0; +out: strbuf_setlen(path, len); strbuf_release(&tree_buf); - return 0; + return ret; } -void cache_tree_verify(struct repository *r, struct index_state *istate) +int cache_tree_verify(struct repository *r, struct index_state *istate) { struct strbuf path = STRBUF_INIT; + int ret; - if (!istate->cache_tree) - return; - if (verify_one(r, istate, istate->cache_tree, &path)) { + if (!istate->cache_tree) { + ret = 0; + goto out; + } + + ret = verify_one(r, istate, istate->cache_tree, &path); + if (ret < 0) + goto out; + if (ret > 0) { strbuf_reset(&path); - if (verify_one(r, istate, istate->cache_tree, &path)) + + ret = verify_one(r, istate, istate->cache_tree, &path); + if (ret < 0) + goto out; + if (ret > 0) BUG("ensure_full_index() called twice while verifying cache tree"); } + + ret = 0; + +out: strbuf_release(&path); + return ret; } diff --git a/cache-tree.h b/cache-tree.h index faae88be63..b82c4963e7 100644 --- a/cache-tree.h +++ b/cache-tree.h @@ -33,7 +33,7 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size); int cache_tree_fully_valid(struct cache_tree *); int cache_tree_update(struct index_state *, int); -void cache_tree_verify(struct repository *, struct index_state *); +int cache_tree_verify(struct repository *, struct index_state *); /* bitmasks to write_index_as_tree flags */ #define WRITE_TREE_MISSING_OK 1 diff --git a/ci/install-sdk.ps1 b/ci/install-sdk.ps1 new file mode 100755 index 0000000000..66f24838a4 --- /dev/null +++ b/ci/install-sdk.ps1 @@ -0,0 +1,12 @@ +param( + [string]$directory='git-sdk', + [string]$url='https://github.com/git-for-windows/git-sdk-64/releases/download/ci-artifacts/git-sdk-x86_64-minimal.zip' +) + +Invoke-WebRequest "$url" -OutFile git-sdk.zip +Expand-Archive -LiteralPath git-sdk.zip -DestinationPath "$directory" +Remove-Item -Path git-sdk.zip + +New-Item -Path .git/info -ItemType Directory -Force +New-Item -Path .git/info/exclude -ItemType File -Force +Add-Content -Path .git/info/exclude -Value "/$directory" @@ -250,8 +250,13 @@ then CI_TYPE=gitlab-ci CI_BRANCH="$CI_COMMIT_REF_NAME" CI_COMMIT="$CI_COMMIT_SHA" - case "$CI_JOB_IMAGE" in - macos-*) + + case "$OS,$CI_JOB_IMAGE" in + Windows_NT,*) + CI_OS_NAME=windows + JOBS=$NUMBER_OF_PROCESSORS + ;; + *,macos-*) # GitLab CI has Python installed via multiple package managers, # most notably via asdf and Homebrew. Ensure that our builds # pick up the Homebrew one by prepending it to our PATH as the @@ -259,9 +264,12 @@ then export PATH="$(brew --prefix)/bin:$PATH" CI_OS_NAME=osx + JOBS=$(nproc) + ;; + *,alpine:*|*,fedora:*|*,ubuntu:*) + CI_OS_NAME=linux + JOBS=$(nproc) ;; - alpine:*|fedora:*|ubuntu:*) - CI_OS_NAME=linux;; *) echo "Could not identify OS image" >&2 env >&2 @@ -272,6 +280,7 @@ then CI_JOB_ID="$CI_JOB_ID" CC="${CC_PACKAGE:-${CC:-gcc}}" DONT_SKIP_TAGS=t + handle_failed_tests () { create_failed_test_artifacts return 1 @@ -280,7 +289,6 @@ then cache_dir="$HOME/none" distro=$(echo "$CI_JOB_IMAGE" | tr : -) - JOBS=$(nproc) else echo "Could not identify CI type" >&2 env >&2 diff --git a/compat/compiler.h b/compat/compiler.h index e9ad9db84f..e12e426404 100644 --- a/compat/compiler.h +++ b/compat/compiler.h @@ -9,7 +9,7 @@ static inline void get_compiler_info(struct strbuf *info) { - int len = info->len; + size_t len = info->len; #ifdef __clang__ strbuf_addf(info, "clang: %s\n", __clang_version__); #elif defined(__GNUC__) @@ -27,7 +27,7 @@ static inline void get_compiler_info(struct strbuf *info) static inline void get_libc_info(struct strbuf *info) { - int len = info->len; + size_t len = info->len; #ifdef __GLIBC__ strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version()); diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c index 80e092b511..9a6efc9bea 100644 --- a/compat/fsmonitor/fsm-listen-win32.c +++ b/compat/fsmonitor/fsm-listen-win32.c @@ -431,9 +431,9 @@ static int recv_rdcw_watch(struct one_watch *watch) * but I observed ERROR_ACCESS_DENIED (0x05) errors during * testing. * - * Note that we only get notificaiton events for events + * Note that we only get notification events for events * *within* the directory, not *on* the directory itself. - * (These might be properies of the parent directory, for + * (These might be properties of the parent directory, for * example). * * NEEDSWORK: We might try to check for the deleted directory diff --git a/compat/mingw.c b/compat/mingw.c index 0e851ecae2..0ff550cef3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -782,7 +782,7 @@ static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts) */ static int has_valid_directory_prefix(wchar_t *wfilename) { - int n = wcslen(wfilename); + size_t n = wcslen(wfilename); while (n > 0) { wchar_t c = wfilename[--n]; @@ -891,7 +891,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) */ static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { - int namelen; + size_t namelen; char alt_name[PATH_MAX]; if (!do_lstat(follow, file_name, buf)) @@ -1274,7 +1274,8 @@ static const char *parse_interpreter(const char *cmd) { static char buf[100]; char *p, *opt; - int n, fd; + ssize_t n; /* read() can return negative values */ + int fd; /* don't even try a .exe */ n = strlen(cmd); @@ -1339,7 +1340,7 @@ static char *path_lookup(const char *cmd, int exe_only) { const char *path; char *prog = NULL; - int len = strlen(cmd); + size_t len = strlen(cmd); int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe"); if (strpbrk(cmd, "/\\")) @@ -1956,7 +1957,7 @@ char *mingw_getenv(const char *name) #define GETENV_MAX_RETAIN 64 static char *values[GETENV_MAX_RETAIN]; static int value_counter; - int len_key, len_value; + size_t len_key, len_value; wchar_t *w_key; char *value; wchar_t w_value[32768]; @@ -1968,7 +1969,8 @@ char *mingw_getenv(const char *name) /* We cannot use xcalloc() here because that uses getenv() itself */ w_key = calloc(len_key, sizeof(wchar_t)); if (!w_key) - die("Out of memory, (tried to allocate %u wchar_t's)", len_key); + die("Out of memory, (tried to allocate %"PRIuMAX" wchar_t's)", + (uintmax_t)len_key); xutftowcs(w_key, name, len_key); /* GetEnvironmentVariableW() only sets the last error upon failure */ SetLastError(ERROR_SUCCESS); @@ -1983,7 +1985,8 @@ char *mingw_getenv(const char *name) /* We cannot use xcalloc() here because that uses getenv() itself */ value = calloc(len_value, sizeof(char)); if (!value) - die("Out of memory, (tried to allocate %u bytes)", len_value); + die("Out of memory, (tried to allocate %"PRIuMAX" bytes)", + (uintmax_t)len_value); xwcstoutf(value, w_value, len_value); /* @@ -2001,7 +2004,7 @@ char *mingw_getenv(const char *name) int mingw_putenv(const char *namevalue) { - int size; + size_t size; wchar_t *wide, *equal; BOOL result; @@ -2011,7 +2014,8 @@ int mingw_putenv(const char *namevalue) size = strlen(namevalue) * 2 + 1; wide = calloc(size, sizeof(wchar_t)); if (!wide) - die("Out of memory, (tried to allocate %u wchar_t's)", size); + die("Out of memory, (tried to allocate %" PRIuMAX " wchar_t's)", + (uintmax_t)size); xutftowcs(wide, namevalue, size); equal = wcschr(wide, L'='); if (!equal) @@ -3085,7 +3089,8 @@ static void maybe_redirect_std_handles(void) */ int wmain(int argc, const wchar_t **wargv) { - int i, maxlen, exit_status; + int i, exit_status; + size_t maxlen; char *buffer, **save; const char **argv; diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index e92be5741d..2eeec82f40 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -292,7 +292,7 @@ compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); concerned. If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match - and all groups is stroed in REGS. (For the "_2" variants, the offsets are + and all groups are stored in REGS. (For the "_2" variants, the offsets are computed relative to the concatenation, not relative to the individual strings.) diff --git a/compat/simple-ipc/ipc-unix-socket.c b/compat/simple-ipc/ipc-unix-socket.c index 57d919c6b4..7db3b2a897 100644 --- a/compat/simple-ipc/ipc-unix-socket.c +++ b/compat/simple-ipc/ipc-unix-socket.c @@ -713,7 +713,7 @@ static int accept_thread__wait_for_connection( * Block SIGPIPE in this thread for the life of the thread. This * avoids any stray SIGPIPE signals when closing pipe fds under * extremely heavy loads (such as when the fifo queue is full and we - * drop incomming connections). + * drop incoming connections). */ static void *accept_thread_proc(void *_accept_thread_data) { diff --git a/compat/vcbuild/include/unistd.h b/compat/vcbuild/include/unistd.h index 3a959d124c..a261a925b7 100644 --- a/compat/vcbuild/include/unistd.h +++ b/compat/vcbuild/include/unistd.h @@ -14,7 +14,11 @@ typedef _mode_t mode_t; #ifndef _SSIZE_T_ #define _SSIZE_T_ +#ifdef _WIN64 +typedef __int64 _ssize_t; +#else typedef long _ssize_t; +#endif /* _WIN64 */ #ifndef _OFF_T_ #define _OFF_T_ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 60a22d619a..3d4dff3185 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3296,7 +3296,7 @@ __gitcomp_directories () # i.e. which are *already* part of their # sparse-checkout. Thus, normal file and directory # completion is always useless for "git - # sparse-checkout add" and is also probelmatic for + # sparse-checkout add" and is also problematic for # "git sparse-checkout set" unless using it to # strictly narrow the checkout. COMPREPLY=( "" ) @@ -3698,7 +3698,7 @@ _git_worktree () # Here we are not completing an --option, it's either the # path or a ref. case "$prev" in - -b|-B) # Complete refs for branch to be created/reseted. + -b|-B) # Complete refs for branch to be created/reset. __git_complete_refs ;; -*) # The previous word is an -o|--option without an diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 5dab3f506c..15ae86db1b 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -946,7 +946,7 @@ cmd_split () { rev=$(git rev-parse -q --verify "$1^{commit}") || die "fatal: '$1' does not refer to a commit" else - die "fatal: you must provide exactly one revision, and optionnally a repository. Got: '$*'" + die "fatal: you must provide exactly one revision, and optionally a repository. Got: '$*'" fi repository="" if test "$#" = 2 diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index c3bd2a58b9..3c6103f6d2 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -47,7 +47,7 @@ last_commit_subject () { # pre-2.32.0 versions of 'git subtree' would write the hash of the tag # (sub1 below), instead of the commit (sub1^{commit}) in the # "git-subtree-split" trailer. -# We immitate this behaviour below using a replace ref. +# We imitate this behaviour below using a replace ref. # This function creates 3 repositories: # - $1 # - $1-sub (added as subtree "sub" in $1) @@ -444,6 +444,7 @@ static int handle_alias(int *argcp, const char ***argv) static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct repository *repo) { int status, help; + int no_repo = 1; struct stat st; const char *prefix; int run_setup = (p->option & (RUN_SETUP | RUN_SETUP_GENTLY)); @@ -455,9 +456,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct if (run_setup & RUN_SETUP) { prefix = setup_git_directory(); + no_repo = 0; } else if (run_setup & RUN_SETUP_GENTLY) { - int nongit_ok; - prefix = setup_git_directory_gently(&nongit_ok); + prefix = setup_git_directory_gently(&no_repo); } else { prefix = NULL; } @@ -480,7 +481,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct trace2_cmd_name(p->cmd); validate_cache_entries(repo->index); - status = p->fn(argc, argv, prefix, (p->option & RUN_SETUP)? repo : NULL); + status = p->fn(argc, argv, prefix, no_repo ? NULL : repo); validate_cache_entries(repo->index); if (status) diff --git a/read-cache.c b/read-cache.c index 1148a55873..01d0b3ad22 100644 --- a/read-cache.c +++ b/read-cache.c @@ -3335,8 +3335,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, int new_shared_index, ret, test_split_index_env; struct split_index *si = istate->split_index; - if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0)) - cache_tree_verify(the_repository, istate); + if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0) && + cache_tree_verify(the_repository, istate) < 0) + return -1; if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) { if (flags & COMMIT_LOCK) diff --git a/ref-filter.c b/ref-filter.c index dd195007ce..84c6036107 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -3244,21 +3244,40 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int return ret; } +struct ref_sorting { + struct ref_sorting *next; + int atom; /* index into used_atom array (internal) */ + enum ref_sorting_order sort_flags; +}; + static inline int can_do_iterative_format(struct ref_filter *filter, struct ref_sorting *sorting, struct ref_format *format) { /* + * Reference backends sort patterns lexicographically by refname, so if + * the sorting options ask for exactly that we are able to do iterative + * formatting. + * + * Note that we do not have to worry about multiple name patterns, + * either. Those get sorted and deduplicated eventually in + * `refs_for_each_fullref_in_prefixes()`, so we return names in the + * correct ordering here, too. + */ + if (sorting && (sorting->next || + sorting->sort_flags || + used_atom[sorting->atom].atom_type != ATOM_REFNAME)) + return 0; + + /* * Filtering & formatting results within a single ref iteration * callback is not compatible with options that require * post-processing a filtered ref_array. These include: * - filtering on reachability - * - sorting the filtered results * - including ahead-behind information in the formatted output */ return !(filter->reachable_from || filter->unreachable_from || - sorting || format->bases.nr || format->is_base_tips.nr); } @@ -3316,12 +3335,6 @@ static int memcasecmp(const void *vs1, const void *vs2, size_t n) return 0; } -struct ref_sorting { - struct ref_sorting *next; - int atom; /* index into used_atom array (internal) */ - enum ref_sorting_order sort_flags; -}; - static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b) { struct atom_value *va, *vb; diff --git a/reftable/basics.c b/reftable/basics.c index 9a949e5cf8..bc4fcc9144 100644 --- a/reftable/basics.c +++ b/reftable/basics.c @@ -9,6 +9,7 @@ https://developers.google.com/open-source/licenses/bsd #define REFTABLE_ALLOW_BANNED_ALLOCATORS #include "basics.h" #include "reftable-basics.h" +#include "reftable-error.h" static void *(*reftable_malloc_ptr)(size_t sz); static void *(*reftable_realloc_ptr)(void *, size_t); @@ -69,6 +70,79 @@ void reftable_set_alloc(void *(*malloc)(size_t), reftable_free_ptr = free; } +void reftable_buf_init(struct reftable_buf *buf) +{ + struct reftable_buf empty = REFTABLE_BUF_INIT; + *buf = empty; +} + +void reftable_buf_release(struct reftable_buf *buf) +{ + reftable_free(buf->buf); + reftable_buf_init(buf); +} + +void reftable_buf_reset(struct reftable_buf *buf) +{ + if (buf->alloc) { + buf->len = 0; + buf->buf[0] = '\0'; + } +} + +int reftable_buf_setlen(struct reftable_buf *buf, size_t len) +{ + if (len > buf->len) + return -1; + if (len == buf->len) + return 0; + buf->buf[len] = '\0'; + buf->len = len; + return 0; +} + +int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b) +{ + size_t len = a->len < b->len ? a->len : b->len; + if (len) { + int cmp = memcmp(a->buf, b->buf, len); + if (cmp) + return cmp; + } + return a->len < b->len ? -1 : a->len != b->len; +} + +int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len) +{ + size_t newlen = buf->len + len; + + if (newlen + 1 > buf->alloc) { + char *reallocated = buf->buf; + REFTABLE_ALLOC_GROW(reallocated, newlen + 1, buf->alloc); + if (!reallocated) + return REFTABLE_OUT_OF_MEMORY_ERROR; + buf->buf = reallocated; + } + + memcpy(buf->buf + buf->len, data, len); + buf->buf[newlen] = '\0'; + buf->len = newlen; + + return 0; +} + +int reftable_buf_addstr(struct reftable_buf *buf, const char *s) +{ + return reftable_buf_add(buf, s, strlen(s)); +} + +char *reftable_buf_detach(struct reftable_buf *buf) +{ + char *result = buf->buf; + reftable_buf_init(buf); + return result; +} + void put_be24(uint8_t *out, uint32_t i) { out[0] = (uint8_t)((i >> 16) & 0xff); @@ -186,7 +260,7 @@ int names_equal(const char **a, const char **b) return a[i] == b[i]; } -int common_prefix_size(struct strbuf *a, struct strbuf *b) +int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b) { int p = 0; for (; p < a->len && p < b->len; p++) { diff --git a/reftable/basics.h b/reftable/basics.h index 4c9ef0fe6c..7aa46d7c30 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -16,6 +16,64 @@ https://developers.google.com/open-source/licenses/bsd #include "system.h" #include "reftable-basics.h" +struct reftable_buf { + size_t alloc; + size_t len; + char *buf; +}; +#define REFTABLE_BUF_INIT { 0 } + +/* + * Initialize the buffer such that it is ready for use. This is equivalent to + * using REFTABLE_BUF_INIT for stack-allocated variables. + */ +void reftable_buf_init(struct reftable_buf *buf); + +/* + * Release memory associated with the buffer. The buffer is reinitialized such + * that it can be reused for subsequent operations. + */ +void reftable_buf_release(struct reftable_buf *buf); + +/* + * Reset the buffer such that it is effectively empty, without releasing the + * memory that this structure holds on to. This is equivalent to calling + * `reftable_buf_setlen(buf, 0)`. + */ +void reftable_buf_reset(struct reftable_buf *buf); + +/* + * Trim the buffer to a shorter length by updating the `len` member and writing + * a NUL byte to `buf[len]`. Returns 0 on success, -1 when `len` points outside + * of the array. + */ +int reftable_buf_setlen(struct reftable_buf *buf, size_t len); + +/* + * Lexicographically compare the two buffers. Returns 0 when both buffers have + * the same contents, -1 when `a` is lexicographically smaller than `b`, and 1 + * otherwise. + */ +int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b); + +/* + * Append `len` bytes from `data` to the buffer. This function works with + * arbitrary byte sequences, including ones that contain embedded NUL + * characters. As such, we use `void *` as input type. Returns 0 on success, + * REFTABLE_OUT_OF_MEMORY_ERROR on allocation failure. + */ +int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len); + +/* Equivalent to `reftable_buf_add(buf, s, strlen(s))`. */ +int reftable_buf_addstr(struct reftable_buf *buf, const char *s); + +/* + * Detach the buffer from the structure such that the underlying memory is now + * owned by the caller. The buffer is reinitialized such that it can be reused + * for subsequent operations. + */ +char *reftable_buf_detach(struct reftable_buf *buf); + /* Bigendian en/decoding of integers */ void put_be24(uint8_t *out, uint32_t i); @@ -88,8 +146,7 @@ char *reftable_strdup(const char *str); #endif /* Find the longest shared prefix size of `a` and `b` */ -struct strbuf; -int common_prefix_size(struct strbuf *a, struct strbuf *b); +int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b); int hash_size(uint32_t id); diff --git a/reftable/block.c b/reftable/block.c index 8d41a2f99e..f5b432566a 100644 --- a/reftable/block.c +++ b/reftable/block.c @@ -38,9 +38,11 @@ int footer_size(int version) } static int block_writer_register_restart(struct block_writer *w, int n, - int is_restart, struct strbuf *key) + int is_restart, struct reftable_buf *key) { - int rlen = w->restart_len; + int rlen, err; + + rlen = w->restart_len; if (rlen >= MAX_RESTARTS) { is_restart = 0; } @@ -59,8 +61,11 @@ static int block_writer_register_restart(struct block_writer *w, int n, w->next += n; - strbuf_reset(&w->last_key); - strbuf_addbuf(&w->last_key, key); + reftable_buf_reset(&w->last_key); + err = reftable_buf_add(&w->last_key, key->buf, key->len); + if (err < 0) + return err; + w->entries++; return 0; } @@ -98,8 +103,8 @@ uint8_t block_writer_type(struct block_writer *bw) empty key. */ int block_writer_add(struct block_writer *w, struct reftable_record *rec) { - struct strbuf empty = STRBUF_INIT; - struct strbuf last = + struct reftable_buf empty = REFTABLE_BUF_INIT; + struct reftable_buf last = w->entries % w->restart_interval == 0 ? empty : w->last_key; struct string_view out = { .buf = w->buf + w->next, @@ -109,11 +114,14 @@ int block_writer_add(struct block_writer *w, struct reftable_record *rec) struct string_view start = out; int is_restart = 0; - struct strbuf key = STRBUF_INIT; + struct reftable_buf key = REFTABLE_BUF_INIT; int n = 0; - int err = -1; + int err; + + err = reftable_record_key(rec, &key); + if (err < 0) + goto done; - reftable_record_key(rec, &key); if (!key.len) { err = REFTABLE_API_ERROR; goto done; @@ -121,19 +129,23 @@ int block_writer_add(struct block_writer *w, struct reftable_record *rec) n = reftable_encode_key(&is_restart, out, last, key, reftable_record_val_type(rec)); - if (n < 0) + if (n < 0) { + err = -1; goto done; + } string_view_consume(&out, n); n = reftable_record_encode(rec, out, w->hash_size); - if (n < 0) + if (n < 0) { + err = -1; goto done; + } string_view_consume(&out, n); err = block_writer_register_restart(w, start.len - out.len, is_restart, &key); done: - strbuf_release(&key); + reftable_buf_release(&key); return err; } @@ -325,7 +337,7 @@ uint8_t block_reader_type(const struct block_reader *r) return r->block.data[r->header_off]; } -int block_reader_first_key(const struct block_reader *br, struct strbuf *key) +int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key) { int off = br->header_off + 4, n; struct string_view in = { @@ -334,7 +346,7 @@ int block_reader_first_key(const struct block_reader *br, struct strbuf *key) }; uint8_t extra = 0; - strbuf_reset(key); + reftable_buf_reset(key); n = reftable_decode_key(key, &extra, in); if (n < 0) @@ -355,13 +367,13 @@ void block_iter_seek_start(struct block_iter *it, const struct block_reader *br) it->block = br->block.data; it->block_len = br->block_len; it->hash_size = br->hash_size; - strbuf_reset(&it->last_key); + reftable_buf_reset(&it->last_key); it->next_off = br->header_off + 4; } struct restart_needle_less_args { int error; - struct strbuf needle; + struct reftable_buf needle; const struct block_reader *reader; }; @@ -433,7 +445,7 @@ int block_iter_next(struct block_iter *it, struct reftable_record *rec) void block_iter_reset(struct block_iter *it) { - strbuf_reset(&it->last_key); + reftable_buf_reset(&it->last_key); it->next_off = 0; it->block = NULL; it->block_len = 0; @@ -442,12 +454,12 @@ void block_iter_reset(struct block_iter *it) void block_iter_close(struct block_iter *it) { - strbuf_release(&it->last_key); - strbuf_release(&it->scratch); + reftable_buf_release(&it->last_key); + reftable_buf_release(&it->scratch); } int block_iter_seek_key(struct block_iter *it, const struct block_reader *br, - struct strbuf *want) + struct reftable_buf *want) { struct restart_needle_less_args args = { .needle = *want, @@ -522,6 +534,10 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br, goto done; } + err = reftable_record_key(&rec, &it->last_key); + if (err < 0) + goto done; + /* * Check whether the current key is greater or equal to the * sought-after key. In case it is greater we know that the @@ -536,8 +552,7 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br, * to `last_key` now, and naturally all keys share a prefix * with themselves. */ - reftable_record_key(&rec, &it->last_key); - if (strbuf_cmp(&it->last_key, want) >= 0) { + if (reftable_buf_cmp(&it->last_key, want) >= 0) { it->next_off = prev_off; goto done; } @@ -554,7 +569,7 @@ void block_writer_release(struct block_writer *bw) REFTABLE_FREE_AND_NULL(bw->zstream); REFTABLE_FREE_AND_NULL(bw->restarts); REFTABLE_FREE_AND_NULL(bw->compressed); - strbuf_release(&bw->last_key); + reftable_buf_release(&bw->last_key); /* the block is not owned. */ } diff --git a/reftable/block.h b/reftable/block.h index 18d7ea0337..9a3effa513 100644 --- a/reftable/block.h +++ b/reftable/block.h @@ -38,7 +38,7 @@ struct block_writer { uint32_t restart_len; uint32_t restart_cap; - struct strbuf last_key; + struct reftable_buf last_key; int entries; }; @@ -98,7 +98,7 @@ void block_reader_release(struct block_reader *br); uint8_t block_reader_type(const struct block_reader *r); /* Decodes the first key in the block */ -int block_reader_first_key(const struct block_reader *br, struct strbuf *key); +int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key); /* Iterate over entries in a block */ struct block_iter { @@ -109,13 +109,13 @@ struct block_iter { int hash_size; /* key for last entry we read. */ - struct strbuf last_key; - struct strbuf scratch; + struct reftable_buf last_key; + struct reftable_buf scratch; }; #define BLOCK_ITER_INIT { \ - .last_key = STRBUF_INIT, \ - .scratch = STRBUF_INIT, \ + .last_key = REFTABLE_BUF_INIT, \ + .scratch = REFTABLE_BUF_INIT, \ } /* Position `it` at start of the block */ @@ -123,7 +123,7 @@ void block_iter_seek_start(struct block_iter *it, const struct block_reader *br) /* Position `it` to the `want` key in the block */ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br, - struct strbuf *want); + struct reftable_buf *want); /* return < 0 for error, 0 for OK, > 0 for EOF. */ int block_iter_next(struct block_iter *it, struct reftable_record *rec); diff --git a/reftable/blocksource.c b/reftable/blocksource.c index a2a6a196d5..52e0915a67 100644 --- a/reftable/blocksource.c +++ b/reftable/blocksource.c @@ -13,21 +13,21 @@ https://developers.google.com/open-source/licenses/bsd #include "reftable-blocksource.h" #include "reftable-error.h" -static void strbuf_return_block(void *b UNUSED, struct reftable_block *dest) +static void reftable_buf_return_block(void *b UNUSED, struct reftable_block *dest) { if (dest->len) memset(dest->data, 0xff, dest->len); reftable_free(dest->data); } -static void strbuf_close(void *b UNUSED) +static void reftable_buf_close(void *b UNUSED) { } -static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off, - uint32_t size) +static int reftable_buf_read_block(void *v, struct reftable_block *dest, + uint64_t off, uint32_t size) { - struct strbuf *b = v; + struct reftable_buf *b = v; assert(off + size <= b->len); REFTABLE_CALLOC_ARRAY(dest->data, size); if (!dest->data) @@ -37,23 +37,23 @@ static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off, return size; } -static uint64_t strbuf_size(void *b) +static uint64_t reftable_buf_size(void *b) { - return ((struct strbuf *)b)->len; + return ((struct reftable_buf *)b)->len; } -static struct reftable_block_source_vtable strbuf_vtable = { - .size = &strbuf_size, - .read_block = &strbuf_read_block, - .return_block = &strbuf_return_block, - .close = &strbuf_close, +static struct reftable_block_source_vtable reftable_buf_vtable = { + .size = &reftable_buf_size, + .read_block = &reftable_buf_read_block, + .return_block = &reftable_buf_return_block, + .close = &reftable_buf_close, }; -void block_source_from_strbuf(struct reftable_block_source *bs, - struct strbuf *buf) +void block_source_from_buf(struct reftable_block_source *bs, + struct reftable_buf *buf) { assert(!bs->ops); - bs->ops = &strbuf_vtable; + bs->ops = &reftable_buf_vtable; bs->arg = buf; } diff --git a/reftable/blocksource.h b/reftable/blocksource.h index 659a27b406..a84a3ccd89 100644 --- a/reftable/blocksource.h +++ b/reftable/blocksource.h @@ -12,9 +12,10 @@ https://developers.google.com/open-source/licenses/bsd #include "system.h" struct reftable_block_source; +struct reftable_buf; /* Create an in-memory block source for reading reftables */ -void block_source_from_strbuf(struct reftable_block_source *bs, - struct strbuf *buf); +void block_source_from_buf(struct reftable_block_source *bs, + struct reftable_buf *buf); #endif diff --git a/reftable/iter.c b/reftable/iter.c index d926db653b..86e801ca9f 100644 --- a/reftable/iter.c +++ b/reftable/iter.c @@ -55,7 +55,7 @@ void iterator_set_empty(struct reftable_iterator *it) static void filtering_ref_iterator_close(void *iter_arg) { struct filtering_ref_iterator *fri = iter_arg; - strbuf_release(&fri->oid); + reftable_buf_release(&fri->oid); reftable_iterator_destroy(&fri->it); } @@ -115,7 +115,7 @@ static void indexed_table_ref_iter_close(void *p) block_iter_close(&it->cur); reftable_block_done(&it->block_reader.block); reftable_free(it->offsets); - strbuf_release(&it->oid); + reftable_buf_release(&it->oid); } static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it) @@ -197,7 +197,10 @@ int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest, *itr = empty; itr->r = r; - strbuf_add(&itr->oid, oid, oid_len); + + err = reftable_buf_add(&itr->oid, oid, oid_len); + if (err < 0) + goto out; itr->offsets = offsets; itr->offset_len = offset_len; diff --git a/reftable/iter.h b/reftable/iter.h index b3225bc7ad..40f98893b8 100644 --- a/reftable/iter.h +++ b/reftable/iter.h @@ -44,12 +44,12 @@ void iterator_set_empty(struct reftable_iterator *it); /* iterator that produces only ref records that point to `oid` */ struct filtering_ref_iterator { - struct strbuf oid; + struct reftable_buf oid; struct reftable_iterator it; }; #define FILTERING_REF_ITERATOR_INIT \ { \ - .oid = STRBUF_INIT \ + .oid = REFTABLE_BUF_INIT \ } void iterator_from_filtering_ref_iterator(struct reftable_iterator *, @@ -60,7 +60,7 @@ void iterator_from_filtering_ref_iterator(struct reftable_iterator *, */ struct indexed_table_ref_iter { struct reftable_reader *r; - struct strbuf oid; + struct reftable_buf oid; /* mutable */ uint64_t *offsets; @@ -75,7 +75,7 @@ struct indexed_table_ref_iter { #define INDEXED_TABLE_REF_ITER_INIT { \ .cur = BLOCK_ITER_INIT, \ - .oid = STRBUF_INIT, \ + .oid = REFTABLE_BUF_INIT, \ } void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it, diff --git a/reftable/reader.c b/reftable/reader.c index 8d37253922..90dc950b57 100644 --- a/reftable/reader.c +++ b/reftable/reader.c @@ -350,13 +350,15 @@ static int table_iter_seek_start(struct table_iter *ti, uint8_t typ, int index) static int table_iter_seek_linear(struct table_iter *ti, struct reftable_record *want) { - struct strbuf want_key = STRBUF_INIT; - struct strbuf got_key = STRBUF_INIT; + struct reftable_buf want_key = REFTABLE_BUF_INIT; + struct reftable_buf got_key = REFTABLE_BUF_INIT; struct reftable_record rec; int err; reftable_record_init(&rec, reftable_record_type(want)); - reftable_record_key(want, &want_key); + err = reftable_record_key(want, &want_key); + if (err < 0) + goto done; /* * First we need to locate the block that must contain our record. To @@ -401,7 +403,7 @@ static int table_iter_seek_linear(struct table_iter *ti, if (err < 0) goto done; - if (strbuf_cmp(&got_key, &want_key) > 0) { + if (reftable_buf_cmp(&got_key, &want_key) > 0) { table_iter_block_done(&next); break; } @@ -422,8 +424,8 @@ static int table_iter_seek_linear(struct table_iter *ti, done: reftable_record_release(&rec); - strbuf_release(&want_key); - strbuf_release(&got_key); + reftable_buf_release(&want_key); + reftable_buf_release(&got_key); return err; } @@ -431,15 +433,17 @@ static int table_iter_seek_indexed(struct table_iter *ti, struct reftable_record *rec) { struct reftable_record want_index = { - .type = BLOCK_TYPE_INDEX, .u.idx = { .last_key = STRBUF_INIT } + .type = BLOCK_TYPE_INDEX, .u.idx = { .last_key = REFTABLE_BUF_INIT } }; struct reftable_record index_result = { .type = BLOCK_TYPE_INDEX, - .u.idx = { .last_key = STRBUF_INIT }, + .u.idx = { .last_key = REFTABLE_BUF_INIT }, }; int err; - reftable_record_key(rec, &want_index.u.idx.last_key); + err = reftable_record_key(rec, &want_index.u.idx.last_key); + if (err < 0) + goto done; /* * The index may consist of multiple levels, where each level may have @@ -765,7 +769,10 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r, } *filter = empty; - strbuf_add(&filter->oid, oid, oid_len); + err = reftable_buf_add(&filter->oid, oid, oid_len); + if (err < 0) + goto out; + iterator_from_table_iter(&filter->it, ti); iterator_from_filtering_ref_iterator(it, filter); diff --git a/reftable/record.c b/reftable/record.c index 30d563e16d..fb5652ed57 100644 --- a/reftable/record.c +++ b/reftable/record.c @@ -98,19 +98,24 @@ const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record * } } -static int decode_string(struct strbuf *dest, struct string_view in) +static int decode_string(struct reftable_buf *dest, struct string_view in) { int start_len = in.len; uint64_t tsize = 0; - int n = get_var_int(&tsize, &in); + int n, err; + + n = get_var_int(&tsize, &in); if (n <= 0) return -1; string_view_consume(&in, n); if (in.len < tsize) return -1; - strbuf_reset(dest); - strbuf_add(dest, in.buf, tsize); + reftable_buf_reset(dest); + err = reftable_buf_add(dest, in.buf, tsize); + if (err < 0) + return err; + string_view_consume(&in, tsize); return start_len - in.len; @@ -133,7 +138,7 @@ static int encode_string(const char *str, struct string_view s) } int reftable_encode_key(int *restart, struct string_view dest, - struct strbuf prev_key, struct strbuf key, + struct reftable_buf prev_key, struct reftable_buf key, uint8_t extra) { struct string_view start = dest; @@ -183,13 +188,13 @@ int reftable_decode_keylen(struct string_view in, return start_len - in.len; } -int reftable_decode_key(struct strbuf *last_key, uint8_t *extra, +int reftable_decode_key(struct reftable_buf *last_key, uint8_t *extra, struct string_view in) { int start_len = in.len; uint64_t prefix_len = 0; uint64_t suffix_len = 0; - int n; + int err, n; n = reftable_decode_keylen(in, &prefix_len, &suffix_len, extra); if (n < 0) @@ -200,19 +205,25 @@ int reftable_decode_key(struct strbuf *last_key, uint8_t *extra, prefix_len > last_key->len) return -1; - strbuf_setlen(last_key, prefix_len); - strbuf_add(last_key, in.buf, suffix_len); + err = reftable_buf_setlen(last_key, prefix_len); + if (err < 0) + return err; + + err = reftable_buf_add(last_key, in.buf, suffix_len); + if (err < 0) + return err; + string_view_consume(&in, suffix_len); return start_len - in.len; } -static void reftable_ref_record_key(const void *r, struct strbuf *dest) +static int reftable_ref_record_key(const void *r, struct reftable_buf *dest) { const struct reftable_ref_record *rec = (const struct reftable_ref_record *)r; - strbuf_reset(dest); - strbuf_addstr(dest, rec->refname); + reftable_buf_reset(dest); + return reftable_buf_addstr(dest, rec->refname); } static int reftable_ref_record_copy_from(void *rec, const void *src_rec, @@ -350,9 +361,9 @@ static int reftable_ref_record_encode(const void *rec, struct string_view s, return start.len - s.len; } -static int reftable_ref_record_decode(void *rec, struct strbuf key, +static int reftable_ref_record_decode(void *rec, struct reftable_buf key, uint8_t val_type, struct string_view in, - int hash_size, struct strbuf *scratch) + int hash_size, struct reftable_buf *scratch) { struct reftable_ref_record *r = rec; struct string_view start = in; @@ -415,7 +426,7 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key, goto done; } string_view_consume(&in, n); - r->value.symref = strbuf_detach(scratch, NULL); + r->value.symref = reftable_buf_detach(scratch); } break; case REFTABLE_REF_DELETION: @@ -465,12 +476,12 @@ static struct reftable_record_vtable reftable_ref_record_vtable = { .cmp = &reftable_ref_record_cmp_void, }; -static void reftable_obj_record_key(const void *r, struct strbuf *dest) +static int reftable_obj_record_key(const void *r, struct reftable_buf *dest) { const struct reftable_obj_record *rec = (const struct reftable_obj_record *)r; - strbuf_reset(dest); - strbuf_add(dest, rec->hash_prefix, rec->hash_prefix_len); + reftable_buf_reset(dest); + return reftable_buf_add(dest, rec->hash_prefix, rec->hash_prefix_len); } static void reftable_obj_record_release(void *rec) @@ -547,10 +558,10 @@ static int reftable_obj_record_encode(const void *rec, struct string_view s, return start.len - s.len; } -static int reftable_obj_record_decode(void *rec, struct strbuf key, +static int reftable_obj_record_decode(void *rec, struct reftable_buf key, uint8_t val_type, struct string_view in, int hash_size UNUSED, - struct strbuf *scratch UNUSED) + struct reftable_buf *scratch UNUSED) { struct string_view start = in; struct reftable_obj_record *r = rec; @@ -664,19 +675,27 @@ static struct reftable_record_vtable reftable_obj_record_vtable = { .cmp = &reftable_obj_record_cmp_void, }; -static void reftable_log_record_key(const void *r, struct strbuf *dest) +static int reftable_log_record_key(const void *r, struct reftable_buf *dest) { const struct reftable_log_record *rec = (const struct reftable_log_record *)r; - int len = strlen(rec->refname); + int len = strlen(rec->refname), err; uint8_t i64[8]; uint64_t ts = 0; - strbuf_reset(dest); - strbuf_add(dest, (uint8_t *)rec->refname, len + 1); + + reftable_buf_reset(dest); + err = reftable_buf_add(dest, (uint8_t *)rec->refname, len + 1); + if (err < 0) + return err; ts = (~ts) - rec->update_index; put_be64(&i64[0], ts); - strbuf_add(dest, i64, sizeof(i64)); + + err = reftable_buf_add(dest, i64, sizeof(i64)); + if (err < 0) + return err; + + return 0; } static int reftable_log_record_copy_from(void *rec, const void *src_rec, @@ -807,9 +826,9 @@ static int reftable_log_record_encode(const void *rec, struct string_view s, return start.len - s.len; } -static int reftable_log_record_decode(void *rec, struct strbuf key, +static int reftable_log_record_decode(void *rec, struct reftable_buf key, uint8_t val_type, struct string_view in, - int hash_size, struct strbuf *scratch) + int hash_size, struct reftable_buf *scratch) { struct string_view start = in; struct reftable_log_record *r = rec; @@ -1027,11 +1046,11 @@ static struct reftable_record_vtable reftable_log_record_vtable = { .cmp = &reftable_log_record_cmp_void, }; -static void reftable_index_record_key(const void *r, struct strbuf *dest) +static int reftable_index_record_key(const void *r, struct reftable_buf *dest) { const struct reftable_index_record *rec = r; - strbuf_reset(dest); - strbuf_addbuf(dest, &rec->last_key); + reftable_buf_reset(dest); + return reftable_buf_add(dest, rec->last_key.buf, rec->last_key.len); } static int reftable_index_record_copy_from(void *rec, const void *src_rec, @@ -1039,9 +1058,12 @@ static int reftable_index_record_copy_from(void *rec, const void *src_rec, { struct reftable_index_record *dst = rec; const struct reftable_index_record *src = src_rec; + int err; - strbuf_reset(&dst->last_key); - strbuf_addbuf(&dst->last_key, &src->last_key); + reftable_buf_reset(&dst->last_key); + err = reftable_buf_add(&dst->last_key, src->last_key.buf, src->last_key.len); + if (err < 0) + return err; dst->offset = src->offset; return 0; @@ -1050,7 +1072,7 @@ static int reftable_index_record_copy_from(void *rec, const void *src_rec, static void reftable_index_record_release(void *rec) { struct reftable_index_record *idx = rec; - strbuf_release(&idx->last_key); + reftable_buf_release(&idx->last_key); } static uint8_t reftable_index_record_val_type(const void *rec UNUSED) @@ -1074,18 +1096,20 @@ static int reftable_index_record_encode(const void *rec, struct string_view out, return start.len - out.len; } -static int reftable_index_record_decode(void *rec, struct strbuf key, +static int reftable_index_record_decode(void *rec, struct reftable_buf key, uint8_t val_type UNUSED, struct string_view in, int hash_size UNUSED, - struct strbuf *scratch UNUSED) + struct reftable_buf *scratch UNUSED) { struct string_view start = in; struct reftable_index_record *r = rec; - int n = 0; + int err, n = 0; - strbuf_reset(&r->last_key); - strbuf_addbuf(&r->last_key, &key); + reftable_buf_reset(&r->last_key); + err = reftable_buf_add(&r->last_key, key.buf, key.len); + if (err < 0) + return err; n = get_var_int(&r->offset, &in); if (n < 0) @@ -1101,14 +1125,14 @@ static int reftable_index_record_equal(const void *a, const void *b, struct reftable_index_record *ia = (struct reftable_index_record *) a; struct reftable_index_record *ib = (struct reftable_index_record *) b; - return ia->offset == ib->offset && !strbuf_cmp(&ia->last_key, &ib->last_key); + return ia->offset == ib->offset && !reftable_buf_cmp(&ia->last_key, &ib->last_key); } static int reftable_index_record_cmp(const void *_a, const void *_b) { const struct reftable_index_record *a = _a; const struct reftable_index_record *b = _b; - return strbuf_cmp(&a->last_key, &b->last_key); + return reftable_buf_cmp(&a->last_key, &b->last_key); } static struct reftable_record_vtable reftable_index_record_vtable = { @@ -1124,9 +1148,9 @@ static struct reftable_record_vtable reftable_index_record_vtable = { .cmp = &reftable_index_record_cmp, }; -void reftable_record_key(struct reftable_record *rec, struct strbuf *dest) +int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest) { - reftable_record_vtable(rec)->key(reftable_record_data(rec), dest); + return reftable_record_vtable(rec)->key(reftable_record_data(rec), dest); } int reftable_record_encode(struct reftable_record *rec, struct string_view dest, @@ -1151,9 +1175,9 @@ uint8_t reftable_record_val_type(struct reftable_record *rec) return reftable_record_vtable(rec)->val_type(reftable_record_data(rec)); } -int reftable_record_decode(struct reftable_record *rec, struct strbuf key, +int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key, uint8_t extra, struct string_view src, int hash_size, - struct strbuf *scratch) + struct reftable_buf *scratch) { return reftable_record_vtable(rec)->decode(reftable_record_data(rec), key, extra, src, hash_size, @@ -1294,7 +1318,7 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ) case BLOCK_TYPE_OBJ: return; case BLOCK_TYPE_INDEX: - strbuf_init(&rec->u.idx.last_key, 0); + reftable_buf_init(&rec->u.idx.last_key); return; default: BUG("unhandled record type"); diff --git a/reftable/record.h b/reftable/record.h index 0f53ba5443..25aa908c85 100644 --- a/reftable/record.h +++ b/reftable/record.h @@ -9,6 +9,7 @@ https://developers.google.com/open-source/licenses/bsd #ifndef RECORD_H #define RECORD_H +#include "basics.h" #include "system.h" #include <stdint.h> @@ -38,8 +39,8 @@ int put_var_int(struct string_view *dest, uint64_t val); /* Methods for records. */ struct reftable_record_vtable { - /* encode the key of to a uint8_t strbuf. */ - void (*key)(const void *rec, struct strbuf *dest); + /* encode the key of to a uint8_t reftable_buf. */ + int (*key)(const void *rec, struct reftable_buf *dest); /* The record type of ('r' for ref). */ uint8_t type; @@ -54,9 +55,9 @@ struct reftable_record_vtable { int (*encode)(const void *rec, struct string_view dest, int hash_size); /* decode data from `src` into the record. */ - int (*decode)(void *rec, struct strbuf key, uint8_t extra, + int (*decode)(void *rec, struct reftable_buf key, uint8_t extra, struct string_view src, int hash_size, - struct strbuf *scratch); + struct reftable_buf *scratch); /* deallocate and null the record. */ void (*release)(void *rec); @@ -83,7 +84,7 @@ int reftable_is_block_type(uint8_t typ); /* Encode `key` into `dest`. Sets `is_restart` to indicate a restart. Returns * number of bytes written. */ int reftable_encode_key(int *is_restart, struct string_view dest, - struct strbuf prev_key, struct strbuf key, + struct reftable_buf prev_key, struct reftable_buf key, uint8_t extra); /* Decode a record's key lengths. */ @@ -96,13 +97,13 @@ int reftable_decode_keylen(struct string_view in, * Decode into `last_key` and `extra` from `in`. `last_key` is expected to * contain the decoded key of the preceding record, if any. */ -int reftable_decode_key(struct strbuf *last_key, uint8_t *extra, +int reftable_decode_key(struct reftable_buf *last_key, uint8_t *extra, struct string_view in); /* reftable_index_record are used internally to speed up lookups. */ struct reftable_index_record { uint64_t offset; /* Offset of block */ - struct strbuf last_key; /* Last key of the block. */ + struct reftable_buf last_key; /* Last key of the block. */ }; /* reftable_obj_record stores an object ID => ref mapping. */ @@ -136,15 +137,15 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ); /* see struct record_vtable */ int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b); int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size); -void reftable_record_key(struct reftable_record *rec, struct strbuf *dest); +int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest); int reftable_record_copy_from(struct reftable_record *rec, struct reftable_record *src, int hash_size); uint8_t reftable_record_val_type(struct reftable_record *rec); int reftable_record_encode(struct reftable_record *rec, struct string_view dest, int hash_size); -int reftable_record_decode(struct reftable_record *rec, struct strbuf key, +int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key, uint8_t extra, struct string_view src, - int hash_size, struct strbuf *scratch); + int hash_size, struct reftable_buf *scratch); int reftable_record_is_deletion(struct reftable_record *rec); static inline uint8_t reftable_record_type(struct reftable_record *rec) diff --git a/reftable/stack.c b/reftable/stack.c index 7e617c2591..c33979536e 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -31,13 +31,16 @@ static void reftable_addition_close(struct reftable_addition *add); static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st, int reuse_open); -static void stack_filename(struct strbuf *dest, struct reftable_stack *st, - const char *name) +static int stack_filename(struct reftable_buf *dest, struct reftable_stack *st, + const char *name) { - strbuf_reset(dest); - strbuf_addstr(dest, st->reftable_dir); - strbuf_addstr(dest, "/"); - strbuf_addstr(dest, name); + int err; + reftable_buf_reset(dest); + if ((err = reftable_buf_addstr(dest, st->reftable_dir)) < 0 || + (err = reftable_buf_addstr(dest, "/")) < 0 || + (err = reftable_buf_addstr(dest, name)) < 0) + return err; + return 0; } static ssize_t reftable_fd_write(void *arg, const void *data, size_t sz) @@ -56,7 +59,7 @@ static int reftable_fd_flush(void *arg) int reftable_new_stack(struct reftable_stack **dest, const char *dir, const struct reftable_write_options *_opts) { - struct strbuf list_file_name = STRBUF_INIT; + struct reftable_buf list_file_name = REFTABLE_BUF_INIT; struct reftable_write_options opts = { 0 }; struct reftable_stack *p; int err; @@ -74,11 +77,12 @@ int reftable_new_stack(struct reftable_stack **dest, const char *dir, *dest = NULL; - strbuf_reset(&list_file_name); - strbuf_addstr(&list_file_name, dir); - strbuf_addstr(&list_file_name, "/tables.list"); + reftable_buf_reset(&list_file_name); + if ((err = reftable_buf_addstr(&list_file_name, dir)) < 0 || + (err = reftable_buf_addstr(&list_file_name, "/tables.list")) < 0) + goto out; - p->list_file = strbuf_detach(&list_file_name, NULL); + p->list_file = reftable_buf_detach(&list_file_name); p->list_fd = -1; p->opts = opts; p->reftable_dir = reftable_strdup(dir); @@ -208,21 +212,24 @@ void reftable_stack_destroy(struct reftable_stack *st) if (st->readers) { int i = 0; - struct strbuf filename = STRBUF_INIT; + struct reftable_buf filename = REFTABLE_BUF_INIT; for (i = 0; i < st->readers_len; i++) { const char *name = reader_name(st->readers[i]); - strbuf_reset(&filename); + int try_unlinking = 1; + + reftable_buf_reset(&filename); if (names && !has_name(names, name)) { - stack_filename(&filename, st, name); + if (stack_filename(&filename, st, name) < 0) + try_unlinking = 0; } reftable_reader_decref(st->readers[i]); - if (filename.len) { + if (try_unlinking && filename.len) { /* On Windows, can only unlink after closing. */ unlink(filename.buf); } } - strbuf_release(&filename); + reftable_buf_release(&filename); st->readers_len = 0; REFTABLE_FREE_AND_NULL(st->readers); } @@ -260,7 +267,7 @@ static int reftable_stack_reload_once(struct reftable_stack *st, size_t reused_len = 0, reused_alloc = 0, names_len; size_t new_readers_len = 0; struct reftable_merged_table *new_merged = NULL; - struct strbuf table_path = STRBUF_INIT; + struct reftable_buf table_path = REFTABLE_BUF_INIT; int err = 0; size_t i; @@ -310,7 +317,10 @@ static int reftable_stack_reload_once(struct reftable_stack *st, if (!rd) { struct reftable_block_source src = { NULL }; - stack_filename(&table_path, st, name); + + err = stack_filename(&table_path, st, name); + if (err < 0) + goto done; err = reftable_block_source_from_file(&src, table_path.buf); @@ -341,7 +351,11 @@ static int reftable_stack_reload_once(struct reftable_stack *st, for (i = 0; i < cur_len; i++) { if (cur[i]) { const char *name = reader_name(cur[i]); - stack_filename(&table_path, st, name); + + err = stack_filename(&table_path, st, name); + if (err < 0) + goto done; + reftable_reader_decref(cur[i]); unlink(table_path.buf); } @@ -374,7 +388,7 @@ done: reftable_free(new_readers); reftable_free(reused); reftable_free(cur); - strbuf_release(&table_path); + reftable_buf_release(&table_path); return err; } @@ -623,14 +637,14 @@ int reftable_stack_add(struct reftable_stack *st, return 0; } -static void format_name(struct strbuf *dest, uint64_t min, uint64_t max) +static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max) { char buf[100]; uint32_t rnd = (uint32_t)git_rand(); snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x", min, max, rnd); - strbuf_reset(dest); - strbuf_addstr(dest, buf); + reftable_buf_reset(dest); + return reftable_buf_addstr(dest, buf); } struct reftable_addition { @@ -648,7 +662,7 @@ static int reftable_stack_init_addition(struct reftable_addition *add, struct reftable_stack *st, unsigned int flags) { - struct strbuf lock_file_name = STRBUF_INIT; + struct reftable_buf lock_file_name = REFTABLE_BUF_INIT; int err; add->stack = st; @@ -690,18 +704,18 @@ static int reftable_stack_init_addition(struct reftable_addition *add, done: if (err) reftable_addition_close(add); - strbuf_release(&lock_file_name); + reftable_buf_release(&lock_file_name); return err; } static void reftable_addition_close(struct reftable_addition *add) { - struct strbuf nm = STRBUF_INIT; + struct reftable_buf nm = REFTABLE_BUF_INIT; size_t i; for (i = 0; i < add->new_tables_len; i++) { - stack_filename(&nm, add->stack, add->new_tables[i]); - unlink(nm.buf); + if (!stack_filename(&nm, add->stack, add->new_tables[i])) + unlink(nm.buf); reftable_free(add->new_tables[i]); add->new_tables[i] = NULL; } @@ -711,7 +725,7 @@ static void reftable_addition_close(struct reftable_addition *add) add->new_tables_cap = 0; rollback_lock_file(&add->tables_list_lock); - strbuf_release(&nm); + reftable_buf_release(&nm); } void reftable_addition_destroy(struct reftable_addition *add) @@ -725,7 +739,7 @@ void reftable_addition_destroy(struct reftable_addition *add) int reftable_addition_commit(struct reftable_addition *add) { - struct strbuf table_list = STRBUF_INIT; + struct reftable_buf table_list = REFTABLE_BUF_INIT; int lock_file_fd = get_lock_file_fd(&add->tables_list_lock); int err = 0; size_t i; @@ -734,16 +748,18 @@ int reftable_addition_commit(struct reftable_addition *add) goto done; for (i = 0; i < add->stack->merged->readers_len; i++) { - strbuf_addstr(&table_list, add->stack->readers[i]->name); - strbuf_addstr(&table_list, "\n"); + if ((err = reftable_buf_addstr(&table_list, add->stack->readers[i]->name)) < 0 || + (err = reftable_buf_addstr(&table_list, "\n")) < 0) + goto done; } for (i = 0; i < add->new_tables_len; i++) { - strbuf_addstr(&table_list, add->new_tables[i]); - strbuf_addstr(&table_list, "\n"); + if ((err = reftable_buf_addstr(&table_list, add->new_tables[i])) < 0 || + (err = reftable_buf_addstr(&table_list, "\n")) < 0) + goto done; } err = write_in_full(lock_file_fd, table_list.buf, table_list.len); - strbuf_release(&table_list); + reftable_buf_release(&table_list); if (err < 0) { err = REFTABLE_IO_ERROR; goto done; @@ -837,19 +853,27 @@ int reftable_addition_add(struct reftable_addition *add, void *arg), void *arg) { - struct strbuf temp_tab_file_name = STRBUF_INIT; - struct strbuf tab_file_name = STRBUF_INIT; - struct strbuf next_name = STRBUF_INIT; + struct reftable_buf temp_tab_file_name = REFTABLE_BUF_INIT; + struct reftable_buf tab_file_name = REFTABLE_BUF_INIT; + struct reftable_buf next_name = REFTABLE_BUF_INIT; struct reftable_writer *wr = NULL; struct tempfile *tab_file = NULL; int err = 0; int tab_fd; - strbuf_reset(&next_name); - format_name(&next_name, add->next_update_index, add->next_update_index); + reftable_buf_reset(&next_name); - stack_filename(&temp_tab_file_name, add->stack, next_name.buf); - strbuf_addstr(&temp_tab_file_name, ".temp.XXXXXX"); + err = format_name(&next_name, add->next_update_index, add->next_update_index); + if (err < 0) + goto done; + + err = stack_filename(&temp_tab_file_name, add->stack, next_name.buf); + if (err < 0) + goto done; + + err = reftable_buf_addstr(&temp_tab_file_name, ".temp.XXXXXX"); + if (err < 0) + goto done; tab_file = mks_tempfile(temp_tab_file_name.buf); if (!tab_file) { @@ -893,9 +917,17 @@ int reftable_addition_add(struct reftable_addition *add, goto done; } - format_name(&next_name, wr->min_update_index, wr->max_update_index); - strbuf_addstr(&next_name, ".ref"); - stack_filename(&tab_file_name, add->stack, next_name.buf); + err = format_name(&next_name, wr->min_update_index, wr->max_update_index); + if (err < 0) + goto done; + + err = reftable_buf_addstr(&next_name, ".ref"); + if (err < 0) + goto done; + + err = stack_filename(&tab_file_name, add->stack, next_name.buf); + if (err < 0) + goto done; /* On windows, this relies on rand() picking a unique destination name. @@ -913,13 +945,13 @@ int reftable_addition_add(struct reftable_addition *add, err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; } - add->new_tables[add->new_tables_len++] = strbuf_detach(&next_name, NULL); + add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name); done: delete_tempfile(&tab_file); - strbuf_release(&temp_tab_file_name); - strbuf_release(&tab_file_name); - strbuf_release(&next_name); + reftable_buf_release(&temp_tab_file_name); + reftable_buf_release(&tab_file_name); + reftable_buf_release(&next_name); reftable_writer_free(wr); return err; } @@ -938,17 +970,24 @@ static int stack_compact_locked(struct reftable_stack *st, struct reftable_log_expiry_config *config, struct tempfile **tab_file_out) { - struct strbuf next_name = STRBUF_INIT; - struct strbuf tab_file_path = STRBUF_INIT; + struct reftable_buf next_name = REFTABLE_BUF_INIT; + struct reftable_buf tab_file_path = REFTABLE_BUF_INIT; struct reftable_writer *wr = NULL; struct tempfile *tab_file; int tab_fd, err = 0; - format_name(&next_name, - reftable_reader_min_update_index(st->readers[first]), - reftable_reader_max_update_index(st->readers[last])); - stack_filename(&tab_file_path, st, next_name.buf); - strbuf_addstr(&tab_file_path, ".temp.XXXXXX"); + err = format_name(&next_name, reftable_reader_min_update_index(st->readers[first]), + reftable_reader_max_update_index(st->readers[last])); + if (err < 0) + goto done; + + err = stack_filename(&tab_file_path, st, next_name.buf); + if (err < 0) + goto done; + + err = reftable_buf_addstr(&tab_file_path, ".temp.XXXXXX"); + if (err < 0) + goto done; tab_file = mks_tempfile(tab_file_path.buf); if (!tab_file) { @@ -986,8 +1025,8 @@ static int stack_compact_locked(struct reftable_stack *st, done: delete_tempfile(&tab_file); reftable_writer_free(wr); - strbuf_release(&next_name); - strbuf_release(&tab_file_path); + reftable_buf_release(&next_name); + reftable_buf_release(&tab_file_path); return err; } @@ -1111,10 +1150,10 @@ static int stack_compact_range(struct reftable_stack *st, struct reftable_log_expiry_config *expiry, unsigned int flags) { - struct strbuf tables_list_buf = STRBUF_INIT; - struct strbuf new_table_name = STRBUF_INIT; - struct strbuf new_table_path = STRBUF_INIT; - struct strbuf table_name = STRBUF_INIT; + struct reftable_buf tables_list_buf = REFTABLE_BUF_INIT; + struct reftable_buf new_table_name = REFTABLE_BUF_INIT; + struct reftable_buf new_table_path = REFTABLE_BUF_INIT; + struct reftable_buf table_name = REFTABLE_BUF_INIT; struct lock_file tables_list_lock = LOCK_INIT; struct lock_file *table_locks = NULL; struct tempfile *new_table = NULL; @@ -1167,7 +1206,9 @@ static int stack_compact_range(struct reftable_stack *st, } for (i = last + 1; i > first; i--) { - stack_filename(&table_name, st, reader_name(st->readers[i - 1])); + err = stack_filename(&table_name, st, reader_name(st->readers[i - 1])); + if (err < 0) + goto done; err = hold_lock_file_for_update(&table_locks[nlocks], table_name.buf, LOCK_NO_DEREF); @@ -1370,10 +1411,18 @@ static int stack_compact_range(struct reftable_stack *st, * it into place now. */ if (!is_empty_table) { - format_name(&new_table_name, st->readers[first]->min_update_index, - st->readers[last]->max_update_index); - strbuf_addstr(&new_table_name, ".ref"); - stack_filename(&new_table_path, st, new_table_name.buf); + err = format_name(&new_table_name, st->readers[first]->min_update_index, + st->readers[last]->max_update_index); + if (err < 0) + goto done; + + err = reftable_buf_addstr(&new_table_name, ".ref"); + if (err < 0) + goto done; + + err = stack_filename(&new_table_path, st, new_table_name.buf); + if (err < 0) + goto done; err = rename_tempfile(&new_table, new_table_path.buf); if (err < 0) { @@ -1387,12 +1436,21 @@ static int stack_compact_range(struct reftable_stack *st, * have just written. In case the compacted table became empty we * simply skip writing it. */ - for (i = 0; i < first_to_replace; i++) - strbuf_addf(&tables_list_buf, "%s\n", names[i]); - if (!is_empty_table) - strbuf_addf(&tables_list_buf, "%s\n", new_table_name.buf); - for (i = last_to_replace + 1; names[i]; i++) - strbuf_addf(&tables_list_buf, "%s\n", names[i]); + for (i = 0; i < first_to_replace; i++) { + if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 || + (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0) + goto done; + } + if (!is_empty_table) { + if ((err = reftable_buf_addstr(&tables_list_buf, new_table_name.buf)) < 0 || + (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0) + goto done; + } + for (i = last_to_replace + 1; names[i]; i++) { + if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 || + (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0) + goto done; + } err = write_in_full(get_lock_file_fd(&tables_list_lock), tables_list_buf.buf, tables_list_buf.len); @@ -1443,10 +1501,10 @@ done: reftable_free(table_locks); delete_tempfile(&new_table); - strbuf_release(&new_table_name); - strbuf_release(&new_table_path); - strbuf_release(&tables_list_buf); - strbuf_release(&table_name); + reftable_buf_release(&new_table_name); + reftable_buf_release(&new_table_path); + reftable_buf_release(&tables_list_buf); + reftable_buf_release(&table_name); free_names(names); if (err == REFTABLE_LOCK_ERROR) @@ -1660,8 +1718,11 @@ static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max, uint64_t update_idx = 0; struct reftable_block_source src = { NULL }; struct reftable_reader *rd = NULL; - struct strbuf table_path = STRBUF_INIT; - stack_filename(&table_path, st, name); + struct reftable_buf table_path = REFTABLE_BUF_INIT; + + err = stack_filename(&table_path, st, name); + if (err < 0) + goto done; err = reftable_block_source_from_file(&src, table_path.buf); if (err < 0) @@ -1678,7 +1739,7 @@ static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max, unlink(table_path.buf); } done: - strbuf_release(&table_path); + reftable_buf_release(&table_path); } static int reftable_stack_clean_locked(struct reftable_stack *st) diff --git a/reftable/system.h b/reftable/system.h index d0cabd5d17..5ec8583343 100644 --- a/reftable/system.h +++ b/reftable/system.h @@ -13,7 +13,6 @@ https://developers.google.com/open-source/licenses/bsd #include "git-compat-util.h" #include "lockfile.h" -#include "strbuf.h" #include "tempfile.h" #include "hash.h" /* hash ID, sizes.*/ #include "dir.h" /* remove_dir_recursively, for tests.*/ diff --git a/reftable/writer.c b/reftable/writer.c index b032a47dec..fd136794d5 100644 --- a/reftable/writer.c +++ b/reftable/writer.c @@ -115,7 +115,7 @@ static int writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ) if (w->next == 0) block_start = header_size(writer_version(w)); - strbuf_reset(&w->last_key); + reftable_buf_reset(&w->last_key); ret = block_writer_init(&w->block_writer_data, typ, w->block, w->opts.block_size, block_start, hash_size(w->opts.hash_id)); @@ -146,8 +146,8 @@ int reftable_writer_new(struct reftable_writer **out, if (opts.block_size >= (1 << 24)) BUG("configured block size exceeds 16MB"); - strbuf_init(&wp->block_writer_data.last_key, 0); - strbuf_init(&wp->last_key, 0); + reftable_buf_init(&wp->block_writer_data.last_key); + reftable_buf_init(&wp->last_key); REFTABLE_CALLOC_ARRAY(wp->block, opts.block_size); if (!wp->block) { reftable_free(wp); @@ -179,7 +179,7 @@ static void writer_release(struct reftable_writer *w) block_writer_release(&w->block_writer_data); w->block_writer = NULL; writer_clear_index(w); - strbuf_release(&w->last_key); + reftable_buf_release(&w->last_key); } } @@ -190,7 +190,7 @@ void reftable_writer_free(struct reftable_writer *w) } struct obj_index_tree_node { - struct strbuf hash; + struct reftable_buf hash; uint64_t *offsets; size_t offset_len; size_t offset_cap; @@ -198,16 +198,16 @@ struct obj_index_tree_node { #define OBJ_INDEX_TREE_NODE_INIT \ { \ - .hash = STRBUF_INIT \ + .hash = REFTABLE_BUF_INIT \ } static int obj_index_tree_node_compare(const void *a, const void *b) { - return strbuf_cmp(&((const struct obj_index_tree_node *)a)->hash, + return reftable_buf_cmp(&((const struct obj_index_tree_node *)a)->hash, &((const struct obj_index_tree_node *)b)->hash); } -static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash) +static int writer_index_hash(struct reftable_writer *w, struct reftable_buf *hash) { uint64_t off = w->next; struct obj_index_tree_node want = { .hash = *hash }; @@ -217,6 +217,7 @@ static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash) node = tree_search(w->obj_index_tree, &want, &obj_index_tree_node_compare); if (!node) { struct obj_index_tree_node empty = OBJ_INDEX_TREE_NODE_INIT; + int err; key = reftable_malloc(sizeof(*key)); if (!key) @@ -224,8 +225,10 @@ static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash) *key = empty; - strbuf_reset(&key->hash); - strbuf_addbuf(&key->hash, hash); + reftable_buf_reset(&key->hash); + err = reftable_buf_add(&key->hash, hash->buf, hash->len); + if (err < 0) + return err; tree_insert(&w->obj_index_tree, key, &obj_index_tree_node_compare); } else { @@ -246,17 +249,23 @@ static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash) static int writer_add_record(struct reftable_writer *w, struct reftable_record *rec) { - struct strbuf key = STRBUF_INIT; + struct reftable_buf key = REFTABLE_BUF_INIT; int err; - reftable_record_key(rec, &key); - if (strbuf_cmp(&w->last_key, &key) >= 0) { + err = reftable_record_key(rec, &key); + if (err < 0) + goto done; + + if (reftable_buf_cmp(&w->last_key, &key) >= 0) { err = REFTABLE_API_ERROR; goto done; } - strbuf_reset(&w->last_key); - strbuf_addbuf(&w->last_key, &key); + reftable_buf_reset(&w->last_key); + err = reftable_buf_add(&w->last_key, key.buf, key.len); + if (err < 0) + goto done; + if (!w->block_writer) { err = writer_reinit_block_writer(w, reftable_record_type(rec)); if (err < 0) @@ -303,7 +312,7 @@ static int writer_add_record(struct reftable_writer *w, } done: - strbuf_release(&key); + reftable_buf_release(&key); return err; } @@ -316,7 +325,7 @@ int reftable_writer_add_ref(struct reftable_writer *w, .ref = *ref }, }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; int err; if (!ref->refname || @@ -331,8 +340,10 @@ int reftable_writer_add_ref(struct reftable_writer *w, goto out; if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) { - strbuf_add(&buf, (char *)reftable_ref_record_val1(ref), - hash_size(w->opts.hash_id)); + err = reftable_buf_add(&buf, (char *)reftable_ref_record_val1(ref), + hash_size(w->opts.hash_id)); + if (err < 0) + goto out; err = writer_index_hash(w, &buf); if (err < 0) @@ -340,9 +351,11 @@ int reftable_writer_add_ref(struct reftable_writer *w, } if (!w->opts.skip_index_objects && reftable_ref_record_val2(ref)) { - strbuf_reset(&buf); - strbuf_add(&buf, reftable_ref_record_val2(ref), - hash_size(w->opts.hash_id)); + reftable_buf_reset(&buf); + err = reftable_buf_add(&buf, reftable_ref_record_val2(ref), + hash_size(w->opts.hash_id)); + if (err < 0) + goto out; err = writer_index_hash(w, &buf); if (err < 0) @@ -352,7 +365,7 @@ int reftable_writer_add_ref(struct reftable_writer *w, err = 0; out: - strbuf_release(&buf); + reftable_buf_release(&buf); return err; } @@ -393,7 +406,7 @@ int reftable_writer_add_log(struct reftable_writer *w, struct reftable_log_record *log) { char *input_log_message = NULL; - struct strbuf cleaned_message = STRBUF_INIT; + struct reftable_buf cleaned_message = REFTABLE_BUF_INIT; int err = 0; if (log->value_type == REFTABLE_LOG_DELETION) @@ -404,24 +417,34 @@ int reftable_writer_add_log(struct reftable_writer *w, input_log_message = log->value.update.message; if (!w->opts.exact_log_message && log->value.update.message) { - strbuf_addstr(&cleaned_message, log->value.update.message); + err = reftable_buf_addstr(&cleaned_message, log->value.update.message); + if (err < 0) + goto done; + while (cleaned_message.len && - cleaned_message.buf[cleaned_message.len - 1] == '\n') - strbuf_setlen(&cleaned_message, - cleaned_message.len - 1); + cleaned_message.buf[cleaned_message.len - 1] == '\n') { + err = reftable_buf_setlen(&cleaned_message, + cleaned_message.len - 1); + if (err < 0) + goto done; + } if (strchr(cleaned_message.buf, '\n')) { /* multiple lines not allowed. */ err = REFTABLE_API_ERROR; goto done; } - strbuf_addstr(&cleaned_message, "\n"); + + err = reftable_buf_addstr(&cleaned_message, "\n"); + if (err < 0) + goto done; + log->value.update.message = cleaned_message.buf; } err = reftable_writer_add_log_verbatim(w, log); log->value.update.message = input_log_message; done: - strbuf_release(&cleaned_message); + reftable_buf_release(&cleaned_message); return err; } @@ -504,7 +527,7 @@ static int writer_finish_section(struct reftable_writer *w) return err; for (i = 0; i < idx_len; i++) - strbuf_release(&idx[i].last_key); + reftable_buf_release(&idx[i].last_key); reftable_free(idx); } @@ -521,13 +544,13 @@ static int writer_finish_section(struct reftable_writer *w) bstats->max_index_level = max_level; /* Reinit lastKey, as the next section can start with any key. */ - strbuf_reset(&w->last_key); + reftable_buf_reset(&w->last_key); return 0; } struct common_prefix_arg { - struct strbuf *last; + struct reftable_buf *last; int max; }; @@ -594,7 +617,7 @@ static void object_record_free(void *void_arg UNUSED, void *key) struct obj_index_tree_node *entry = key; REFTABLE_FREE_AND_NULL(entry->offsets); - strbuf_release(&entry->hash); + reftable_buf_release(&entry->hash); reftable_free(entry); } @@ -708,7 +731,7 @@ done: static void writer_clear_index(struct reftable_writer *w) { for (size_t i = 0; w->index && i < w->index_len; i++) - strbuf_release(&w->index[i].last_key); + reftable_buf_release(&w->index[i].last_key); REFTABLE_FREE_AND_NULL(w->index); w->index_len = 0; w->index_cap = 0; @@ -717,7 +740,7 @@ static void writer_clear_index(struct reftable_writer *w) static int writer_flush_nonempty_block(struct reftable_writer *w) { struct reftable_index_record index_record = { - .last_key = STRBUF_INIT, + .last_key = REFTABLE_BUF_INIT, }; uint8_t typ = block_writer_type(w->block_writer); struct reftable_block_stats *bstats; @@ -777,8 +800,11 @@ static int writer_flush_nonempty_block(struct reftable_writer *w) return REFTABLE_OUT_OF_MEMORY_ERROR; index_record.offset = w->next; - strbuf_reset(&index_record.last_key); - strbuf_addbuf(&index_record.last_key, &w->block_writer->last_key); + reftable_buf_reset(&index_record.last_key); + err = reftable_buf_add(&index_record.last_key, w->block_writer->last_key.buf, + w->block_writer->last_key.len); + if (err < 0) + return err; w->index[w->index_len] = index_record; w->index_len++; diff --git a/reftable/writer.h b/reftable/writer.h index 8d0df9cc52..e8a6fbb785 100644 --- a/reftable/writer.h +++ b/reftable/writer.h @@ -19,7 +19,7 @@ struct reftable_writer { int (*flush)(void *); void *write_arg; int pending_padding; - struct strbuf last_key; + struct reftable_buf last_key; /* offset of next block to write. */ uint64_t next; @@ -2420,7 +2420,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link) if (rename(src, git_dir)) die_errno(_("unable to move %s to %s"), src, git_dir); - repair_worktrees(NULL, NULL); + repair_worktrees_after_gitdir_move(src); } write_file(git_link, "gitdir: %s", git_dir); @@ -465,8 +465,9 @@ GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to use in the test scripts. Recognized values for <hash-algo> are "sha1" and "sha256". -GIT_TEST_DEFAULT_REF_FORMAT=<format> specifies which ref storage format -to use in the test scripts. Recognized values for <format> are "files". +GIT_TEST_DEFAULT_REF_FORMAT=<format> specifies which ref storage format to use +in the test scripts. Recognized values for <format> are "files" and +"reftable". GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the 'pack.writeReverseIndex' setting. diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c index 7e1d9e0ee4..ff407b575c 100644 --- a/t/helper/test-rot13-filter.c +++ b/t/helper/test-rot13-filter.c @@ -9,7 +9,7 @@ * ("clean", "smudge", etc). * * When --always-delay is given all pathnames with the "can-delay" flag - * that don't appear on the list bellow are delayed with a count of 1 + * that don't appear on the list below are delayed with a count of 1 * (see more below). * * This implementation supports special test cases: diff --git a/t/lib-bundle.sh b/t/lib-bundle.sh index cf7ed818b2..62b7bb13c8 100644 --- a/t/lib-bundle.sh +++ b/t/lib-bundle.sh @@ -11,7 +11,7 @@ convert_bundle_to_pack () { } # Check count of objects in a bundle file. -# We can use "--thin" opiton to check thin pack, which must be fixed by +# We can use "--thin" option to check thin pack, which must be fixed by # command `git-index-pack --fix-thin --stdin`. test_bundle_object_count () { thin= diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index 11d2dc9fe3..0dd764310d 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -187,7 +187,7 @@ set_reword_editor () { exit 1 fi fi && - # There should be no uncommited changes + # There should be no uncommitted changes git diff --exit-code HEAD && # The todo-list should be re-read after a reword GIT_SEQUENCE_EDITOR="\"$PWD/reword-sequence-editor.sh\"" \ diff --git a/t/lib-sudo.sh b/t/lib-sudo.sh index b4d7788f4e..477e0fdc04 100644 --- a/t/lib-sudo.sh +++ b/t/lib-sudo.sh @@ -6,7 +6,7 @@ run_with_sudo () { local RUN="$TEST_DIRECTORY/$$.sh" write_script "$RUN" "$TEST_SHELL_PATH" # avoid calling "$RUN" directly so sudo doesn't get a chance to - # override the shell, add aditional restrictions or even reject + # override the shell, add additional restrictions or even reject # running the script because its security policy deem it unsafe sudo "$TEST_SHELL_PATH" -c "\"$RUN\"" ret=$? diff --git a/t/lib-unicode-nfc-nfd.sh b/t/lib-unicode-nfc-nfd.sh index 22232247ef..aed0a4dd44 100755 --- a/t/lib-unicode-nfc-nfd.sh +++ b/t/lib-unicode-nfc-nfd.sh @@ -74,7 +74,7 @@ test_lazy_prereq UNICODE_NFD_PRESERVED ' # Yielding: \xcf \x89 + \xcc \x94 + \xcd \x82 # # Note that I've used the canonical ordering of the -# combinining characters. It is also possible to +# combining characters. It is also possible to # swap them. My testing shows that that non-standard # ordering also causes a collision in mkdir. However, # the resulting names don't draw correctly on the diff --git a/t/perf/p7527-builtin-fsmonitor.sh b/t/perf/p7527-builtin-fsmonitor.sh index c3f9a4caa4..90164327e8 100755 --- a/t/perf/p7527-builtin-fsmonitor.sh +++ b/t/perf/p7527-builtin-fsmonitor.sh @@ -95,7 +95,7 @@ test_expect_success "Setup borrowed repo (fsm+uc)" " # time is not useful. # # Create a temp branch and do all work relative to it so that we don't -# accidentially alter the real ballast branch. +# accidentally alter the real ballast branch. # test_expect_success "Setup borrowed repo (temp ballast branch)" " test_might_fail git -C $REPO checkout $BALLAST_BR && diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index ab0c763411..8ab6d9c469 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -282,7 +282,7 @@ test_perf_ () { # Run the performance test script specified in perf-test with # optional prerequisite and setup steps. # Options: -# --prereq prerequisites: Skip the test if prequisites aren't met +# --prereq prerequisites: Skip the test if prerequisites aren't met # --setup "setup-steps": Run setup steps prior to each measured iteration # test_perf () { @@ -309,7 +309,7 @@ test_size_ () { # prerequisites and setup steps. Returns the numeric value # returned by size-test. # Options: -# --prereq prerequisites: Skip the test if prequisites aren't met +# --prereq prerequisites: Skip the test if prerequisites aren't met # --setup "setup-steps": Run setup steps prior to the size measurement test_size () { diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 98b81e4d63..35c5c2b4f9 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -684,7 +684,7 @@ test_expect_success 'subtest: tests respect lazy prerequisites' ' write_and_run_sub_test_lib_test lazy-prereqs <<-\EOF && test_lazy_prereq LAZY_TRUE true - test_expect_success LAZY_TRUE "lazy prereq is satisifed" "true" + test_expect_success LAZY_TRUE "lazy prereq is satisfied" "true" test_expect_success !LAZY_TRUE "negative lazy prereq" "false" test_lazy_prereq LAZY_FALSE false @@ -695,7 +695,7 @@ test_expect_success 'subtest: tests respect lazy prerequisites' ' EOF check_sub_test_lib_test lazy-prereqs <<-\EOF - ok 1 - lazy prereq is satisifed + ok 1 - lazy prereq is satisfied ok 2 # skip negative lazy prereq (missing !LAZY_TRUE) ok 3 # skip lazy prereq not satisfied (missing LAZY_FALSE) ok 4 - negative false prereq diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index eeb2714d9d..9e6c6ee0d4 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -1116,11 +1116,11 @@ do test_delayed_checkout_progress test_terminal git checkout $opt ' - test_expect_success PERL "delayed checkout ommits progress on non-tty ($mode checkout)" ' + test_expect_success PERL "delayed checkout omits progress on non-tty ($mode checkout)" ' test_delayed_checkout_progress ! git checkout $opt ' - test_expect_success PERL,TTY "delayed checkout ommits progress with --quiet ($mode checkout)" ' + test_expect_success PERL,TTY "delayed checkout omits progress with --quiet ($mode checkout)" ' test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt ' diff --git a/t/t0212/parse_events.perl b/t/t0212/parse_events.perl index 30a9f51e9f..7146476c69 100644 --- a/t/t0212/parse_events.perl +++ b/t/t0212/parse_events.perl @@ -204,7 +204,7 @@ while (<>) { } # A series of potentially nested and threaded region and data events - # is fundamentally incompatibile with the type of summary record we + # is fundamentally incompatible with the type of summary record we # are building in this script. Since they are intended for # perf-trace-like analysis rather than a result summary, we ignore # most of them here. diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh index 20df336cc3..bef2b70871 100755 --- a/t/t0600-reffiles-backend.sh +++ b/t/t0600-reffiles-backend.sh @@ -271,7 +271,7 @@ test_expect_success 'setup worktree' ' # Some refs (refs/bisect/*, pseudorefs) are kept per worktree, so they should # only appear in the for-each-reflog output if it is called from the correct # worktree, which is exercised in this test. This test is poorly written for -# mulitple reasons: 1) it creates invalidly formatted log entres. 2) it uses +# multiple reasons: 1) it creates invalidly formatted log entries. 2) it uses # direct FS access for creating the reflogs. 3) PSEUDO-WT and refs/bisect/random # do not create reflogs by default, so it is not testing a realistic scenario. test_expect_success 'for_each_reflog()' ' diff --git a/t/t1016-compatObjectFormat.sh b/t/t1016-compatObjectFormat.sh index be3206a16f..92024fe51d 100755 --- a/t/t1016-compatObjectFormat.sh +++ b/t/t1016-compatObjectFormat.sh @@ -117,7 +117,7 @@ do git config extensions.objectformat $hash && git config extensions.compatobjectformat $(compat_hash $hash) && git config gpg.program $TEST_DIRECTORY/t1016/gpg && - echo "Hellow World!" > hello && + echo "Hello World!" > hello && eval hello_${hash}_oid=$(git hash-object hello) && git update-index --add hello && git commit -m "Initial commit" && diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 3d44bd7643..2157f37da3 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -708,7 +708,7 @@ test_expect_success 'reset with wildcard pathspec' ' test_all_match git ls-files -s -- deep && # The following `git reset`s result in updating the index on files with - # `skip-worktree` enabled. To avoid failing due to discrepencies in reported + # `skip-worktree` enabled. To avoid failing due to discrepancies in reported # "modified" files, `test_sparse_match` reset is performed separately from # "full-checkout" reset, then the index contents of all repos are verified. @@ -824,7 +824,7 @@ test_expect_success 'update-index --remove outside sparse definition' ' # Reset the state test_all_match git reset --hard && - # --force-remove supercedes --ignore-skip-worktree-entries, removing + # --force-remove supersedes --ignore-skip-worktree-entries, removing # a skip-worktree file from the index (and disk) when both are specified # with --remove test_sparse_match git update-index --force-remove --ignore-skip-worktree-entries folder1/a && @@ -2081,7 +2081,7 @@ test_expect_success 'grep is not expanded' ' test_expect_failure 'grep within submodules is not expanded' ' init_repos_as_submodules && - # do not use ensure_not_expanded() here, becasue `grep` should be + # do not use ensure_not_expanded() here, because `grep` should be # run in the superproject, not in "./sparse-index" GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ git grep --cached --recurse-submodules a -- "*/folder1/*" && diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index eb1691860d..bb057596f1 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -1838,10 +1838,10 @@ do test_expect_success "stdin $type create dangling symref ref works" ' test_when_finished "git symbolic-ref -d refs/heads/symref" && - format_command $type "symref-create refs/heads/symref" "refs/heads/unkown" >stdin && + format_command $type "symref-create refs/heads/symref" "refs/heads/unknown" >stdin && git update-ref --stdin $type --no-deref <stdin && git symbolic-ref refs/heads/symref >expect && - echo refs/heads/unkown >actual && + echo refs/heads/unknown >actual && test_cmp expect actual ' diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index ef40511d89..a3464976e3 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -195,7 +195,7 @@ test_expect_success 'dotdot is not an empty set' ' ' test_expect_success 'dotdot does not peel endpoints' ' - git tag -a -m "annote" annotated HEAD && + git tag -a -m "annotate" annotated HEAD && A=$(git rev-parse annotated) && H=$(git rev-parse annotated^0) && { diff --git a/t/t2082-parallel-checkout-attributes.sh b/t/t2082-parallel-checkout-attributes.sh index aec55496eb..da06cafad7 100755 --- a/t/t2082-parallel-checkout-attributes.sh +++ b/t/t2082-parallel-checkout-attributes.sh @@ -91,7 +91,7 @@ test_expect_success 'parallel-checkout with eol conversions' ' # Entries that require an external filter are not eligible for parallel # checkout. Check that both the parallel-eligible and non-eligible entries are -# properly writen in a single checkout operation. +# properly written in a single checkout operation. # test_expect_success 'parallel-checkout and external filter' ' set_checkout_config 2 0 && diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index 71aa9bcd62..976d048e3e 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -120,4 +120,23 @@ test_expect_success 'prune duplicate (main/linked)' ' ! test -d .git/worktrees/wt ' +test_expect_success 'not prune proper worktrees when run inside linked worktree' ' + test_when_finished rm -rf repo wt_ext && + git init repo && + ( + cd repo && + echo content >file && + git add file && + git commit -m msg && + git worktree add ../wt_ext && + git worktree add wt_int && + cd wt_int && + git worktree prune -v >out && + test_must_be_empty out && + cd ../../wt_ext && + git worktree prune -v >out && + test_must_be_empty out + ) +' + test_done diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh index edbf502ec5..7686e60f6a 100755 --- a/t/t2406-worktree-repair.sh +++ b/t/t2406-worktree-repair.sh @@ -197,4 +197,23 @@ test_expect_success 'repair moved main and linked worktrees' ' test_cmp expect-gitfile sidemoved/.git ' +test_expect_success 'repair copied main and linked worktrees' ' + test_when_finished "rm -rf orig dup" && + mkdir -p orig && + git -C orig init main && + test_commit -C orig/main nothing && + git -C orig/main worktree add ../linked && + cp orig/main/.git/worktrees/linked/gitdir orig/main.expect && + cp orig/linked/.git orig/linked.expect && + cp -R orig dup && + sed "s,orig/linked/\.git$,dup/linked/.git," orig/main.expect >dup/main.expect && + sed "s,orig/main/\.git/worktrees/linked$,dup/main/.git/worktrees/linked," \ + orig/linked.expect >dup/linked.expect && + git -C dup/main worktree repair ../linked && + test_cmp orig/main.expect orig/main/.git/worktrees/linked/gitdir && + test_cmp orig/linked.expect orig/linked/.git && + test_cmp dup/main.expect dup/main/.git/worktrees/linked/gitdir && + test_cmp dup/linked.expect dup/linked/.git +' + test_done diff --git a/t/t2408-worktree-relative.sh b/t/t2408-worktree-relative.sh new file mode 100755 index 0000000000..a3136db7e2 --- /dev/null +++ b/t/t2408-worktree-relative.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +test_description='test worktrees linked with relative paths' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'links worktrees with relative paths' ' + test_when_finished rm -rf repo && + git init repo && + ( + cd repo && + test_commit initial && + git worktree add wt1 && + echo "../../../wt1/.git" >expected_gitdir && + cat .git/worktrees/wt1/gitdir >actual_gitdir && + echo "gitdir: ../.git/worktrees/wt1" >expected_git && + cat wt1/.git >actual_git && + test_cmp expected_gitdir actual_gitdir && + test_cmp expected_git actual_git + ) +' + +test_expect_success 'move repo without breaking relative internal links' ' + test_when_finished rm -rf repo moved && + git init repo && + ( + cd repo && + test_commit initial && + git worktree add wt1 && + cd .. && + mv repo moved && + cd moved/wt1 && + git status >out 2>err && + test_must_be_empty err + ) +' + +test_done diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh index 2501c89c1c..18e5ac88c3 100755 --- a/t/t4058-diff-duplicates.sh +++ b/t/t4058-diff-duplicates.sh @@ -10,6 +10,8 @@ # that the diff output isn't wildly unreasonable. test_description='test tree diff when trees have duplicate entries' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # make_tree_entry <mode> <mode> <sha1> @@ -132,22 +134,23 @@ test_expect_success 'create a few commits' ' rm commit_id up final ' -test_expect_failure 'git read-tree does not segfault' ' - test_when_finished rm .git/index.lock && - test_might_fail git read-tree --reset base +test_expect_success 'git read-tree does not segfault' ' + test_must_fail git read-tree --reset base 2>err && + test_grep "error: corrupted cache-tree has entries not present in index" err ' -test_expect_failure 'reset --hard does not segfault' ' - test_when_finished rm .git/index.lock && +test_expect_success 'reset --hard does not segfault' ' git checkout base && - test_might_fail git reset --hard + test_must_fail git reset --hard 2>err && + test_grep "error: corrupted cache-tree has entries not present in index" err ' -test_expect_failure 'git diff HEAD does not segfault' ' +test_expect_success 'git diff HEAD does not segfault' ' git checkout base && GIT_TEST_CHECK_CACHE_TREE=false && git reset --hard && - test_might_fail git diff HEAD + test_must_fail git diff HEAD 2>err && + test_grep "error: corrupted cache-tree has entries not present in index" err ' test_expect_failure 'can switch to another branch when status is empty' ' diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index c20c885724..5b5d3b637c 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -143,6 +143,10 @@ test_expect_success 'shortlog from non-git directory refuses extra arguments' ' test_grep "too many arguments" out ' +test_expect_success 'shortlog --author from non-git directory does not segfault' ' + nongit git shortlog --author=author </dev/null +' + test_expect_success 'shortlog should add newline when input line matches wraplen' ' cat >expect <<\EOF && A U Thor (2): diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index eb63ce011f..57b8b79738 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -137,7 +137,7 @@ test_expect_success 'NUL separation with --stat' ' test_expect_failure 'NUL termination with --stat' ' stat0_part=$(git diff --stat HEAD^ HEAD) && stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) && - printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n0" >expected && + printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n\0" >expected && git log -z --stat --pretty="tformat:%s" >actual && test_cmp expected actual ' diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh index 916e58c166..9b6cf8d88b 100755 --- a/t/t5572-pull-submodule.sh +++ b/t/t5572-pull-submodule.sh @@ -230,6 +230,7 @@ test_expect_success 'branch has no merge base with remote-tracking counterpart' test_create_repo a-submodule && test_commit -C a-submodule foo && + test_commit -C a-submodule bar && test_create_repo parent && git -C parent submodule add "$(pwd)/a-submodule" && @@ -246,4 +247,23 @@ test_expect_success 'branch has no merge base with remote-tracking counterpart' git -C child pull --recurse-submodules --rebase ' +test_expect_success 'fetch submodule remote of different name from superproject' ' + git -C child remote rename origin o1 && + git -C child submodule update --init && + + # Needs to create unreachable commit from current master branch. + git -C a-submodule checkout -b newmain HEAD^ && + test_commit -C a-submodule echo && + test_commit -C a-submodule moreecho && + subc=$(git -C a-submodule rev-parse --short HEAD) && + + git -C parent/a-submodule fetch && + git -C parent/a-submodule checkout "$subc" && + git -C parent commit -m "update submodule" a-submodule && + git -C a-submodule reset --hard HEAD^^ && + + git -C child pull --no-recurse-submodules && + git -C child submodule update +' + test_done diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index d7702fc756..deba3ca430 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -98,30 +98,42 @@ test_expect_success 'set up buggy branch' ' ' test_expect_success 'replace the author' ' - git cat-file commit $HASH2 | grep "author A U Thor" && - R=$(git cat-file commit $HASH2 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) && - git cat-file commit $R | grep "author O Thor" && + git cat-file commit $HASH2 >actual && + test_grep "author A U Thor" actual && + R=$(sed -e "s/A U/O/" actual | git hash-object -t commit --stdin -w) && + git cat-file commit $R >actual && + test_grep "author O Thor" actual && git update-ref refs/replace/$HASH2 $R && - git show HEAD~5 | grep "O Thor" && - git show $HASH2 | grep "O Thor" + git show HEAD~5 >actual && + test_grep "O Thor" actual && + git show $HASH2 >actual && + test_grep "O Thor" actual ' test_expect_success 'test --no-replace-objects option' ' - git cat-file commit $HASH2 | grep "author O Thor" && - git --no-replace-objects cat-file commit $HASH2 | grep "author A U Thor" && - git show $HASH2 | grep "O Thor" && - git --no-replace-objects show $HASH2 | grep "A U Thor" + git cat-file commit $HASH2 >actual && + test_grep "author O Thor" actual && + git --no-replace-objects cat-file commit $HASH2 >actual && + test_grep "author A U Thor" actual && + git show $HASH2 >actual && + test_grep "O Thor" actual && + git --no-replace-objects show $HASH2 >actual && + test_grep "A U Thor" actual ' test_expect_success 'test GIT_NO_REPLACE_OBJECTS env variable' ' - GIT_NO_REPLACE_OBJECTS=1 git cat-file commit $HASH2 | grep "author A U Thor" && - GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 | grep "A U Thor" + GIT_NO_REPLACE_OBJECTS=1 git cat-file commit $HASH2 >actual && + test_grep "author A U Thor" actual && + GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 >actual && + test_grep "A U Thor" actual ' test_expect_success 'test core.usereplacerefs config option' ' test_config core.usereplacerefs false && - git cat-file commit $HASH2 | grep "author A U Thor" && - git show $HASH2 | grep "A U Thor" + git cat-file commit $HASH2 >actual && + test_grep "author A U Thor" actual && + git show $HASH2 >actual && + test_grep "A U Thor" actual ' cat >tag.sig <<EOF @@ -148,14 +160,18 @@ test_expect_success 'repack, clone and fetch work' ' git clone --no-hardlinks . clone_dir && ( cd clone_dir && - git show HEAD~5 | grep "A U Thor" && - git show $HASH2 | grep "A U Thor" && + git show HEAD~5 >actual && + test_grep "A U Thor" actual && + git show $HASH2 >actual && + test_grep "A U Thor" actual && git cat-file commit $R && git repack -a -d && test_must_fail git cat-file commit $R && git fetch ../ "refs/replace/*:refs/replace/*" && - git show HEAD~5 | grep "O Thor" && - git show $HASH2 | grep "O Thor" && + git show HEAD~5 >actual && + test_grep "O Thor" actual && + git show $HASH2 >actual && + test_grep "O Thor" actual && git cat-file commit $R ) ' @@ -169,13 +185,15 @@ test_expect_success '"git replace" listing and deleting' ' test_must_fail git replace --delete && test_must_fail git replace -l -d $HASH2 && git replace -d $HASH2 && - git show $HASH2 | grep "A U Thor" && + git show $HASH2 >actual && + test_grep "A U Thor" actual && test -z "$(git replace -l)" ' test_expect_success '"git replace" replacing' ' git replace $HASH2 $R && - git show $HASH2 | grep "O Thor" && + git show $HASH2 >actual && + test_grep "O Thor" actual && test_must_fail git replace $HASH2 $R && git replace -f $HASH2 $R && test_must_fail git replace -f && @@ -186,7 +204,8 @@ test_expect_success '"git replace" resolves sha1' ' SHORTHASH2=$(git rev-parse --short=8 $HASH2) && git replace -d $SHORTHASH2 && git replace $SHORTHASH2 $R && - git show $HASH2 | grep "O Thor" && + git show $HASH2 >actual && + test_grep "O Thor" actual && test_must_fail git replace $HASH2 $R && git replace -f $HASH2 $R && test_must_fail git replace --force && @@ -209,10 +228,12 @@ test_expect_success '"git replace" resolves sha1' ' # test_expect_success 'create parallel branch without the bug' ' git replace -d $HASH2 && - git show $HASH2 | grep "A U Thor" && + git show $HASH2 >actual && + test_grep "A U Thor" actual && git checkout $HASH1 && git cherry-pick $HASH2 && - git show $HASH5 | git apply && + git show $HASH5 >actual && + git apply actual && git commit --amend -m "hello: 4 more lines WITHOUT the bug" hello && PARA2=$(git rev-parse --verify HEAD) && git cherry-pick $HASH3 && @@ -225,7 +246,8 @@ test_expect_success 'create parallel branch without the bug' ' git checkout main && cur=$(git rev-parse --verify HEAD) && test "$cur" = "$HASH7" && - git log --pretty=oneline | grep $PARA2 && + git log --pretty=oneline >actual && + test_grep $PARA2 actual && git remote add cloned ./clone_dir ' @@ -234,23 +256,30 @@ test_expect_success 'push to cloned repo' ' ( cd clone_dir && git checkout parallel && - git log --pretty=oneline | grep $PARA2 + git log --pretty=oneline >actual && + test_grep $PARA2 actual ) ' test_expect_success 'push branch with replacement' ' - git cat-file commit $PARA3 | grep "author A U Thor" && - S=$(git cat-file commit $PARA3 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) && - git cat-file commit $S | grep "author O Thor" && + git cat-file commit $PARA3 >actual && + test_grep "author A U Thor" actual && + S=$(sed -e "s/A U/O/" actual | git hash-object -t commit --stdin -w) && + git cat-file commit $S >actual && + test_grep "author O Thor" actual && git replace $PARA3 $S && - git show $HASH6~2 | grep "O Thor" && - git show $PARA3 | grep "O Thor" && + git show $HASH6~2 >actual && + test_grep "O Thor" actual && + git show $PARA3 >actual && + test_grep "O Thor" actual && git push cloned $HASH6^:refs/heads/parallel2 && ( cd clone_dir && git checkout parallel2 && - git log --pretty=oneline | grep $PARA3 && - git show $PARA3 | grep "A U Thor" + git log --pretty=oneline >actual && + test_grep $PARA3 actual && + git show $PARA3 >actual && + test_grep "A U Thor" actual ) ' @@ -260,14 +289,14 @@ test_expect_success 'fetch branch with replacement' ' cd clone_dir && git fetch origin refs/heads/tofetch:refs/heads/parallel3 && git log --pretty=oneline parallel3 >output.txt && - ! grep $PARA3 output.txt && + test_grep ! $PARA3 output.txt && git show $PARA3 >para3.txt && - grep "A U Thor" para3.txt && + test_grep "A U Thor" para3.txt && git fetch origin "refs/replace/*:refs/replace/*" && git log --pretty=oneline parallel3 >output.txt && - grep $PARA3 output.txt && + test_grep $PARA3 output.txt && git show $PARA3 >para3.txt && - grep "O Thor" para3.txt + test_grep "O Thor" para3.txt ) ' @@ -284,8 +313,8 @@ test_expect_success 'bisect and replacements' ' ' test_expect_success 'index-pack and replacements' ' - git --no-replace-objects rev-list --objects HEAD | - git --no-replace-objects pack-objects test- && + git --no-replace-objects rev-list --objects HEAD >actual && + git --no-replace-objects pack-objects test- <actual && git index-pack test-*.pack ' @@ -319,7 +348,8 @@ test_expect_success '-f option bypasses the type check' ' ' test_expect_success 'git cat-file --batch works on replace objects' ' - git replace | grep $PARA3 && + git replace >actual && + test_grep $PARA3 actual && echo $PARA3 | git cat-file --batch ' @@ -344,7 +374,8 @@ test_expect_success 'test --format medium' ' echo "$PARA3 -> $S" && echo "$MYTAG -> $HASH1" } | sort >expected && - git replace -l --format medium | sort >actual && + git replace -l --format medium >output && + sort output >actual && test_cmp expected actual ' @@ -356,7 +387,8 @@ test_expect_success 'test --format long' ' echo "$PARA3 (commit) -> $S (commit)" && echo "$MYTAG (tag) -> $HASH1 (commit)" } | sort >expected && - git replace --format=long | sort >actual && + git replace --format=long >output && + sort output >actual && test_cmp expected actual ' @@ -374,12 +406,16 @@ test_expect_success 'setup fake editors' ' test_expect_success '--edit with and without already replaced object' ' test_must_fail env GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && GIT_EDITOR=./fakeeditor git replace --force --edit "$PARA3" && - git replace -l | grep "$PARA3" && - git cat-file commit "$PARA3" | grep "A fake Thor" && + git replace -l >actual && + test_grep "$PARA3" actual && + git cat-file commit "$PARA3" >actual && + test_grep "A fake Thor" actual && git replace -d "$PARA3" && GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && - git replace -l | grep "$PARA3" && - git cat-file commit "$PARA3" | grep "A fake Thor" + git replace -l >actual && + test_grep "$PARA3" actual && + git cat-file commit "$PARA3" >actual && + test_grep "A fake Thor" actual ' test_expect_success '--edit and change nothing or command failed' ' @@ -387,8 +423,10 @@ test_expect_success '--edit and change nothing or command failed' ' test_must_fail env GIT_EDITOR=true git replace --edit "$PARA3" && test_must_fail env GIT_EDITOR="./failingfakeeditor" git replace --edit "$PARA3" && GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && - git replace -l | grep "$PARA3" && - git cat-file commit "$PARA3" | grep "A fake Thor" + git replace -l >actual && + test_grep "$PARA3" actual && + git cat-file commit "$PARA3" >actual && + test_grep "A fake Thor" actual ' test_expect_success 'replace ref cleanup' ' @@ -468,7 +506,8 @@ test_expect_success GPG 'set up a merge commit with a mergetag' ' git checkout main && git merge -s ours test_tag && HASH10=$(git rev-parse --verify HEAD) && - git cat-file commit $HASH10 | grep "^mergetag object" + git cat-file commit $HASH10 >actual && + test_grep "^mergetag object" actual ' test_expect_success GPG '--graft on a commit with a mergetag' ' diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 5c97eb0dfe..54fed91e39 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -747,7 +747,7 @@ test_expect_success MINGW 'handle clean & core.longpaths = false nicely' ' test_must_fail git clean -xdf 2>.git/err && # grepping for a strerror string is unportable but it is OK here with # MINGW prereq - test_grep "too long" .git/err + test_grep -e "too long" -e "No such file or directory" .git/err ' test_expect_success 'clean untracked paths by pathspec' ' diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c index 54c26c43e7..2ddf480588 100644 --- a/t/unit-tests/lib-reftable.c +++ b/t/unit-tests/lib-reftable.c @@ -19,7 +19,7 @@ static int strbuf_writer_flush(void *arg UNUSED) return 0; } -struct reftable_writer *t_reftable_strbuf_writer(struct strbuf *buf, +struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf, struct reftable_write_options *opts) { struct reftable_writer *writer; @@ -29,7 +29,7 @@ struct reftable_writer *t_reftable_strbuf_writer(struct strbuf *buf, return writer; } -void t_reftable_write_to_buf(struct strbuf *buf, +void t_reftable_write_to_buf(struct reftable_buf *buf, struct reftable_ref_record *refs, size_t nrefs, struct reftable_log_record *logs, diff --git a/t/unit-tests/lib-reftable.h b/t/unit-tests/lib-reftable.h index d115419084..d4950fed3d 100644 --- a/t/unit-tests/lib-reftable.h +++ b/t/unit-tests/lib-reftable.h @@ -2,15 +2,16 @@ #define LIB_REFTABLE_H #include "git-compat-util.h" -#include "strbuf.h" #include "reftable/reftable-writer.h" +struct reftable_buf; + void t_reftable_set_hash(uint8_t *p, int i, uint32_t id); -struct reftable_writer *t_reftable_strbuf_writer(struct strbuf *buf, +struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf, struct reftable_write_options *opts); -void t_reftable_write_to_buf(struct strbuf *buf, +void t_reftable_write_to_buf(struct reftable_buf *buf, struct reftable_ref_record *refs, size_t nrecords, struct reftable_log_record *logs, diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c index 1fa77b6faf..65d50df091 100644 --- a/t/unit-tests/t-reftable-basics.c +++ b/t/unit-tests/t-reftable-basics.c @@ -54,7 +54,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) } } - if_test ("names_length retuns size of a NULL-terminated string array") { + if_test ("names_length returns size of a NULL-terminated string array") { const char *a[] = { "a", "b", NULL }; check_int(names_length(a), ==, 2); } @@ -99,8 +99,8 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) } if_test ("common_prefix_size works") { - struct strbuf a = STRBUF_INIT; - struct strbuf b = STRBUF_INIT; + struct reftable_buf a = REFTABLE_BUF_INIT; + struct reftable_buf b = REFTABLE_BUF_INIT; struct { const char *a, *b; int want; @@ -113,14 +113,14 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) }; for (size_t i = 0; i < ARRAY_SIZE(cases); i++) { - strbuf_addstr(&a, cases[i].a); - strbuf_addstr(&b, cases[i].b); + check(!reftable_buf_addstr(&a, cases[i].a)); + check(!reftable_buf_addstr(&b, cases[i].b)); check_int(common_prefix_size(&a, &b), ==, cases[i].want); - strbuf_reset(&a); - strbuf_reset(&b); + reftable_buf_reset(&a); + reftable_buf_reset(&b); } - strbuf_release(&a); - strbuf_release(&b); + reftable_buf_release(&a); + reftable_buf_release(&b); } if_test ("put_be24 and get_be24 work") { diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c index d470060e8b..f9af907117 100644 --- a/t/unit-tests/t-reftable-block.c +++ b/t/unit-tests/t-reftable-block.c @@ -20,7 +20,7 @@ static void t_ref_block_read_write(void) const size_t block_size = 1024; struct reftable_block block = { 0 }; struct block_writer bw = { - .last_key = STRBUF_INIT, + .last_key = REFTABLE_BUF_INIT, }; struct reftable_record rec = { .type = BLOCK_TYPE_REF, @@ -29,12 +29,12 @@ static void t_ref_block_read_write(void) int ret; struct block_reader br = { 0 }; struct block_iter it = BLOCK_ITER_INIT; - struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block.data, block_size); check(block.data != NULL); block.len = block_size; - block_source_from_strbuf(&block.source ,&buf); + block_source_from_buf(&block.source ,&buf); ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size, header_off, hash_size(GIT_SHA1_FORMAT_ID)); check(!ret); @@ -100,8 +100,8 @@ static void t_ref_block_read_write(void) block_iter_close(&it); reftable_record_release(&rec); reftable_block_done(&br.block); - strbuf_release(&want); - strbuf_release(&buf); + reftable_buf_release(&want); + reftable_buf_release(&buf); for (i = 0; i < N; i++) reftable_record_release(&recs[i]); } @@ -114,7 +114,7 @@ static void t_log_block_read_write(void) const size_t block_size = 2048; struct reftable_block block = { 0 }; struct block_writer bw = { - .last_key = STRBUF_INIT, + .last_key = REFTABLE_BUF_INIT, }; struct reftable_record rec = { .type = BLOCK_TYPE_LOG, @@ -123,12 +123,12 @@ static void t_log_block_read_write(void) int ret; struct block_reader br = { 0 }; struct block_iter it = BLOCK_ITER_INIT; - struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block.data, block_size); check(block.data != NULL); block.len = block_size; - block_source_from_strbuf(&block.source ,&buf); + block_source_from_buf(&block.source ,&buf); ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size, header_off, hash_size(GIT_SHA1_FORMAT_ID)); check(!ret); @@ -166,8 +166,8 @@ static void t_log_block_read_write(void) for (i = 0; i < N; i++) { block_iter_reset(&it); - strbuf_reset(&want); - strbuf_addstr(&want, recs[i].u.log.refname); + reftable_buf_reset(&want); + check(!reftable_buf_addstr(&want, recs[i].u.log.refname)); ret = block_iter_seek_key(&it, &br, &want); check_int(ret, ==, 0); @@ -190,8 +190,8 @@ static void t_log_block_read_write(void) block_iter_close(&it); reftable_record_release(&rec); reftable_block_done(&br.block); - strbuf_release(&want); - strbuf_release(&buf); + reftable_buf_release(&want); + reftable_buf_release(&buf); for (i = 0; i < N; i++) reftable_record_release(&recs[i]); } @@ -204,7 +204,7 @@ static void t_obj_block_read_write(void) const size_t block_size = 1024; struct reftable_block block = { 0 }; struct block_writer bw = { - .last_key = STRBUF_INIT, + .last_key = REFTABLE_BUF_INIT, }; struct reftable_record rec = { .type = BLOCK_TYPE_OBJ, @@ -213,12 +213,12 @@ static void t_obj_block_read_write(void) int ret; struct block_reader br = { 0 }; struct block_iter it = BLOCK_ITER_INIT; - struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block.data, block_size); check(block.data != NULL); block.len = block_size; - block_source_from_strbuf(&block.source, &buf); + block_source_from_buf(&block.source, &buf); ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size, header_off, hash_size(GIT_SHA1_FORMAT_ID)); check(!ret); @@ -273,8 +273,8 @@ static void t_obj_block_read_write(void) block_iter_close(&it); reftable_record_release(&rec); reftable_block_done(&br.block); - strbuf_release(&want); - strbuf_release(&buf); + reftable_buf_release(&want); + reftable_buf_release(&buf); for (i = 0; i < N; i++) reftable_record_release(&recs[i]); } @@ -287,31 +287,34 @@ static void t_index_block_read_write(void) const size_t block_size = 1024; struct reftable_block block = { 0 }; struct block_writer bw = { - .last_key = STRBUF_INIT, + .last_key = REFTABLE_BUF_INIT, }; struct reftable_record rec = { .type = BLOCK_TYPE_INDEX, - .u.idx.last_key = STRBUF_INIT, + .u.idx.last_key = REFTABLE_BUF_INIT, }; size_t i = 0; int ret; struct block_reader br = { 0 }; struct block_iter it = BLOCK_ITER_INIT; - struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block.data, block_size); check(block.data != NULL); block.len = block_size; - block_source_from_strbuf(&block.source, &buf); + block_source_from_buf(&block.source, &buf); ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size, header_off, hash_size(GIT_SHA1_FORMAT_ID)); check(!ret); for (i = 0; i < N; i++) { - strbuf_init(&recs[i].u.idx.last_key, 9); + char buf[128]; + snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i); + + reftable_buf_init(&recs[i].u.idx.last_key); recs[i].type = BLOCK_TYPE_INDEX; - strbuf_addf(&recs[i].u.idx.last_key, "branch%02"PRIuMAX, (uintmax_t)i); + check(!reftable_buf_addstr(&recs[i].u.idx.last_key, buf)); recs[i].u.idx.offset = i; ret = block_writer_add(&bw, &recs[i]); @@ -362,8 +365,8 @@ static void t_index_block_read_write(void) block_iter_close(&it); reftable_record_release(&rec); reftable_block_done(&br.block); - strbuf_release(&want); - strbuf_release(&buf); + reftable_buf_release(&want); + reftable_buf_release(&buf); for (i = 0; i < N; i++) reftable_record_release(&recs[i]); } diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c index 3c84363e98..4c25ee5334 100644 --- a/t/unit-tests/t-reftable-merged.c +++ b/t/unit-tests/t-reftable-merged.c @@ -20,7 +20,7 @@ static struct reftable_merged_table * merged_table_from_records(struct reftable_ref_record **refs, struct reftable_block_source **source, struct reftable_reader ***readers, const size_t *sizes, - struct strbuf *buf, const size_t n) + struct reftable_buf *buf, const size_t n) { struct reftable_merged_table *mt = NULL; struct reftable_write_options opts = { @@ -35,7 +35,7 @@ merged_table_from_records(struct reftable_ref_record **refs, for (size_t i = 0; i < n; i++) { t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts); - block_source_from_strbuf(&(*source)[i], &buf[i]); + block_source_from_buf(&(*source)[i], &buf[i]); err = reftable_reader_new(&(*readers)[i], &(*source)[i], "name"); @@ -75,7 +75,7 @@ static void t_merged_single_record(void) struct reftable_ref_record *refs[] = { r1, r2, r3 }; size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; - struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; + struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; struct reftable_block_source *bs = NULL; struct reftable_reader **readers = NULL; struct reftable_merged_table *mt = @@ -97,7 +97,7 @@ static void t_merged_single_record(void) readers_destroy(readers, 3); reftable_merged_table_free(mt); for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) - strbuf_release(&bufs[i]); + reftable_buf_release(&bufs[i]); reftable_free(bs); } @@ -152,7 +152,7 @@ static void t_merged_refs(void) struct reftable_ref_record *refs[] = { r1, r2, r3 }; size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; - struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; + struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; struct reftable_block_source *bs = NULL; struct reftable_reader **readers = NULL; struct reftable_merged_table *mt = @@ -192,7 +192,7 @@ static void t_merged_refs(void) reftable_free(out); for (i = 0; i < 3; i++) - strbuf_release(&bufs[i]); + reftable_buf_release(&bufs[i]); readers_destroy(readers, 3); reftable_merged_table_free(mt); reftable_free(bs); @@ -234,8 +234,8 @@ static void t_merged_seek_multiple_times(void) size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), }; - struct strbuf bufs[] = { - STRBUF_INIT, STRBUF_INIT, + struct reftable_buf bufs[] = { + REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, }; struct reftable_block_source *sources = NULL; struct reftable_reader **readers = NULL; @@ -265,7 +265,7 @@ static void t_merged_seek_multiple_times(void) } for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) - strbuf_release(&bufs[i]); + reftable_buf_release(&bufs[i]); readers_destroy(readers, ARRAY_SIZE(refs)); reftable_ref_record_release(&rec); reftable_iterator_destroy(&it); @@ -277,7 +277,7 @@ static struct reftable_merged_table * merged_table_from_log_records(struct reftable_log_record **logs, struct reftable_block_source **source, struct reftable_reader ***readers, const size_t *sizes, - struct strbuf *buf, const size_t n) + struct reftable_buf *buf, const size_t n) { struct reftable_merged_table *mt = NULL; struct reftable_write_options opts = { @@ -293,7 +293,7 @@ merged_table_from_log_records(struct reftable_log_record **logs, for (size_t i = 0; i < n; i++) { t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts); - block_source_from_strbuf(&(*source)[i], &buf[i]); + block_source_from_buf(&(*source)[i], &buf[i]); err = reftable_reader_new(&(*readers)[i], &(*source)[i], "name"); @@ -361,7 +361,7 @@ static void t_merged_logs(void) struct reftable_log_record *logs[] = { r1, r2, r3 }; size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; - struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; + struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; struct reftable_block_source *bs = NULL; struct reftable_reader **readers = NULL; struct reftable_merged_table *mt = merged_table_from_log_records( @@ -412,7 +412,7 @@ static void t_merged_logs(void) reftable_free(out); for (i = 0; i < 3; i++) - strbuf_release(&bufs[i]); + reftable_buf_release(&bufs[i]); readers_destroy(readers, 3); reftable_merged_table_free(mt); reftable_free(bs); @@ -421,7 +421,7 @@ static void t_merged_logs(void) static void t_default_write_opts(void) { struct reftable_write_options opts = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record rec = { .refname = (char *) "master", @@ -442,7 +442,7 @@ static void t_default_write_opts(void) check(!err); reftable_writer_free(w); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&rd, &source, "filename"); check(!err); @@ -457,7 +457,7 @@ static void t_default_write_opts(void) reftable_reader_decref(rd); reftable_merged_table_free(merged); - strbuf_release(&buf); + reftable_buf_release(&buf); } @@ -467,7 +467,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) TEST(t_merged_logs(), "merged table with multiple log updates for same ref"); TEST(t_merged_refs(), "merged table with multiple updates to same ref"); TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times"); - TEST(t_merged_single_record(), "ref ocurring in only one record can be fetched"); + TEST(t_merged_single_record(), "ref occurring in only one record can be fetched"); return test_done(); } diff --git a/t/unit-tests/t-reftable-reader.c b/t/unit-tests/t-reftable-reader.c index eea86966c0..19cb53b641 100644 --- a/t/unit-tests/t-reftable-reader.c +++ b/t/unit-tests/t-reftable-reader.c @@ -16,11 +16,11 @@ static int t_reader_seek_once(void) struct reftable_ref_record ref = { 0 }; struct reftable_iterator it = { 0 }; struct reftable_reader *reader; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; int ret; t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); ret = reftable_reader_new(&reader, &source, "name"); check(!ret); @@ -40,7 +40,7 @@ static int t_reader_seek_once(void) reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); reftable_reader_decref(reader); - strbuf_release(&buf); + reftable_buf_release(&buf); return 0; } @@ -57,11 +57,11 @@ static int t_reader_reseek(void) struct reftable_ref_record ref = { 0 }; struct reftable_iterator it = { 0 }; struct reftable_reader *reader; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; int ret; t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); ret = reftable_reader_new(&reader, &source, "name"); check(!ret); @@ -84,7 +84,7 @@ static int t_reader_reseek(void) reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); reftable_reader_decref(reader); - strbuf_release(&buf); + reftable_buf_release(&buf); return 0; } diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c index 27ce84445e..d279b86df0 100644 --- a/t/unit-tests/t-reftable-readwrite.c +++ b/t/unit-tests/t-reftable-readwrite.c @@ -18,13 +18,13 @@ static const int update_index = 5; static void t_buffer(void) { - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; struct reftable_block out = { 0 }; int n; uint8_t in[] = "hello"; - strbuf_add(&buf, in, sizeof(in)); - block_source_from_strbuf(&source, &buf); + check(!reftable_buf_add(&buf, in, sizeof(in))); + block_source_from_buf(&source, &buf); check_int(block_source_size(&source), ==, 6); n = block_source_read_block(&source, &out, 0, sizeof(in)); check_int(n, ==, sizeof(in)); @@ -37,10 +37,10 @@ static void t_buffer(void) reftable_block_done(&out); block_source_close(&source); - strbuf_release(&buf); + reftable_buf_release(&buf); } -static void write_table(char ***names, struct strbuf *buf, int N, +static void write_table(char ***names, struct reftable_buf *buf, int N, int block_size, uint32_t hash_id) { struct reftable_write_options opts = { @@ -82,7 +82,7 @@ static void write_table(char ***names, struct strbuf *buf, int N, static void t_log_buffer_size(void) { - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_write_options opts = { .block_size = 4096, }; @@ -114,12 +114,12 @@ static void t_log_buffer_size(void) err = reftable_writer_close(w); check(!err); reftable_writer_free(w); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_log_overflow(void) { - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; char msg[256] = { 0 }; struct reftable_write_options opts = { .block_size = ARRAY_SIZE(msg), @@ -148,7 +148,7 @@ static void t_log_overflow(void) err = reftable_writer_add_log(w, &log); check_int(err, ==, REFTABLE_ENTRY_TOO_BIG_ERROR); reftable_writer_free(w); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_log_write_read(void) @@ -161,7 +161,7 @@ static void t_log_write_read(void) struct reftable_iterator it = { 0 }; struct reftable_reader *reader; struct reftable_block_source source = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); const struct reftable_stats *stats = NULL; int N = 2, err, i, n; @@ -207,7 +207,7 @@ static void t_log_write_read(void) reftable_writer_free(w); w = NULL; - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.log"); check(!err); @@ -247,7 +247,7 @@ static void t_log_write_read(void) reftable_iterator_destroy(&it); /* cleanup. */ - strbuf_release(&buf); + reftable_buf_release(&buf); free_names(names); reftable_reader_decref(reader); } @@ -260,7 +260,7 @@ static void t_log_zlib_corruption(void) struct reftable_iterator it = { 0 }; struct reftable_reader *reader; struct reftable_block_source source = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); const struct reftable_stats *stats = NULL; char message[100] = { 0 }; @@ -298,7 +298,7 @@ static void t_log_zlib_corruption(void) /* corrupt the data. */ buf.buf[50] ^= 0x99; - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.log"); check(!err); @@ -312,13 +312,13 @@ static void t_log_zlib_corruption(void) /* cleanup. */ reftable_reader_decref(reader); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_table_read_write_sequential(void) { char **names; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; int N = 50; struct reftable_iterator it = { 0 }; struct reftable_block_source source = { 0 }; @@ -328,7 +328,7 @@ static void t_table_read_write_sequential(void) write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.ref"); check(!err); @@ -352,25 +352,25 @@ static void t_table_read_write_sequential(void) reftable_iterator_destroy(&it); reftable_reader_decref(reader); - strbuf_release(&buf); + reftable_buf_release(&buf); free_names(names); } static void t_table_write_small_table(void) { char **names; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; int N = 1; write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID); check_int(buf.len, <, 200); - strbuf_release(&buf); + reftable_buf_release(&buf); free_names(names); } static void t_table_read_api(void) { char **names; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; int N = 50; struct reftable_reader *reader; struct reftable_block_source source = { 0 }; @@ -380,7 +380,7 @@ static void t_table_read_api(void) write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.ref"); check(!err); @@ -393,17 +393,17 @@ static void t_table_read_api(void) err = reftable_iterator_next_log(&it, &log); check_int(err, ==, REFTABLE_API_ERROR); - strbuf_release(&buf); + reftable_buf_release(&buf); free_names(names); reftable_iterator_destroy(&it); reftable_reader_decref(reader); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_table_read_write_seek(int index, int hash_id) { char **names; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; int N = 50; struct reftable_reader *reader; struct reftable_block_source source = { 0 }; @@ -411,12 +411,12 @@ static void t_table_read_write_seek(int index, int hash_id) int i = 0; struct reftable_iterator it = { 0 }; - struct strbuf pastLast = STRBUF_INIT; + struct reftable_buf pastLast = REFTABLE_BUF_INIT; struct reftable_ref_record ref = { 0 }; write_table(&names, &buf, N, 256, hash_id); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.ref"); check(!err); @@ -443,8 +443,8 @@ static void t_table_read_write_seek(int index, int hash_id) reftable_iterator_destroy(&it); } - strbuf_addstr(&pastLast, names[N - 1]); - strbuf_addstr(&pastLast, "/"); + check(!reftable_buf_addstr(&pastLast, names[N - 1])); + check(!reftable_buf_addstr(&pastLast, "/")); err = reftable_reader_init_ref_iterator(reader, &it); check(!err); @@ -457,10 +457,10 @@ static void t_table_read_write_seek(int index, int hash_id) check_int(err, >, 0); } - strbuf_release(&pastLast); + reftable_buf_release(&pastLast); reftable_iterator_destroy(&it); - strbuf_release(&buf); + reftable_buf_release(&buf); free_names(names); reftable_reader_decref(reader); } @@ -492,7 +492,7 @@ static void t_table_refs_for(int indexed) struct reftable_ref_record ref = { 0 }; struct reftable_reader *reader; struct reftable_block_source source = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_iterator it = { 0 }; int N = 50, n, j, err, i; @@ -538,7 +538,7 @@ static void t_table_refs_for(int indexed) reftable_writer_free(w); w = NULL; - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.ref"); check(!err); @@ -565,7 +565,7 @@ static void t_table_refs_for(int indexed) } check_int(j, ==, want_names_len); - strbuf_release(&buf); + reftable_buf_release(&buf); free_names(want_names); reftable_iterator_destroy(&it); reftable_reader_decref(reader); @@ -584,7 +584,7 @@ static void t_table_refs_for_obj_index(void) static void t_write_empty_table(void) { struct reftable_write_options opts = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_block_source source = { 0 }; struct reftable_reader *rd = NULL; @@ -600,7 +600,7 @@ static void t_write_empty_table(void) check_int(buf.len, ==, header_size(1) + footer_size(1)); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&rd, &source, "filename"); check(!err); @@ -615,7 +615,7 @@ static void t_write_empty_table(void) reftable_iterator_destroy(&it); reftable_reader_decref(rd); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_write_object_id_min_length(void) @@ -623,7 +623,7 @@ static void t_write_object_id_min_length(void) struct reftable_write_options opts = { .block_size = 75, }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record ref = { .update_index = 1, @@ -649,7 +649,7 @@ static void t_write_object_id_min_length(void) check(!err); check_int(reftable_writer_stats(w)->object_id_len, ==, 2); reftable_writer_free(w); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_write_object_id_length(void) @@ -657,7 +657,7 @@ static void t_write_object_id_length(void) struct reftable_write_options opts = { .block_size = 75, }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record ref = { .update_index = 1, @@ -684,13 +684,13 @@ static void t_write_object_id_length(void) check(!err); check_int(reftable_writer_stats(w)->object_id_len, ==, 16); reftable_writer_free(w); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_write_empty_key(void) { struct reftable_write_options opts = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record ref = { .refname = (char *) "", @@ -706,13 +706,13 @@ static void t_write_empty_key(void) err = reftable_writer_close(w); check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR); reftable_writer_free(w); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_write_key_order(void) { struct reftable_write_options opts = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record refs[2] = { { @@ -745,7 +745,7 @@ static void t_write_key_order(void) reftable_writer_close(w); reftable_writer_free(w); - strbuf_release(&buf); + reftable_buf_release(&buf); } static void t_write_multiple_indices(void) @@ -753,12 +753,13 @@ static void t_write_multiple_indices(void) struct reftable_write_options opts = { .block_size = 100, }; - struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_buf writer_buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; struct reftable_iterator it = { 0 }; const struct reftable_stats *stats; struct reftable_writer *writer; struct reftable_reader *reader; + char buf[128]; int err, i; writer = t_reftable_strbuf_writer(&writer_buf, &opts); @@ -770,9 +771,8 @@ static void t_write_multiple_indices(void) .value.val1 = {i}, }; - strbuf_reset(&buf); - strbuf_addf(&buf, "refs/heads/%04d", i); - ref.refname = buf.buf, + snprintf(buf, sizeof(buf), "refs/heads/%04d", i); + ref.refname = buf; err = reftable_writer_add_ref(writer, &ref); check(!err); @@ -788,9 +788,8 @@ static void t_write_multiple_indices(void) }, }; - strbuf_reset(&buf); - strbuf_addf(&buf, "refs/heads/%04d", i); - log.refname = buf.buf, + snprintf(buf, sizeof(buf), "refs/heads/%04d", i); + log.refname = buf; err = reftable_writer_add_log(writer, &log); check(!err); @@ -807,7 +806,7 @@ static void t_write_multiple_indices(void) check_int(stats->obj_stats.index_offset, >, 0); check_int(stats->log_stats.index_offset, >, 0); - block_source_from_strbuf(&source, &writer_buf); + block_source_from_buf(&source, &writer_buf); err = reftable_reader_new(&reader, &source, "filename"); check(!err); @@ -823,8 +822,7 @@ static void t_write_multiple_indices(void) reftable_iterator_destroy(&it); reftable_writer_free(writer); reftable_reader_decref(reader); - strbuf_release(&writer_buf); - strbuf_release(&buf); + reftable_buf_release(&writer_buf); } static void t_write_multi_level_index(void) @@ -832,7 +830,7 @@ static void t_write_multi_level_index(void) struct reftable_write_options opts = { .block_size = 100, }; - struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_buf writer_buf = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; struct reftable_iterator it = { 0 }; const struct reftable_stats *stats; @@ -848,10 +846,10 @@ static void t_write_multi_level_index(void) .value_type = REFTABLE_REF_VAL1, .value.val1 = {i}, }; + char buf[128]; - strbuf_reset(&buf); - strbuf_addf(&buf, "refs/heads/%03" PRIuMAX, (uintmax_t)i); - ref.refname = buf.buf, + snprintf(buf, sizeof(buf), "refs/heads/%03" PRIuMAX, (uintmax_t)i); + ref.refname = buf; err = reftable_writer_add_ref(writer, &ref); check(!err); @@ -865,7 +863,7 @@ static void t_write_multi_level_index(void) stats = reftable_writer_stats(writer); check_int(stats->ref_stats.max_index_level, ==, 2); - block_source_from_strbuf(&source, &writer_buf); + block_source_from_buf(&source, &writer_buf); err = reftable_reader_new(&reader, &source, "filename"); check(!err); @@ -880,18 +878,18 @@ static void t_write_multi_level_index(void) reftable_iterator_destroy(&it); reftable_writer_free(writer); reftable_reader_decref(reader); - strbuf_release(&writer_buf); - strbuf_release(&buf); + reftable_buf_release(&writer_buf); + reftable_buf_release(&buf); } static void t_corrupt_table_empty(void) { - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; struct reftable_reader *reader; int err; - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.log"); check_int(err, ==, REFTABLE_FORMAT_ERROR); } @@ -899,17 +897,17 @@ static void t_corrupt_table_empty(void) static void t_corrupt_table(void) { uint8_t zeros[1024] = { 0 }; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; struct reftable_reader *reader; int err; - strbuf_add(&buf, zeros, sizeof(zeros)); + check(!reftable_buf_add(&buf, zeros, sizeof(zeros))); - block_source_from_strbuf(&source, &buf); + block_source_from_buf(&source, &buf); err = reftable_reader_new(&reader, &source, "file.log"); check_int(err, ==, REFTABLE_FORMAT_ERROR); - strbuf_release(&buf); + reftable_buf_release(&buf); } int cmd_main(int argc UNUSED, const char *argv[] UNUSED) diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c index a7f67d4d9f..eb98bf2da9 100644 --- a/t/unit-tests/t-reftable-record.c +++ b/t/unit-tests/t-reftable-record.c @@ -116,7 +116,7 @@ static void t_reftable_ref_record_compare_name(void) static void t_reftable_ref_record_roundtrip(void) { - struct strbuf scratch = STRBUF_INIT; + struct reftable_buf scratch = REFTABLE_BUF_INIT; for (int i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) { struct reftable_record in = { @@ -124,7 +124,7 @@ static void t_reftable_ref_record_roundtrip(void) .u.ref.value_type = i, }; struct reftable_record out = { .type = BLOCK_TYPE_REF }; - struct strbuf key = STRBUF_INIT; + struct reftable_buf key = REFTABLE_BUF_INIT; uint8_t buffer[1024] = { 0 }; struct string_view dest = { .buf = buffer, @@ -166,11 +166,11 @@ static void t_reftable_ref_record_roundtrip(void) GIT_SHA1_RAWSZ)); reftable_record_release(&in); - strbuf_release(&key); + reftable_buf_release(&key); reftable_record_release(&out); } - strbuf_release(&scratch); + reftable_buf_release(&scratch); } static void t_reftable_log_record_comparison(void) @@ -262,7 +262,7 @@ static void t_reftable_log_record_roundtrip(void) .value_type = REFTABLE_LOG_UPDATE, } }; - struct strbuf scratch = STRBUF_INIT; + struct reftable_buf scratch = REFTABLE_BUF_INIT; set_hash(in[0].value.update.new_hash, 1); set_hash(in[0].value.update.old_hash, 2); set_hash(in[2].value.update.new_hash, 3); @@ -274,7 +274,7 @@ static void t_reftable_log_record_roundtrip(void) for (size_t i = 0; i < ARRAY_SIZE(in); i++) { struct reftable_record rec = { .type = BLOCK_TYPE_LOG }; - struct strbuf key = STRBUF_INIT; + struct reftable_buf key = REFTABLE_BUF_INIT; uint8_t buffer[1024] = { 0 }; struct string_view dest = { .buf = buffer, @@ -313,11 +313,11 @@ static void t_reftable_log_record_roundtrip(void) check(reftable_log_record_equal(&in[i], &out.u.log, GIT_SHA1_RAWSZ)); reftable_log_record_release(&in[i]); - strbuf_release(&key); + reftable_buf_release(&key); reftable_record_release(&out); } - strbuf_release(&scratch); + reftable_buf_release(&scratch); } static void t_key_roundtrip(void) @@ -327,30 +327,30 @@ static void t_key_roundtrip(void) .buf = buffer, .len = sizeof(buffer), }; - struct strbuf last_key = STRBUF_INIT; - struct strbuf key = STRBUF_INIT; - struct strbuf roundtrip = STRBUF_INIT; + struct reftable_buf last_key = REFTABLE_BUF_INIT; + struct reftable_buf key = REFTABLE_BUF_INIT; + struct reftable_buf roundtrip = REFTABLE_BUF_INIT; int restart; uint8_t extra; int n, m; uint8_t rt_extra; - strbuf_addstr(&last_key, "refs/heads/master"); - strbuf_addstr(&key, "refs/tags/bla"); + check(!reftable_buf_addstr(&last_key, "refs/heads/master")); + check(!reftable_buf_addstr(&key, "refs/tags/bla")); extra = 6; n = reftable_encode_key(&restart, dest, last_key, key, extra); check(!restart); check_int(n, >, 0); - strbuf_addstr(&roundtrip, "refs/heads/master"); + check(!reftable_buf_addstr(&roundtrip, "refs/heads/master")); m = reftable_decode_key(&roundtrip, &rt_extra, dest); check_int(n, ==, m); - check(!strbuf_cmp(&key, &roundtrip)); + check(!reftable_buf_cmp(&key, &roundtrip)); check_int(rt_extra, ==, extra); - strbuf_release(&last_key); - strbuf_release(&key); - strbuf_release(&roundtrip); + reftable_buf_release(&last_key); + reftable_buf_release(&key); + reftable_buf_release(&roundtrip); } static void t_reftable_obj_record_comparison(void) @@ -413,7 +413,7 @@ static void t_reftable_obj_record_roundtrip(void) .hash_prefix_len = 5, }, }; - struct strbuf scratch = STRBUF_INIT; + struct reftable_buf scratch = REFTABLE_BUF_INIT; for (size_t i = 0; i < ARRAY_SIZE(recs); i++) { uint8_t buffer[1024] = { 0 }; @@ -427,7 +427,7 @@ static void t_reftable_obj_record_roundtrip(void) .obj = recs[i], }, }; - struct strbuf key = STRBUF_INIT; + struct reftable_buf key = REFTABLE_BUF_INIT; struct reftable_record out = { .type = BLOCK_TYPE_OBJ }; int n, m; uint8_t extra; @@ -443,11 +443,11 @@ static void t_reftable_obj_record_roundtrip(void) check_int(n, ==, m); check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); - strbuf_release(&key); + reftable_buf_release(&key); reftable_record_release(&out); } - strbuf_release(&scratch); + reftable_buf_release(&scratch); } static void t_reftable_index_record_comparison(void) @@ -456,22 +456,22 @@ static void t_reftable_index_record_comparison(void) { .type = BLOCK_TYPE_INDEX, .u.idx.offset = 22, - .u.idx.last_key = STRBUF_INIT, + .u.idx.last_key = REFTABLE_BUF_INIT, }, { .type = BLOCK_TYPE_INDEX, .u.idx.offset = 32, - .u.idx.last_key = STRBUF_INIT, + .u.idx.last_key = REFTABLE_BUF_INIT, }, { .type = BLOCK_TYPE_INDEX, .u.idx.offset = 32, - .u.idx.last_key = STRBUF_INIT, + .u.idx.last_key = REFTABLE_BUF_INIT, }, }; - strbuf_addstr(&in[0].u.idx.last_key, "refs/heads/master"); - strbuf_addstr(&in[1].u.idx.last_key, "refs/heads/master"); - strbuf_addstr(&in[2].u.idx.last_key, "refs/heads/branch"); + check(!reftable_buf_addstr(&in[0].u.idx.last_key, "refs/heads/master")); + check(!reftable_buf_addstr(&in[1].u.idx.last_key, "refs/heads/master")); + check(!reftable_buf_addstr(&in[2].u.idx.last_key, "refs/heads/branch")); check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); check(!reftable_record_cmp(&in[0], &in[1])); @@ -493,7 +493,7 @@ static void t_reftable_index_record_roundtrip(void) .type = BLOCK_TYPE_INDEX, .u.idx = { .offset = 42, - .last_key = STRBUF_INIT, + .last_key = REFTABLE_BUF_INIT, }, }; uint8_t buffer[1024] = { 0 }; @@ -501,21 +501,21 @@ static void t_reftable_index_record_roundtrip(void) .buf = buffer, .len = sizeof(buffer), }; - struct strbuf scratch = STRBUF_INIT; - struct strbuf key = STRBUF_INIT; + struct reftable_buf scratch = REFTABLE_BUF_INIT; + struct reftable_buf key = REFTABLE_BUF_INIT; struct reftable_record out = { .type = BLOCK_TYPE_INDEX, - .u.idx = { .last_key = STRBUF_INIT }, + .u.idx = { .last_key = REFTABLE_BUF_INIT }, }; int n, m; uint8_t extra; - strbuf_addstr(&in.u.idx.last_key, "refs/heads/master"); + check(!reftable_buf_addstr(&in.u.idx.last_key, "refs/heads/master")); reftable_record_key(&in, &key); t_copy(&in); check(!reftable_record_is_deletion(&in)); - check(!strbuf_cmp(&key, &in.u.idx.last_key)); + check(!reftable_buf_cmp(&key, &in.u.idx.last_key)); n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); check_int(n, >, 0); @@ -527,9 +527,9 @@ static void t_reftable_index_record_roundtrip(void) check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); reftable_record_release(&out); - strbuf_release(&key); - strbuf_release(&scratch); - strbuf_release(&in.u.idx.last_key); + reftable_buf_release(&key); + reftable_buf_release(&scratch); + reftable_buf_release(&in.u.idx.last_key); } int cmd_main(int argc UNUSED, const char *argv[] UNUSED) diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c index 874095b9ee..72f6747064 100644 --- a/t/unit-tests/t-reftable-stack.c +++ b/t/unit-tests/t-reftable-stack.c @@ -16,7 +16,7 @@ https://developers.google.com/open-source/licenses/bsd static void clear_dir(const char *dirname) { - struct strbuf path = STRBUF_INIT; + struct strbuf path = REFTABLE_BUF_INIT; strbuf_addstr(&path, dirname); remove_dir_recursively(&path, 0); strbuf_release(&path); @@ -105,7 +105,6 @@ static int write_test_ref(struct reftable_writer *wr, void *arg) static void write_n_ref_tables(struct reftable_stack *st, size_t n) { - struct strbuf buf = STRBUF_INIT; int disable_auto_compact; int err; @@ -117,10 +116,10 @@ static void write_n_ref_tables(struct reftable_stack *st, .update_index = reftable_stack_next_update_index(st), .value_type = REFTABLE_REF_VAL1, }; + char buf[128]; - strbuf_reset(&buf); - strbuf_addf(&buf, "refs/heads/branch-%04"PRIuMAX, (uintmax_t)i); - ref.refname = buf.buf; + snprintf(buf, sizeof(buf), "refs/heads/branch-%04"PRIuMAX, (uintmax_t)i); + ref.refname = buf; t_reftable_set_hash(ref.value.val1, i, GIT_SHA1_FORMAT_ID); err = reftable_stack_add(st, &write_test_ref, &ref); @@ -128,7 +127,6 @@ static void write_n_ref_tables(struct reftable_stack *st, } st->opts.disable_auto_compact = disable_auto_compact; - strbuf_release(&buf); } struct write_log_arg { @@ -147,7 +145,7 @@ static int write_test_log(struct reftable_writer *wr, void *arg) static void t_reftable_stack_add_one(void) { char *dir = get_tmp_dir(__LINE__); - struct strbuf scratch = STRBUF_INIT; + struct reftable_buf scratch = REFTABLE_BUF_INIT; int mask = umask(002); struct reftable_write_options opts = { .default_permissions = 0660, @@ -174,17 +172,17 @@ static void t_reftable_stack_add_one(void) check_int(st->readers_len, >, 0); #ifndef GIT_WINDOWS_NATIVE - strbuf_addstr(&scratch, dir); - strbuf_addstr(&scratch, "/tables.list"); + check(!reftable_buf_addstr(&scratch, dir)); + check(!reftable_buf_addstr(&scratch, "/tables.list")); err = stat(scratch.buf, &stat_result); check(!err); check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); - strbuf_reset(&scratch); - strbuf_addstr(&scratch, dir); - strbuf_addstr(&scratch, "/"); + reftable_buf_reset(&scratch); + check(!reftable_buf_addstr(&scratch, dir)); + check(!reftable_buf_addstr(&scratch, "/")); /* do not try at home; not an external API for reftable. */ - strbuf_addstr(&scratch, st->readers[0]->name); + check(!reftable_buf_addstr(&scratch, st->readers[0]->name)); err = stat(scratch.buf, &stat_result); check(!err); check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); @@ -194,7 +192,7 @@ static void t_reftable_stack_add_one(void) reftable_ref_record_release(&dest); reftable_stack_destroy(st); - strbuf_release(&scratch); + reftable_buf_release(&scratch); clear_dir(dir); umask(mask); } @@ -416,7 +414,7 @@ static void t_reftable_stack_auto_compaction_fails_gracefully(void) }; struct reftable_write_options opts = { 0 }; struct reftable_stack *st; - struct strbuf table_path = STRBUF_INIT; + struct reftable_buf table_path = REFTABLE_BUF_INIT; char *dir = get_tmp_dir(__LINE__); int err; @@ -434,7 +432,10 @@ static void t_reftable_stack_auto_compaction_fails_gracefully(void) * Adding a new table to the stack should not be impacted by this, even * though auto-compaction will now fail. */ - strbuf_addf(&table_path, "%s/%s.lock", dir, st->readers[0]->name); + check(!reftable_buf_addstr(&table_path, dir)); + check(!reftable_buf_addstr(&table_path, "/")); + check(!reftable_buf_addstr(&table_path, st->readers[0]->name)); + check(!reftable_buf_addstr(&table_path, ".lock")); write_file_buf(table_path.buf, "", 0); ref.update_index = 2; @@ -445,7 +446,7 @@ static void t_reftable_stack_auto_compaction_fails_gracefully(void) check_int(st->stats.failures, ==, 1); reftable_stack_destroy(st); - strbuf_release(&table_path); + reftable_buf_release(&table_path); clear_dir(dir); } @@ -515,7 +516,7 @@ static void t_reftable_stack_add(void) char *dir = get_tmp_dir(__LINE__); struct reftable_ref_record refs[2] = { 0 }; struct reftable_log_record logs[2] = { 0 }; - struct strbuf path = STRBUF_INIT; + struct reftable_buf path = REFTABLE_BUF_INIT; struct stat stat_result; size_t i, N = ARRAY_SIZE(refs); @@ -574,17 +575,17 @@ static void t_reftable_stack_add(void) } #ifndef GIT_WINDOWS_NATIVE - strbuf_addstr(&path, dir); - strbuf_addstr(&path, "/tables.list"); + check(!reftable_buf_addstr(&path, dir)); + check(!reftable_buf_addstr(&path, "/tables.list")); err = stat(path.buf, &stat_result); check(!err); check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); - strbuf_reset(&path); - strbuf_addstr(&path, dir); - strbuf_addstr(&path, "/"); + reftable_buf_reset(&path); + check(!reftable_buf_addstr(&path, dir)); + check(!reftable_buf_addstr(&path, "/")); /* do not try at home; not an external API for reftable. */ - strbuf_addstr(&path, st->readers[0]->name); + check(!reftable_buf_addstr(&path, st->readers[0]->name)); err = stat(path.buf, &stat_result); check(!err); check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); @@ -598,7 +599,7 @@ static void t_reftable_stack_add(void) reftable_ref_record_release(&refs[i]); reftable_log_record_release(&logs[i]); } - strbuf_release(&path); + reftable_buf_release(&path); clear_dir(dir); } @@ -1062,7 +1063,7 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void) .disable_auto_compact = 1, }; struct reftable_stack *st = NULL; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; char *dir = get_tmp_dir(__LINE__); int err; @@ -1077,8 +1078,10 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void) * size, we expect that auto-compaction will want to compact all of the * tables. Locking any of the tables will keep it from doing so. */ - strbuf_reset(&buf); - strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[2]->name); + check(!reftable_buf_addstr(&buf, dir)); + check(!reftable_buf_addstr(&buf, "/")); + check(!reftable_buf_addstr(&buf, st->readers[2]->name)); + check(!reftable_buf_addstr(&buf, ".lock")); write_file_buf(buf.buf, "", 0); /* @@ -1093,7 +1096,7 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void) check_int(st->merged->readers_len, ==, 4); reftable_stack_destroy(st); - strbuf_release(&buf); + reftable_buf_release(&buf); clear_dir(dir); } @@ -1101,7 +1104,6 @@ static void t_reftable_stack_add_performs_auto_compaction(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; - struct strbuf refname = STRBUF_INIT; char *dir = get_tmp_dir(__LINE__); int err; size_t i, n = 20; @@ -1115,6 +1117,7 @@ static void t_reftable_stack_add_performs_auto_compaction(void) .value_type = REFTABLE_REF_SYMREF, .value.symref = (char *) "master", }; + char buf[128]; /* * Disable auto-compaction for all but the last runs. Like this @@ -1123,9 +1126,8 @@ static void t_reftable_stack_add_performs_auto_compaction(void) */ st->opts.disable_auto_compact = i != n; - strbuf_reset(&refname); - strbuf_addf(&refname, "branch-%04"PRIuMAX, (uintmax_t)i); - ref.refname = refname.buf; + snprintf(buf, sizeof(buf), "branch-%04"PRIuMAX, (uintmax_t)i); + ref.refname = buf; err = reftable_stack_add(st, write_test_ref, &ref); check(!err); @@ -1142,7 +1144,6 @@ static void t_reftable_stack_add_performs_auto_compaction(void) } reftable_stack_destroy(st); - strbuf_release(&refname); clear_dir(dir); } @@ -1152,7 +1153,7 @@ static void t_reftable_stack_compaction_with_locked_tables(void) .disable_auto_compact = 1, }; struct reftable_stack *st = NULL; - struct strbuf buf = STRBUF_INIT; + struct reftable_buf buf = REFTABLE_BUF_INIT; char *dir = get_tmp_dir(__LINE__); int err; @@ -1163,8 +1164,10 @@ static void t_reftable_stack_compaction_with_locked_tables(void) check_int(st->merged->readers_len, ==, 3); /* Lock one of the tables that we're about to compact. */ - strbuf_reset(&buf); - strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[1]->name); + check(!reftable_buf_addstr(&buf, dir)); + check(!reftable_buf_addstr(&buf, "/")); + check(!reftable_buf_addstr(&buf, st->readers[1]->name)); + check(!reftable_buf_addstr(&buf, ".lock")); write_file_buf(buf.buf, "", 0); /* @@ -1177,7 +1180,7 @@ static void t_reftable_stack_compaction_with_locked_tables(void) check_int(st->merged->readers_len, ==, 3); reftable_stack_destroy(st); - strbuf_release(&buf); + reftable_buf_release(&buf); clear_dir(dir); } @@ -1303,7 +1306,7 @@ static void t_reftable_stack_reload_with_missing_table(void) struct reftable_stack *st = NULL; struct reftable_ref_record rec = { 0 }; struct reftable_iterator it = { 0 }; - struct strbuf table_path = STRBUF_INIT, content = STRBUF_INIT; + struct reftable_buf table_path = REFTABLE_BUF_INIT, content = REFTABLE_BUF_INIT; char *dir = get_tmp_dir(__LINE__); int err; @@ -1321,10 +1324,13 @@ static void t_reftable_stack_reload_with_missing_table(void) * our old readers. This should trigger a partial reload of the stack, * where we try to reuse our old readers. */ - strbuf_addf(&content, "%s\n", st->readers[0]->name); - strbuf_addf(&content, "%s\n", st->readers[1]->name); - strbuf_addstr(&content, "garbage\n"); - strbuf_addf(&table_path, "%s.lock", st->list_file); + check(!reftable_buf_addstr(&content, st->readers[0]->name)); + check(!reftable_buf_addstr(&content, "\n")); + check(!reftable_buf_addstr(&content, st->readers[1]->name)); + check(!reftable_buf_addstr(&content, "\n")); + check(!reftable_buf_addstr(&content, "garbage\n")); + check(!reftable_buf_addstr(&table_path, st->list_file)); + check(!reftable_buf_addstr(&table_path, ".lock")); write_file_buf(table_path.buf, content.buf, content.len); err = rename(table_path.buf, st->list_file); check(!err); @@ -1349,8 +1355,8 @@ static void t_reftable_stack_reload_with_missing_table(void) reftable_ref_record_release(&rec); reftable_iterator_destroy(&it); reftable_stack_destroy(st); - strbuf_release(&table_path); - strbuf_release(&content); + reftable_buf_release(&table_path); + reftable_buf_release(&content); clear_dir(dir); } diff --git a/unpack-trees.c b/unpack-trees.c index 9a55cb6204..e10a9d1209 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -808,6 +808,8 @@ static int traverse_by_cache_tree(int pos, int nr_entries, int nr_names, if (!o->merge) BUG("We need cache-tree to do this optimization"); + if (nr_entries + pos > o->src_index->cache_nr) + return error(_("corrupted cache-tree has entries not present in index")); /* * Do what unpack_callback() and unpack_single_entry() normally @@ -2070,9 +2072,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options if (o->dst_index) { move_index_extensions(&o->internal.result, o->src_index); if (!ret) { - if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0)) - cache_tree_verify(the_repository, - &o->internal.result); + if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0) && + cache_tree_verify(the_repository, + &o->internal.result) < 0) { + ret = -1; + goto done; + } + if (!o->skip_cache_tree_update && !cache_tree_fully_valid(o->internal.result.cache_tree)) cache_tree_update(&o->internal.result, diff --git a/worktree.c b/worktree.c index 0f032ccedf..77ff484d3e 100644 --- a/worktree.c +++ b/worktree.c @@ -110,6 +110,12 @@ struct worktree *get_linked_worktree(const char *id, strbuf_rtrim(&worktree_path); strbuf_strip_suffix(&worktree_path, "/.git"); + if (!is_absolute_path(worktree_path.buf)) { + strbuf_strip_suffix(&path, "gitdir"); + strbuf_addbuf(&path, &worktree_path); + strbuf_realpath_forgiving(&worktree_path, path.buf, 0); + } + CALLOC_ARRAY(worktree, 1); worktree->repo = the_repository; worktree->path = strbuf_detach(&worktree_path, NULL); @@ -373,18 +379,29 @@ done: void update_worktree_location(struct worktree *wt, const char *path_) { struct strbuf path = STRBUF_INIT; + struct strbuf repo = STRBUF_INIT; + struct strbuf file = STRBUF_INIT; + struct strbuf tmp = STRBUF_INIT; if (is_main_worktree(wt)) BUG("can't relocate main worktree"); + strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1); strbuf_realpath(&path, path_, 1); if (fspathcmp(wt->path, path.buf)) { - write_file(git_common_path("worktrees/%s/gitdir", wt->id), - "%s/.git", path.buf); + strbuf_addf(&file, "%s/gitdir", repo.buf); + write_file(file.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp)); + strbuf_reset(&file); + strbuf_addf(&file, "%s/.git", path.buf); + write_file(file.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp)); + free(wt->path); wt->path = strbuf_detach(&path, NULL); } strbuf_release(&path); + strbuf_release(&repo); + strbuf_release(&file); + strbuf_release(&tmp); } int is_worktree_being_rebased(const struct worktree *wt, @@ -564,38 +581,52 @@ static void repair_gitfile(struct worktree *wt, { struct strbuf dotgit = STRBUF_INIT; struct strbuf repo = STRBUF_INIT; - char *backlink; + struct strbuf backlink = STRBUF_INIT; + struct strbuf tmp = STRBUF_INIT; + char *dotgit_contents = NULL; const char *repair = NULL; int err; /* missing worktree can't be repaired */ if (!file_exists(wt->path)) - return; + goto done; if (!is_directory(wt->path)) { fn(1, wt->path, _("not a directory"), cb_data); - return; + goto done; } strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1); strbuf_addf(&dotgit, "%s/.git", wt->path); - backlink = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err)); + dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err)); + + if (dotgit_contents) { + if (is_absolute_path(dotgit_contents)) { + strbuf_addstr(&backlink, dotgit_contents); + } else { + strbuf_addf(&backlink, "%s/%s", wt->path, dotgit_contents); + strbuf_realpath_forgiving(&backlink, backlink.buf, 0); + } + } if (err == READ_GITFILE_ERR_NOT_A_FILE) fn(1, wt->path, _(".git is not a file"), cb_data); else if (err) repair = _(".git file broken"); - else if (fspathcmp(backlink, repo.buf)) + else if (fspathcmp(backlink.buf, repo.buf)) repair = _(".git file incorrect"); if (repair) { fn(0, wt->path, repair, cb_data); - write_file(dotgit.buf, "gitdir: %s", repo.buf); + write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, wt->path, &tmp)); } - free(backlink); +done: + free(dotgit_contents); strbuf_release(&repo); strbuf_release(&dotgit); + strbuf_release(&backlink); + strbuf_release(&tmp); } static void repair_noop(int iserr UNUSED, @@ -618,6 +649,59 @@ void repair_worktrees(worktree_repair_fn fn, void *cb_data) free_worktrees(worktrees); } +void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path) +{ + struct strbuf path = STRBUF_INIT; + struct strbuf repo = STRBUF_INIT; + struct strbuf gitdir = STRBUF_INIT; + struct strbuf dotgit = STRBUF_INIT; + struct strbuf olddotgit = STRBUF_INIT; + struct strbuf tmp = STRBUF_INIT; + + if (is_main_worktree(wt)) + goto done; + + strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1); + strbuf_addf(&gitdir, "%s/gitdir", repo.buf); + + if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0) + goto done; + + strbuf_rtrim(&olddotgit); + if (is_absolute_path(olddotgit.buf)) { + strbuf_addbuf(&dotgit, &olddotgit); + } else { + strbuf_addf(&dotgit, "%s/worktrees/%s/%s", old_path, wt->id, olddotgit.buf); + strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0); + } + + if (!file_exists(dotgit.buf)) + goto done; + + strbuf_addbuf(&path, &dotgit); + strbuf_strip_suffix(&path, "/.git"); + + write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp)); + write_file(gitdir.buf, "%s", relative_path(dotgit.buf, repo.buf, &tmp)); +done: + strbuf_release(&path); + strbuf_release(&repo); + strbuf_release(&gitdir); + strbuf_release(&dotgit); + strbuf_release(&olddotgit); + strbuf_release(&tmp); +} + +void repair_worktrees_after_gitdir_move(const char *old_path) +{ + struct worktree **worktrees = get_worktrees_internal(1); + struct worktree **wt = worktrees + 1; /* +1 skips main worktree */ + + for (; *wt; wt++) + repair_worktree_after_gitdir_move(*wt, old_path); + free_worktrees(worktrees); +} + static int is_main_worktree_path(const char *path) { struct strbuf target = STRBUF_INIT; @@ -642,10 +726,9 @@ static int is_main_worktree_path(const char *path) * be able to infer the gitdir by manually reading /path/to/worktree/.git, * extracting the <id>, and checking if <repo>/worktrees/<id> exists. */ -static char *infer_backlink(const char *gitfile) +static int infer_backlink(const char *gitfile, struct strbuf *inferred) { struct strbuf actual = STRBUF_INIT; - struct strbuf inferred = STRBUF_INIT; const char *id; if (strbuf_read_file(&actual, gitfile, 0) < 0) @@ -658,17 +741,18 @@ static char *infer_backlink(const char *gitfile) id++; /* advance past '/' to point at <id> */ if (!*id) goto error; - strbuf_git_common_path(&inferred, the_repository, "worktrees/%s", id); - if (!is_directory(inferred.buf)) + strbuf_reset(inferred); + strbuf_git_common_path(inferred, the_repository, "worktrees/%s", id); + if (!is_directory(inferred->buf)) goto error; strbuf_release(&actual); - return strbuf_detach(&inferred, NULL); + return 1; error: strbuf_release(&actual); - strbuf_release(&inferred); - return NULL; + strbuf_reset(inferred); /* clear invalid path */ + return 0; } /* @@ -680,9 +764,13 @@ void repair_worktree_at_path(const char *path, { struct strbuf dotgit = STRBUF_INIT; struct strbuf realdotgit = STRBUF_INIT; + struct strbuf backlink = STRBUF_INIT; + struct strbuf inferred_backlink = STRBUF_INIT; struct strbuf gitdir = STRBUF_INIT; struct strbuf olddotgit = STRBUF_INIT; - char *backlink = NULL; + struct strbuf realolddotgit = STRBUF_INIT; + struct strbuf tmp = STRBUF_INIT; + char *dotgit_contents = NULL; const char *repair = NULL; int err; @@ -698,107 +786,178 @@ void repair_worktree_at_path(const char *path, goto done; } - backlink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err)); - if (err == READ_GITFILE_ERR_NOT_A_FILE) { + infer_backlink(realdotgit.buf, &inferred_backlink); + strbuf_realpath_forgiving(&inferred_backlink, inferred_backlink.buf, 0); + dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err)); + if (dotgit_contents) { + if (is_absolute_path(dotgit_contents)) { + strbuf_addstr(&backlink, dotgit_contents); + } else { + strbuf_addbuf(&backlink, &realdotgit); + strbuf_strip_suffix(&backlink, ".git"); + strbuf_addstr(&backlink, dotgit_contents); + strbuf_realpath_forgiving(&backlink, backlink.buf, 0); + } + } else if (err == READ_GITFILE_ERR_NOT_A_FILE) { fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data); goto done; } else if (err == READ_GITFILE_ERR_NOT_A_REPO) { - if (!(backlink = infer_backlink(realdotgit.buf))) { + if (inferred_backlink.len) { + /* + * Worktree's .git file does not point at a repository + * but we found a .git/worktrees/<id> in this + * repository with the same <id> as recorded in the + * worktree's .git file so make the worktree point at + * the discovered .git/worktrees/<id>. + */ + strbuf_swap(&backlink, &inferred_backlink); + } else { fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data); goto done; } - } else if (err) { + } else { fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data); goto done; } - strbuf_addf(&gitdir, "%s/gitdir", backlink); + /* + * If we got this far, either the worktree's .git file pointed at a + * valid repository (i.e. read_gitfile_gently() returned success) or + * the .git file did not point at a repository but we were able to + * infer a suitable new value for the .git file by locating a + * .git/worktrees/<id> in *this* repository corresponding to the <id> + * recorded in the worktree's .git file. + * + * However, if, at this point, inferred_backlink is non-NULL (i.e. we + * found a suitable .git/worktrees/<id> in *this* repository) *and* the + * worktree's .git file points at a valid repository *and* those two + * paths differ, then that indicates that the user probably *copied* + * the main and linked worktrees to a new location as a unit rather + * than *moving* them. Thus, the copied worktree's .git file actually + * points at the .git/worktrees/<id> in the *original* repository, not + * in the "copy" repository. In this case, point the "copy" worktree's + * .git file at the "copy" repository. + */ + if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf)) { + strbuf_swap(&backlink, &inferred_backlink); + } + + strbuf_addf(&gitdir, "%s/gitdir", backlink.buf); if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0) repair = _("gitdir unreadable"); else { strbuf_rtrim(&olddotgit); - if (fspathcmp(olddotgit.buf, realdotgit.buf)) + if (is_absolute_path(olddotgit.buf)) { + strbuf_addbuf(&realolddotgit, &olddotgit); + } else { + strbuf_addf(&realolddotgit, "%s/%s", backlink.buf, olddotgit.buf); + strbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0); + } + if (fspathcmp(realolddotgit.buf, realdotgit.buf)) repair = _("gitdir incorrect"); } if (repair) { fn(0, gitdir.buf, repair, cb_data); - write_file(gitdir.buf, "%s", realdotgit.buf); + write_file(gitdir.buf, "%s", relative_path(realdotgit.buf, backlink.buf, &tmp)); } done: - free(backlink); + free(dotgit_contents); strbuf_release(&olddotgit); + strbuf_release(&realolddotgit); + strbuf_release(&backlink); + strbuf_release(&inferred_backlink); strbuf_release(&gitdir); strbuf_release(&realdotgit); strbuf_release(&dotgit); + strbuf_release(&tmp); } int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire) { struct stat st; - char *path; + struct strbuf dotgit = STRBUF_INIT; + struct strbuf gitdir = STRBUF_INIT; + struct strbuf repo = STRBUF_INIT; + struct strbuf file = STRBUF_INIT; + char *path = NULL; + int rc = 0; int fd; size_t len; ssize_t read_result; *wtpath = NULL; - if (!is_directory(git_path("worktrees/%s", id))) { + strbuf_realpath(&repo, git_common_path("worktrees/%s", id), 1); + strbuf_addf(&gitdir, "%s/gitdir", repo.buf); + if (!is_directory(repo.buf)) { strbuf_addstr(reason, _("not a valid directory")); - return 1; + rc = 1; + goto done; } - if (file_exists(git_path("worktrees/%s/locked", id))) - return 0; - if (stat(git_path("worktrees/%s/gitdir", id), &st)) { + strbuf_addf(&file, "%s/locked", repo.buf); + if (file_exists(file.buf)) { + goto done; + } + if (stat(gitdir.buf, &st)) { strbuf_addstr(reason, _("gitdir file does not exist")); - return 1; + rc = 1; + goto done; } - fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY); + fd = open(gitdir.buf, O_RDONLY); if (fd < 0) { strbuf_addf(reason, _("unable to read gitdir file (%s)"), strerror(errno)); - return 1; + rc = 1; + goto done; } len = xsize_t(st.st_size); path = xmallocz(len); read_result = read_in_full(fd, path, len); + close(fd); if (read_result < 0) { strbuf_addf(reason, _("unable to read gitdir file (%s)"), strerror(errno)); - close(fd); - free(path); - return 1; - } - close(fd); - - if (read_result != len) { + rc = 1; + goto done; + } else if (read_result != len) { strbuf_addf(reason, _("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"), (uintmax_t)len, (uintmax_t)read_result); - free(path); - return 1; + rc = 1; + goto done; } while (len && (path[len - 1] == '\n' || path[len - 1] == '\r')) len--; if (!len) { strbuf_addstr(reason, _("invalid gitdir file")); - free(path); - return 1; + rc = 1; + goto done; } path[len] = '\0'; - if (!file_exists(path)) { - if (stat(git_path("worktrees/%s/index", id), &st) || - st.st_mtime <= expire) { + if (is_absolute_path(path)) { + strbuf_addstr(&dotgit, path); + } else { + strbuf_addf(&dotgit, "%s/%s", repo.buf, path); + strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0); + } + if (!file_exists(dotgit.buf)) { + strbuf_reset(&file); + strbuf_addf(&file, "%s/index", repo.buf); + if (stat(file.buf, &st) || st.st_mtime <= expire) { strbuf_addstr(reason, _("gitdir file points to non-existent location")); - free(path); - return 1; - } else { - *wtpath = path; - return 0; + rc = 1; + goto done; } } - *wtpath = path; - return 0; + *wtpath = strbuf_detach(&dotgit, NULL); +done: + free(path); + strbuf_release(&dotgit); + strbuf_release(&gitdir); + strbuf_release(&repo); + strbuf_release(&file); + return rc; } static int move_config_setting(const char *key, const char *value, diff --git a/worktree.h b/worktree.h index 11279d0c8f..e961186216 100644 --- a/worktree.h +++ b/worktree.h @@ -132,6 +132,16 @@ typedef void (* worktree_repair_fn)(int iserr, const char *path, void repair_worktrees(worktree_repair_fn, void *cb_data); /* + * Repair the linked worktrees after the gitdir has been moved. + */ +void repair_worktrees_after_gitdir_move(const char *old_path); + +/* + * Repair the linked worktree after the gitdir has been moved. + */ +void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path); + +/* * Repair administrative files corresponding to the worktree at the given path. * The worktree's .git file pointing at the repository must be intact for the * repair to succeed. Useful for re-associating an orphaned worktree with the |
