Commit 3d6a42d1e14281c564d779e7490d761555d014d4

Edward Thomson 2016-02-25T11:23:19

nsec: support NDK's crazy nanoseconds Android NDK does not have a `struct timespec` in its `struct stat` for nanosecond support, instead it has a single nanosecond member inside the struct stat itself. We will use that and use a macro to expand to the `st_mtim` / `st_mtimespec` definition on other systems (much like the existing `st_mtime` backcompat definition).

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0aa5862..6a7dac2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -86,17 +86,21 @@ IF (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
 	OPTION( USE_OPENSSL                     "Link with and use openssl library"             ON )
 ENDIF()
 
-CHECK_STRUCT_HAS_MEMBER ("struct stat" st_atim "sys/types.h;sys/stat.h"
-	HAVE_STRUCT_STAT_ST_ATIM LANGUAGE C)
-CHECK_STRUCT_HAS_MEMBER ("struct stat" st_atimespec "sys/types.h;sys/stat.h"
-	HAVE_STRUCT_STAT_ST_ATIMESPEC LANGUAGE C)
-
-IF (HAVE_STRUCT_STAT_ST_ATIM)
+CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtim "sys/types.h;sys/stat.h"
+	HAVE_STRUCT_STAT_ST_MTIM LANGUAGE C)
+CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtimespec "sys/types.h;sys/stat.h"
+	HAVE_STRUCT_STAT_ST_MTIMESPEC LANGUAGE C)
+CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtime_nsec sys/stat.h
+	HAVE_STRUCT_STAT_MTIME_NSEC LANGUAGE C)
+
+IF (HAVE_STRUCT_STAT_ST_MTIM)
 	CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtim.tv_nsec sys/stat.h
 		HAVE_STRUCT_STAT_NSEC LANGUAGE C)
-ELSEIF (HAVE_STRUCT_STAT_ST_ATIMESPEC)
+ELSEIF (HAVE_STRUCT_STAT_ST_MTIMESPEC)
 	CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtimespec.tv_nsec sys/stat.h
 		HAVE_STRUCT_STAT_NSEC LANGUAGE C)
+ELSE ()
+	SET( HAVE_STRUCT_STAT_NSEC ON )
 ENDIF()
 
 IF (HAVE_STRUCT_STAT_NSEC OR WIN32)
@@ -539,8 +543,12 @@ IF (USE_NSEC)
 	ADD_DEFINITIONS(-DGIT_USE_NSEC)
 ENDIF()
 
-IF (HAVE_STRUCT_STAT_ST_ATIMESPEC)
-	ADD_DEFINITIONS(-DGIT_USE_STAT_ATIMESPEC)
+IF (HAVE_STRUCT_STAT_ST_MTIM)
+	ADD_DEFINITIONS(-DGIT_USE_STAT_MTIM)
+ELSEIF (HAVE_STRUCT_STAT_ST_MTIMESPEC)
+	ADD_DEFINITIONS(-DGIT_USE_STAT_MTIMESPEC)
+ELSEIF (HAVE_STRUCT_STAT_ST_MTIME_NSEC)
+	ADD_DEFINITIONS(-DGIT_USE_STAT_MTIME_NSEC)
 ENDIF()
 
 ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
