Skip to content

Commit 34779c5

Browse files
j6tgitster
authored andcommitted
Windows: Skip fstat/lstat optimization in write_entry()
Commit e4c7292 (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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6ac6f87 commit 34779c5

File tree

3 files changed

+17
-1
lines changed

3 files changed

+17
-1
lines changed

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ all::
167167
# Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call
168168
# your external grep (e.g., if your system lacks grep, if its grep is
169169
# broken, or spawning external process is slower than built-in grep git has).
170+
#
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.
170174

171175
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
172176
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -803,6 +807,7 @@ ifeq ($(uname_S),HP-UX)
803807
endif
804808
ifneq (,$(findstring CYGWIN,$(uname_S)))
805809
COMPAT_OBJS += compat/cygwin.o
810+
UNRELIABLE_FSTAT = UnfortunatelyYes
806811
endif
807812
ifneq (,$(findstring MINGW,$(uname_S)))
808813
NO_PREAD = YesPlease
@@ -829,6 +834,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
829834
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
830835
NO_NSEC = YesPlease
831836
USE_WIN32_MMAP = YesPlease
837+
UNRELIABLE_FSTAT = UnfortunatelyYes
832838
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
833839
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
834840
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -1107,6 +1113,9 @@ endif
11071113
ifdef NO_EXTERNAL_GREP
11081114
BASIC_CFLAGS += -DNO_EXTERNAL_GREP
11091115
endif
1116+
ifdef UNRELIABLE_FSTAT
1117+
BASIC_CFLAGS += -DUNRELIABLE_FSTAT
1118+
endif
11101119

11111120
ifeq ($(TCLTK_PATH),)
11121121
NO_TCLTK=NoThanks

entry.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
147147

148148
wrote = write_in_full(fd, new, size);
149149
/* use fstat() only when path == ce->name */
150-
if (state->refresh_cache && !to_tempfile && !state->base_dir_len) {
150+
if (fstat_is_reliable() &&
151+
state->refresh_cache && !to_tempfile && !state->base_dir_len) {
151152
fstat(fd, &st);
152153
fstat_done = 1;
153154
}

git-compat-util.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,4 +408,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
408408
#endif
409409
#endif
410410

411+
#ifdef UNRELIABLE_FSTAT
412+
#define fstat_is_reliable() 0
413+
#else
414+
#define fstat_is_reliable() 1
415+
#endif
416+
411417
#endif

0 commit comments

Comments
 (0)