@matheusbsbs / matheus-bagliano / commits / be66a6c43d
Fork 0

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>

Johannes Schindelin committed Apr 25, 2009 at 11:57 UTC be66a6c43dcba42c56f66a8706721a76098f8e25
6 files changed +28 -1
Documentation/config.txt
+5
@@ -429,6 +429,11 @@ relatively high IO latencies. With this set to 'true', git will do the
429 index comparison to the filesystem data in parallel, allowing
430 overlapping IO's.
431
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 +
437 alias.*::
438 Command aliases for the linkgit:git[1] command wrapper - e.g.
439 after defining "alias.last = cat-file commit HEAD", the invocation
Makefile
+8
@@ -171,6 +171,10 @@ all::
171 # Define UNRELIABLE_FSTAT if your system's fstat does not return the same
172 # information on a not yet closed file that lstat would return for the same
173 # 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).
178
179 GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
180 @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -835,6 +839,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
839 NO_NSEC = YesPlease
840 USE_WIN32_MMAP = YesPlease
841 UNRELIABLE_FSTAT = UnfortunatelyYes
842 + UNRELIABLE_HARDLINKS = UnfortunatelySometimes
843 COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
844 COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
845 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -1018,6 +1023,9 @@ else
1023 COMPAT_OBJS += compat/win32mmap.o
1024 endif
1025 endif
1026 +ifdef UNRELIABLE_HARDLINKS
1027 + COMPAT_CFLAGS += -DUNRELIABLE_HARDLINKS=1
1028 +endif
1029 ifdef NO_PREAD
1030 COMPAT_CFLAGS += -DNO_PREAD
1031 COMPAT_OBJS += compat/pread.o
cache.h
+2
@@ -554,6 +554,8 @@ extern enum branch_track git_branch_track;
554 extern enum rebase_setup_type autorebase;
555 extern enum push_default_type push_default;
556
557 +extern int unreliable_hardlinks;
558 +
559 #define GIT_REPO_VERSION 0
560 extern int repository_format_version;
561 extern int check_repository_format(void);
config.c
+5
@@ -495,6 +495,11 @@ static int git_default_core_config(const char *var, const char *value)
495 return 0;
496 }
497
498 + if (!strcmp(var, "core.unreliablehardlinks")) {
499 + unreliable_hardlinks = git_config_bool(var, value);
500 + return 0;
501 + }
502 +
503 /* Add other config variables here and to Documentation/config.txt. */
504 return 0;
505 }
environment.c
+4
@@ -43,6 +43,10 @@ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
43 enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
44 enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
45 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;
50
51 /* Parallel index stat data preload? */
52 int core_preload_index = 0;
sha1_file.c
+4 -1
@@ -2225,7 +2225,9 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
2225 {
2226 int ret = 0;
2227
2228 - if (link(tmpfile, filename))
2228 + if (unreliable_hardlinks)
2229 + goto try_rename;
2230 + else if (link(tmpfile, filename))
2231 ret = errno;
2232
2233 /*
@@ -2240,6 +2242,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
2242 * left to unlink.
2243 */
2244 if (ret && ret != EEXIST) {
2245 + try_rename:
2246 if (!rename(tmpfile, filename))
2247 goto out;
2248 ret = errno;