diff --git a/src/fileops.c b/src/fileops.c
index 150333d..22868b4 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -1034,7 +1034,6 @@ int git_futils_filestamp_check(
 	git_futils_filestamp *stamp, const char *path)
 {
 	struct stat st;
-	const struct timespec *statmtime = &st.st_mtim;
 
 	/* if the stamp is NULL, then always reload */
 	if (stamp == NULL)
@@ -1043,17 +1042,17 @@ int git_futils_filestamp_check(
 	if (p_stat(path, &st) < 0)
 		return GIT_ENOTFOUND;
 
-	if (stamp->mtime.tv_sec == statmtime->tv_sec &&
+	if (stamp->mtime.tv_sec == st.st_mtime &&
 #if defined(GIT_USE_NSEC)
-		stamp->mtime.tv_nsec == statmtime->tv_nsec &&
+		stamp->mtime.tv_nsec == st.st_mtime_nsec &&
 #endif
 		stamp->size  == (git_off_t)st.st_size   &&
 		stamp->ino   == (unsigned int)st.st_ino)
 		return 0;
 
-	stamp->mtime.tv_sec = statmtime->tv_sec;
+	stamp->mtime.tv_sec = st.st_mtime;
 #if defined(GIT_USE_NSEC)
-	stamp->mtime.tv_nsec = statmtime->tv_nsec;
+	stamp->mtime.tv_nsec = st.st_mtime_nsec;
 #endif
 	stamp->size  = (git_off_t)st.st_size;
 	stamp->ino   = (unsigned int)st.st_ino;
@@ -1076,11 +1075,11 @@ void git_futils_filestamp_set(
 void git_futils_filestamp_set_from_stat(
 	git_futils_filestamp *stamp, struct stat *st)
 {
-	const struct timespec *statmtime = &st->st_mtim;
-
 	if (st) {
-		stamp->mtime = *statmtime;
-#if !defined(GIT_USE_NSEC)
+		stamp->mtime.tv_sec = st->st_mtime;
+#if defined(GIT_USE_NSEC)
+		stamp->mtime.tv_nsec = st->st_mtime_nsec;
+#else
 		stamp->mtime.tv_nsec = 0;
 #endif
 		stamp->size  = (git_off_t)st->st_size;
diff --git a/src/index.c b/src/index.c
index d0a0da2..c18f358 100644
--- a/src/index.c
+++ b/src/index.c
@@ -829,8 +829,8 @@ void git_index_entry__init_from_stat(
 	entry->ctime.seconds = (int32_t)st->st_ctime;
 	entry->mtime.seconds = (int32_t)st->st_mtime;
 #if defined(GIT_USE_NSEC)
-	entry->mtime.nanoseconds = st->st_mtim.tv_nsec;
-	entry->ctime.nanoseconds = st->st_ctim.tv_nsec;
+	entry->mtime.nanoseconds = st->st_mtime_nsec;
+	entry->ctime.nanoseconds = st->st_ctime_nsec;
 #endif
 	entry->dev  = st->st_rdev;
 	entry->ino  = st->st_ino;
diff --git a/src/unix/posix.h b/src/unix/posix.h
index 83edf2b..482d2c8 100644
--- a/src/unix/posix.h
+++ b/src/unix/posix.h
@@ -21,6 +21,18 @@ typedef int GIT_SOCKET;
 #define p_lstat(p,b) lstat(p,b)
 #define p_stat(p,b) stat(p, b)
 
+#if defined(GIT_USE_STAT_MTIMESPEC)
+# define st_atime_nsec st_atimespec.tv_nsec
+# define st_mtime_nsec st_mtimespec.tv_nsec
+# define st_ctime_nsec st_ctimespec.tv_nsec
+#elif defined(GIT_USE_STAT_MTIM)
+# define st_atime_nsec st_atim.tv_nsec
+# define st_mtime_nsec st_mtim.tv_nsec
+# define st_ctime_nsec st_ctim.tv_nsec
+#elif !defined(GIT_USE_STAT_MTIME_NSEC) && defined(GIT_USE_NEC)
+# error GIT_USE_NSEC defined but unknown struct stat nanosecond type
+#endif
+
 #define p_utimes(f, t) utimes(f, t)
 
 #define p_readlink(a, b, c) readlink(a, b, c)
diff --git a/src/win32/win32-compat.h b/src/win32/win32-compat.h
index dff1f45..f888fd6 100644
--- a/src/win32/win32-compat.h
+++ b/src/win32/win32-compat.h
@@ -42,6 +42,9 @@ struct p_stat {
 #define st_atime st_atim.tv_sec
 #define st_mtime st_mtim.tv_sec
 #define st_ctime st_ctim.tv_sec
+#define st_atime_nsec st_atim.tv_nsec
+#define st_mtime_nsec st_mtim.tv_nsec
+#define st_ctime_nsec st_ctim.tv_nsec
 };
 
 #define stat p_stat