Skip to content

Commit

Permalink
Add an option not to use link(src, dest) && unlink(src) when that is …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
Johannes Schindelin authored and Junio C Hamano committed Apr 25, 2009
1 parent 785a985 commit be66a6c
Showing 6 changed files with 28 additions and 1 deletion.
5 changes: 5 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
@@ -429,6 +429,11 @@ relatively high IO latencies. With this set to 'true', git will do the
index comparison to the filesystem data in parallel, allowing
overlapping IO's.

core.unreliableHardlinks::
Some filesystem drivers cannot properly handle hardlinking a file
and deleting the source right away. In such a case, you need to
set this config variable to 'true'.

alias.*::
Command aliases for the linkgit:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -171,6 +171,10 @@ all::
# Define UNRELIABLE_FSTAT if your system's fstat does not return the same
# information on a not yet closed file that lstat would return for the same
# file after it was closed.
#
# Define UNRELIABLE_HARDLINKS if your operating systems has problems when
# hardlinking a file to another name and unlinking the original file right
# away (some NTFS drivers seem to zero the contents in that scenario).

GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -835,6 +839,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease
UNRELIABLE_FSTAT = UnfortunatelyYes
UNRELIABLE_HARDLINKS = UnfortunatelySometimes
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -1018,6 +1023,9 @@ else
COMPAT_OBJS += compat/win32mmap.o
endif
endif
ifdef UNRELIABLE_HARDLINKS
COMPAT_CFLAGS += -DUNRELIABLE_HARDLINKS=1
endif
ifdef NO_PREAD
COMPAT_CFLAGS += -DNO_PREAD
COMPAT_OBJS += compat/pread.o
2 changes: 2 additions & 0 deletions cache.h
Original file line number Diff line number Diff line change
@@ -554,6 +554,8 @@ extern enum branch_track git_branch_track;
extern enum rebase_setup_type autorebase;
extern enum push_default_type push_default;

extern int unreliable_hardlinks;

#define GIT_REPO_VERSION 0
extern int repository_format_version;
extern int check_repository_format(void);
5 changes: 5 additions & 0 deletions config.c
Original file line number Diff line number Diff line change
@@ -495,6 +495,11 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}

if (!strcmp(var, "core.unreliablehardlinks")) {
unreliable_hardlinks = git_config_bool(var, value);
return 0;
}

/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
4 changes: 4 additions & 0 deletions environment.c
Original file line number Diff line number Diff line change
@@ -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;

/* Parallel index stat data preload? */
int core_preload_index = 0;
5 changes: 4 additions & 1 deletion sha1_file.c
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit be66a6c

Please sign in to comment.