git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] packed_ref_store: handle a packed-refs file that is a symlink

From
Jonathan Nieder <jrnieder@gmail.com>
Date
Jul 27, 2017, 00:18 UTC
Message-ID
<20170727001812.GI13924@aiede.mtv.corp.google.com>
In-Reply-To
<d0da02a8b6f0272fa70ae3b1dc80fee6c6ee8d18.1501111803.git.mhagger@alum.mit.edu>
Hi,
Michael Haggerty wrote:
Show 22 quoted lines
> One of the tricks that `contrib/workdir/git-new-workdir` plays is to
> making `packed-refs` in the new workdir a symlink to the `packed-refs`
> file in the original repository. Before
> 42dfa7ecef ("commit_packed_refs(): use a staging file separate from
> the lockfile", 2017-06-23), a lockfile was used as the staging file,
> and because the `LOCK_NO_DEREF` was not used, the pointed-to file was
> locked and modified.
>
> But after that commit, the staging file was created using a tempfile,
> with the end result that rewriting the `packed-refs` file in the
> workdir overwrote the symlink rather than the original `packed-refs`
> file.
>
> Change `commit_packed_refs()` to use `get_locked_file_path()` to find
> the path of the file that it should overwrite. Since that path was
> properly resolved when the lockfile was created, this restores the
> pre-42dfa7ecef behavior.
>
> Also add a test case to document this use case and prevent a
> regression like this from recurring.
>
> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Reported-by: Dave Walker <dawalker@google.com>
[...]
>  refs/packed-backend.c | 24 ++++++++++++++++++------
>  t/t3210-pack-refs.sh  | 15 +++++++++++++++
>  2 files changed, 33 insertions(+), 6 deletions(-)

The patch looks good, except for one nit marked below (*). I'll apply it locally and ask people to test it, probably tomorrow morning.

Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Thanks for writing it.  Patch left unsnipped for reference.
Show 69 quoted lines
> diff --git a/refs/packed-backend.c b/refs/packed-backend.c
> index a28befbfa3..59e7d1a509 100644
> --- a/refs/packed-backend.c
> +++ b/refs/packed-backend.c
> @@ -610,19 +610,27 @@ int commit_packed_refs(struct ref_store *ref_store, struct strbuf *err)
>  	struct packed_ref_cache *packed_ref_cache =
>  		get_packed_ref_cache(refs);
>  	int ok;
> +	int ret = -1;
>  	struct strbuf sb = STRBUF_INIT;
>  	FILE *out;
>  	struct ref_iterator *iter;
> +	char *packed_refs_path;
>  
>  	if (!is_lock_file_locked(&refs->lock))
>  		die("BUG: commit_packed_refs() called when unlocked");
>  
> -	strbuf_addf(&sb, "%s.new", refs->path);
> +	/*
> +	 * If packed-refs is a symlink, we want to overwrite the
> +	 * symlinked-to file, not the symlink itself. Also, put the
> +	 * staging file next to it:
> +	 */
> +	packed_refs_path = get_locked_file_path(&refs->lock);
> +	strbuf_addf(&sb, "%s.new", packed_refs_path);
>  	if (create_tempfile(&refs->tempfile, sb.buf) < 0) {
>  		strbuf_addf(err, "unable to create file %s: %s",
>  			    sb.buf, strerror(errno));
>  		strbuf_release(&sb);
> -		return -1;
> +		goto out;
>  	}
>  	strbuf_release(&sb);
>  
> @@ -660,17 +668,21 @@ int commit_packed_refs(struct ref_store *ref_store, struct strbuf *err)
>  		goto error;
>  	}
>  
> -	if (rename_tempfile(&refs->tempfile, refs->path)) {
> +	if (rename_tempfile(&refs->tempfile, packed_refs_path)) {
>  		strbuf_addf(err, "error replacing %s: %s",
>  			    refs->path, strerror(errno));
> -		return -1;
> +		goto out;
>  	}
>  
> -	return 0;
> +	ret = 0;
> +	goto out;
>  
>  error:
>  	delete_tempfile(&refs->tempfile);
> -	return -1;
> +
> +out:
> +	free(packed_refs_path);
> +	return ret;
>  }
>  
>  /*
> diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
> index 2bb4b25ed9..0d8a03e2a9 100755
> --- a/t/t3210-pack-refs.sh
> +++ b/t/t3210-pack-refs.sh
> @@ -238,4 +238,19 @@ test_expect_success 'retry acquiring packed-refs.lock' '
>  	git -c core.packedrefstimeout=3000 pack-refs --all --prune
>  '
>  
> +test_expect_success 'pack symlinked packed-refs' '
(*) Does this need a SYMLINKS prereq to avoid trouble on Windows?
Show 15 quoted lines
> +	# First make sure that symlinking works when reading:
> +	git update-ref refs/heads/loosy refs/heads/master &&
> +	git for-each-ref >all-refs-before &&
> +	mv .git/packed-refs .git/my-deviant-packed-refs &&
> +	ln -s my-deviant-packed-refs .git/packed-refs &&
> +	git for-each-ref >all-refs-linked &&
> +	test_cmp all-refs-before all-refs-linked &&
> +	git pack-refs --all --prune &&
> +	git for-each-ref >all-refs-packed &&
> +	test_cmp all-refs-before all-refs-packed &&
> +	test -h .git/packed-refs &&
> +	test "$(readlink .git/packed-refs)" = "my-deviant-packed-refs"
> +'
> +
>  test_done
Previous: Stefan BellerNext: Michael Haggerty
Message 37 of 52 in “Create a reference backend for packed refs”
  1. 00/30 Create a reference backend for packed refsMichael Haggerty, Jul 1, 2017
  2. 01/30 t1408: add a test of stale packed refs covered by loose refsMichael Haggerty, Jul 1, 2017
  3. 03/30 packed_ref_store: new structMichael Haggerty, Jul 1, 2017
  4. 04/30 packed_ref_store: move `packed_refs_path` hereMichael Haggerty, Jul 1, 2017
  5. 02/30 add_packed_ref(): teach function to overwrite existing refsMichael Haggerty, Jul 1, 2017
  6. 06/30 clear_packed_ref_cache(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  7. 05/30 packed_ref_store: move `packed_refs_lock` member hereMichael Haggerty, Jul 1, 2017
  8. 09/30 get_packed_refs(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  9. 07/30 validate_packed_ref_cache(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  10. 12/30 commit_packed_refs(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  11. 08/30 get_packed_ref_cache(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  12. 10/30 add_packed_ref(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  13. 11/30 lock_packed_refs(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  14. 16/30 packed_peel_ref(): new function, extracted from `files_peel_ref()`Michael Haggerty, Jul 1, 2017
  15. 15/30 repack_without_refs(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  16. 14/30 get_packed_ref(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  17. 17/30 packed_ref_store: support iterationMichael Haggerty, Jul 1, 2017
  18. 19/30 packed-backend: new module for handling packed referencesMichael Haggerty, Jul 1, 2017
  19. 18/30 packed_read_raw_ref(): new function, replacing `resolve_packed_ref()`Michael Haggerty, Jul 1, 2017
  20. 22/30 commit_packed_refs(): use a staging file separate from the lockfileMichael Haggerty, Jul 1, 2017
  21. 20/30 packed_ref_store: make class into a subclass of `ref_store`Michael Haggerty, Jul 1, 2017
  22. 13/30 rollback_packed_refs(): take a `packed_ref_store *` parameterMichael Haggerty, Jul 1, 2017
  23. 23/30 packed_refs_lock(): function renamed from lock_packed_refs()Michael Haggerty, Jul 1, 2017
  24. 28/30 repack_without_refs(): don't lock or unlock the packed refsMichael Haggerty, Jul 1, 2017
  25. 29/30 t3210: add some tests of bogus packed-refs file contentsMichael Haggerty, Jul 1, 2017
  26. 26/30 clear_packed_ref_cache(): don't protest if the lock is heldMichael Haggerty, Jul 1, 2017
  27. 30/30 read_packed_refs(): die if `packed-refs` contains bogus dataMichael Haggerty, Jul 1, 2017
  28. 27/30 commit_packed_refs(): remove call to `packed_refs_unlock()`Michael Haggerty, Jul 1, 2017
  29. 21/30 commit_packed_refs(): report errors rather than dyingMichael Haggerty, Jul 1, 2017
  30. 25/30 packed_refs_unlock(), packed_refs_is_locked(): new functionsMichael Haggerty, Jul 1, 2017
  31. 24/30 packed_refs_lock(): report errors via a `struct strbuf *err`Michael Haggerty, Jul 1, 2017
  32. Jeff KingJul 5, 2017
  33. Stefan BellerJul 20, 2017
  34. Jonathan NiederJul 20, 2017
  35. packed_ref_store: handle a packed-refs file that is a symlinkMichael Haggerty, Jul 26, 2017
  36. Stefan BellerJul 27, 2017
  37. Jonathan NiederJul 27, 2017
  38. Michael HaggertyJul 27, 2017
  39. Junio C HamanoJul 27, 2017
  40. Jeff KingJul 27, 2017
  41. Junio C HamanoJul 27, 2017
  42. Michael HaggertyJul 28, 2017
  43. Ævar Arnfjörð BjarmasonMay 31, 2021
  44. Jeff KingJun 3, 2021
  45. t: use portable wrapper for readlink(1)Jeff King, Jun 3, 2021
  46. Ævar Arnfjörð BjarmasonJun 4, 2021
  47. Felipe ContrerasJun 3, 2021
  48. Jeff KingJun 3, 2021
  49. Felipe ContrerasJun 3, 2021
  50. Ævar Arnfjörð BjarmasonJun 4, 2021
  51. Felipe ContrerasJun 5, 2021
  52. Ævar Arnfjörð BjarmasonJun 4, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.