Skip to content

Commit be66a6c

Browse files
dschogitster
authored andcommitted
Add an option not to use link(src, dest) && unlink(src) when that is unreliable
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 785a985 commit be66a6c

6 files changed

Lines changed: 28 additions & 1 deletion

File tree

Documentation/config.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,11 @@ relatively high IO latencies. With this set to 'true', git will do the
429429
index comparison to the filesystem data in parallel, allowing
430430
overlapping IO's.
431431

432+
core.unreliableHardlinks::
433+
Some filesystem drivers cannot properly handle hardlinking a file
434+
and deleting the source right away. In such a case, you need to
435+
set this config variable to 'true'.
436+
432437
alias.*::
433438
Command aliases for the linkgit:git[1] command wrapper - e.g.
434439
after defining "alias.last = cat-file commit HEAD", the invocation

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ all::
171171
# Define UNRELIABLE_FSTAT if your system's fstat does not return the same
172172
# information on a not yet closed file that lstat would return for the same
173173
# file after it was closed.
174+
#
175+
# Define UNRELIABLE_HARDLINKS if your operating systems has problems when
176+
# hardlinking a file to another name and unlinking the original file right
177+
# away (some NTFS drivers seem to zero the contents in that scenario).
174178

175179
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
176180
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -835,6 +839,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
835839
NO_NSEC = YesPlease
836840
USE_WIN32_MMAP = YesPlease
837841
UNRELIABLE_FSTAT = UnfortunatelyYes
842+
UNRELIABLE_HARDLINKS = UnfortunatelySometimes
838843
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
839844
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
840845
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -1018,6 +1023,9 @@ else
10181023
COMPAT_OBJS += compat/win32mmap.o
10191024
endif
10201025
endif
1026+
ifdef UNRELIABLE_HARDLINKS
1027+
COMPAT_CFLAGS += -DUNRELIABLE_HARDLINKS=1
1028+
endif
10211029
ifdef NO_PREAD
10221030
COMPAT_CFLAGS += -DNO_PREAD
10231031
COMPAT_OBJS += compat/pread.o

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,8 @@ extern enum branch_track git_branch_track;
554554
extern enum rebase_setup_type autorebase;
555555
extern enum push_default_type push_default;
556556

557+
extern int unreliable_hardlinks;
558+
557559
#define GIT_REPO_VERSION 0
558560
extern int repository_format_version;
559561
extern int check_repository_format(void);

config.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,11 @@ static int git_default_core_config(const char *var, const char *value)
495495
return 0;
496496
}
497497

498+
if (!strcmp(var, "core.unreliablehardlinks")) {
499+
unreliable_hardlinks = git_config_bool(var, value);
500+
return 0;
501+
}
502+
498503
/* Add other config variables here and to Documentation/config.txt. */
499504
return 0;
500505
}

environment.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
4343
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
4444
enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
4545
enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
46+
#ifndef UNRELIABLE_HARDLINKS
47+
#define UNRELIABLE_HARDLINKS 0
48+
#endif
49+
int unreliable_hardlinks = UNRELIABLE_HARDLINKS;
4650

4751
/* Parallel index stat data preload? */
4852
int core_preload_index = 0;

sha1_file.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2225,7 +2225,9 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
22252225
{
22262226
int ret = 0;
22272227

2228-
if (link(tmpfile, filename))
2228+
if (unreliable_hardlinks)
2229+
goto try_rename;
2230+
else if (link(tmpfile, filename))
22292231
ret = errno;
22302232

22312233
/*
@@ -2240,6 +2242,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
22402242
* left to unlink.
22412243
*/
22422244
if (ret && ret != EEXIST) {
2245+
try_rename:
22432246
if (!rename(tmpfile, filename))
22442247
goto out;
22452248
ret = errno;

0 commit comments

Comments
 (0)