aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Sixt <j6t@kdbg.org>2009-04-20 10:17:00 +0200
committerJunio C Hamano <gitster@pobox.com>2009-04-20 12:14:02 -0700
commit34779c535c4e121414197ab08b4b502a22a75433 (patch)
treed856d59cbc54cbb7a79c5d22abc0d31bf93acd0c
parent6ac6f87818edfd33fea8ce3c95b47fe00a4e4b91 (diff)
downloadgit-34779c535c4e121414197ab08b4b502a22a75433.tar.gz
git-34779c535c4e121414197ab08b4b502a22a75433.tar.xz
Windows: Skip fstat/lstat optimization in write_entry()
Commit e4c72923 (write_entry(): use fstat() instead of lstat() when file is open, 2009-02-09) introduced an optimization of write_entry(). Unfortunately, we cannot take advantage of this optimization on Windows because there is no guarantee that the time stamps are updated before the file is closed: "The only guarantee about a file timestamp is that the file time is correctly reflected when the handle that makes the change is closed." (http://msdn.microsoft.com/en-us/library/ms724290(VS.85).aspx) The failure of this optimization on Windows can be observed most easily by running a 'git checkout' that has to update several large files. In this case, 'git checkout' will report modified files, but infact only the timestamps were incorrectly recorded in the index, as can be verified by a subsequent 'git diff', which shows no change. Dmitry Potapov reports the same fix needs on Cygwin; this commit contains his updates for that. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--Makefile9
-rw-r--r--entry.c3
-rw-r--r--git-compat-util.h6
3 files changed, 17 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 6e0838b03..49f36f578 100644
--- a/Makefile
+++ b/Makefile
@@ -167,6 +167,10 @@ all::
# Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call
# your external grep (e.g., if your system lacks grep, if its grep is
# broken, or spawning external process is slower than built-in grep git has).
+#
+# 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.
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -803,6 +807,7 @@ ifeq ($(uname_S),HP-UX)
endif
ifneq (,$(findstring CYGWIN,$(uname_S)))
COMPAT_OBJS += compat/cygwin.o
+ UNRELIABLE_FSTAT = UnfortunatelyYes
endif
ifneq (,$(findstring MINGW,$(uname_S)))
NO_PREAD = YesPlease
@@ -829,6 +834,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease
+ UNRELIABLE_FSTAT = UnfortunatelyYes
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -1107,6 +1113,9 @@ endif
ifdef NO_EXTERNAL_GREP
BASIC_CFLAGS += -DNO_EXTERNAL_GREP
endif
+ifdef UNRELIABLE_FSTAT
+ BASIC_CFLAGS += -DUNRELIABLE_FSTAT
+endif
ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
diff --git a/entry.c b/entry.c
index 5daacc2fe..915514aa5 100644
--- a/entry.c
+++ b/entry.c
@@ -147,7 +147,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
wrote = write_in_full(fd, new, size);
/* use fstat() only when path == ce->name */
- if (state->refresh_cache && !to_tempfile && !state->base_dir_len) {
+ if (fstat_is_reliable() &&
+ state->refresh_cache && !to_tempfile && !state->base_dir_len) {
fstat(fd, &st);
fstat_done = 1;
}
diff --git a/git-compat-util.h b/git-compat-util.h
index f09f24406..785aa31b4 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -408,4 +408,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
#endif
#endif
+#ifdef UNRELIABLE_FSTAT
+#define fstat_is_reliable() 0
+#else
+#define fstat_is_reliable() 1
+#endif
+
#endif