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

Re: [PATCH v2] Add an option not to use link(src, dest) && unlink(src) when that is unreliable

From
Junio C Hamano <gitster@pobox.com>
Date
Apr 25, 2009, 16:49 UTC
Message-ID
<7vbpqkznjs.fsf@gitster.siamese.dyndns.org>
In-Reply-To
<alpine.DEB.1.00.0904251155130.10279@pacific.mpi-cbg.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 15 quoted lines
> It seems that accessing NTFS partitions with ufsd (at least on my EeePC)
> has an unnerving bug: if you link() a file and unlink() it right away,
> the target of the link() will have the correct size, but consist of NULs.
>
> It seems as if the calls are simply not serialized correctly, as single-stepping
> through the function move_temp_to_file() works flawlessly.
>
> As ufsd is "Commertial software" (sic!), I cannot fix it, and have to work
> around it in Git.
>
> At the same time, it seems that this fixes msysGit issues 222 and 229 to
> assume that Windows cannot handle link() && unlink().
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> Acked-by: Johannes Sixt <j6t@kdbg.org>
Hannes, are you ok with this?
Show 12 quoted lines
> diff --git a/environment.c b/environment.c
> index 4696885..10578d2 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -43,6 +43,10 @@ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
>  enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
>  enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
>  enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
> +#ifndef UNRELIABLE_HARDLINKS
> +#define UNRELIABLE_HARDLINKS 0
> +#endif
> +int unreliable_hardlinks = UNRELIABLE_HARDLINKS;

Hmm, this ifndef/define/endif is somewhat yucky to see especially in a .c source file. Sorry, I do not think of a better alternative, though.

	int unreliable_hardlinks = defined(UNRELIABLE_HARDLINKS)
would not work either X-<.
Show 11 quoted lines
> diff --git a/sha1_file.c b/sha1_file.c
> index 8fe135d..bb6eecf 100644
> --- a/sha1_file.c
> +++ b/sha1_file.c
> @@ -2225,7 +2225,9 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
>  {
>  	int ret = 0;
>  
> -	if (link(tmpfile, filename))
> +	if (unreliable_hardlinks)
> +		ret = ~EEXIST; /* anything but EEXIST */
It is a bit too far away from the:
	if (ret && ret != EEXIST)

you are trying to trigger with this hack, and without seeing that "if" in the context anybody would go "Huh?". It is a good sign that this is fragile (the later "if" may be rewritten by somebody else without realizing this hack exists). Besides, it is (rather, "happens to be at this moment") "anything non-zero but EEXIST".

I have a feeling that it would be much less fragile to write it like this, as a label warns anybody touching the code to check where else the control flow may come from.

diff --git a/sha1_file.c b/sha1_file.c
index 8fe135d..11969fc 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2225,7 +2225,9 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
 {
 	int ret = 0;
 
-	if (link(tmpfile, filename))
+	if (unreliable_hardlinks)
+		goto try_rename;
+	else if (link(tmpfile, filename))
 		ret = errno;
 
 	/*
@@ -2240,6 +2242,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
 	 * left to unlink.
 	 */
 	if (ret && ret != EEXIST) {
+	try_rename:
 		if (!rename(tmpfile, filename))
 			goto out;
 		ret = errno;
Previous: Johannes SchindelinNext: Linus Torvalds
Message 5 of 38 in “Add an option not to use link(src, dest) && unlink(src) when that is unreliable”
  1. Add an option not to use link(src, dest) && unlink(src) when that is unreliableJohannes Schindelin, Apr 23, 2009
  2. Johannes SixtApr 23, 2009
  3. Johannes SchindelinApr 23, 2009
  4. Add an option not to use link(src, dest) && unlink(src) when that is unreliableJohannes Schindelin, Apr 25, 2009
  5. Junio C HamanoApr 25, 2009
  6. Linus TorvaldsApr 25, 2009
  7. Michael GaberApr 25, 2009
  8. Linus TorvaldsApr 25, 2009
  9. Jay SoffianApr 27, 2009
  10. Johannes SixtApr 25, 2009
  11. Junio C HamanoApr 25, 2009
  12. Johannes SchindelinApr 26, 2009
  13. Linus TorvaldsApr 25, 2009
  14. Alex RiesenApr 23, 2009
  15. Johannes SchindelinApr 23, 2009
  16. Alex RiesenApr 24, 2009
  17. Linus TorvaldsApr 25, 2009
  18. Johannes SixtApr 25, 2009
  19. Junio C HamanoApr 26, 2009
  20. Johannes SchindelinApr 26, 2009
  21. Add an option not to use link(src, dest) && unlink(src) when that is unreliableJohannes Schindelin, Apr 27, 2009
  22. Linus TorvaldsApr 27, 2009
  23. Johannes SchindelinApr 27, 2009
  24. Linus TorvaldsApr 27, 2009
  25. Junio C HamanoApr 27, 2009
  26. Linus TorvaldsApr 27, 2009
  27. Linus TorvaldsApr 27, 2009
  28. Junio C HamanoApr 27, 2009
  29. Johannes SchindelinApr 27, 2009
  30. Linus TorvaldsApr 27, 2009
  31. Rename core.unreliableHardlinks to core.createObjectJohannes Schindelin, Apr 27, 2009
  32. Junio C HamanoApr 27, 2009
  33. Johannes SchindelinApr 28, 2009
  34. Junio C HamanoApr 28, 2009
  35. Johannes SchindelinApr 28, 2009
  36. Junio C HamanoApr 28, 2009
  37. Johannes SchindelinApr 28, 2009
  38. Johannes SchindelinApr 26, 2009

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.