From ebd9d5ba1abc432f3a11b99ac32657b4cea7ecfd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= <martin@v.loewis.de>
Date: Tue, 9 Aug 2005 15:00:59 +0000
Subject: Patch #1180695: Implement nanosecond stat resolution on FreeBSD, add
 st_gen, st_birthtime.

---
 Doc/lib/libos.tex     |   7 ++
 Misc/NEWS             |   3 +
 Modules/posixmodule.c |  47 ++++++++
 configure             | 289 +++++++++++++++++++++++++++++++++++++++++++++++++-
 configure.in          |  19 ++++
 pyconfig.h.in         |   9 ++
 6 files changed, 373 insertions(+), 1 deletion(-)

diff --git a/Doc/lib/libos.tex b/Doc/lib/libos.tex
index 3d9056d..2e6636e 100644
--- a/Doc/lib/libos.tex
+++ b/Doc/lib/libos.tex
@@ -996,6 +996,12 @@ also be available:
 \member{st_rdev} (type of device if an inode device).
 \member{st_flags} (user defined flags for file).
 
+On other Unix systems (such as FreeBSD), the following attributes
+may be available (but may be only filled out of root tries to
+use them:
+\member{st_gen} (file generation number),
+\member{st_birthtime} (time of file creation).
+
 On Mac OS systems, the following attributes may also be available:
 \member{st_rsize},
 \member{st_creator},
@@ -1037,6 +1043,7 @@ Availability: Macintosh, \UNIX, Windows.
 
 \versionchanged
 [Added access to values as attributes of the returned object]{2.2}
+\versionchanged[Added st_gen, st_birthtime]{2.5}
 \end{funcdesc}
 
 \begin{funcdesc}{stat_float_times}{\optional{newvalue}}
diff --git a/Misc/NEWS b/Misc/NEWS
index 10e43bc..a1f15ab 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -121,6 +121,9 @@ Core and builtins
 Extension Modules
 -----------------
 
+- Patch #1180695: Add nanosecond stat resolution, and st_gen, 
+  st_birthtime for FreeBSD.
+
 - Patch #1231069: The fcntl.ioctl function now uses the 'I' code for
   the request code argument, which results in more C-like behaviour
   for large or negative values.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index e0c2b7f..6e229f6 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -706,6 +706,12 @@ static PyStructSequence_Field stat_result_fields[] = {
 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
 	{"st_flags",   "user defined flags for file"},
 #endif
+#ifdef HAVE_STRUCT_STAT_ST_GEN
+	{"st_gen",    "generation number"},
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
+	{"st_birthtime",   "time of creation"},
+#endif
 	{0}
 };
 
@@ -733,6 +739,18 @@ static PyStructSequence_Field stat_result_fields[] = {
 #define ST_FLAGS_IDX ST_RDEV_IDX
 #endif
 
+#ifdef HAVE_STRUCT_STAT_ST_GEN
+#define ST_GEN_IDX (ST_RDEV_IDX+1)
+#else
+#define ST_GEN_IDX ST_RDEV_IDX
+#endif
+
+#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
+#define ST_BIRTHTIME_IDX (ST_GEN_IDX+1)
+#else
+#define ST_BIRTHTIME_IDX ST_GEN_IDX
+#endif
+
 static PyStructSequence_Desc stat_result_desc = {
 	"stat_result", /* name */
 	stat_result__doc__, /* doc */
@@ -878,8 +896,14 @@ _pystat_fromstructstat(STRUCT_STAT st)
 	mnsec = st.st_mtim.tv_nsec;
 	cnsec = st.st_ctim.tv_nsec;
 #else
+#ifdef HAVE_STAT_TV_NSEC2
+	ansec = st.st_atimespec.tv_nsec;
+	mnsec = st.st_mtimespec.tv_nsec;
+	cnsec = st.st_ctimespec.tv_nsec;
+#else
 	ansec = mnsec = cnsec = 0;
 #endif
+#endif
 	fill_time(v, 7, st.st_atime, ansec);
 	fill_time(v, 8, st.st_mtime, mnsec);
 	fill_time(v, 9, st.st_ctime, cnsec);
@@ -896,6 +920,29 @@ _pystat_fromstructstat(STRUCT_STAT st)
 	PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
 			 PyInt_FromLong((long)st.st_rdev));
 #endif
+#ifdef HAVE_STRUCT_STAT_ST_GEN
+	PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
+			 PyInt_FromLong((long)st.st_gen));
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
+	{
+	  PyObject *val;
+	  unsigned long bsec,bnsec;
+	  bsec = (long)st.st_birthtime;
+#ifdef HAVE_STAT_TV_NSEC2
+	  bnsec = st.st_birthtimespec.tv_nsec;
+#else
+	  bnsec = 0;
+#endif
+	  if (_stat_float_times) {
+	    val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
+	  } else {
+	    val = PyInt_FromLong((long)bsec);
+	  }
+	  PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
+				    val);
+	}
+#endif
 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
 	PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
 			 PyInt_FromLong((long)st.st_flags));
diff --git a/configure b/configure
index 26403dd..213b50c 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 1.485 .
+# From configure.in Revision: 1.486 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.59 for python 2.5.
 #
@@ -16526,6 +16526,226 @@ _ACEOF
 
 fi
 
+echo "$as_me:$LINENO: checking for struct stat.st_gen" >&5
+echo $ECHO_N "checking for struct stat.st_gen... $ECHO_C" >&6
+if test "${ac_cv_member_struct_stat_st_gen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (ac_aggr.st_gen)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_stat_st_gen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (sizeof ac_aggr.st_gen)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_stat_st_gen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_stat_st_gen=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_gen" >&5
+echo "${ECHO_T}$ac_cv_member_struct_stat_st_gen" >&6
+if test $ac_cv_member_struct_stat_st_gen = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_GEN 1
+_ACEOF
+
+
+fi
+
+echo "$as_me:$LINENO: checking for struct stat.st_birthtime" >&5
+echo $ECHO_N "checking for struct stat.st_birthtime... $ECHO_C" >&6
+if test "${ac_cv_member_struct_stat_st_birthtime+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (ac_aggr.st_birthtime)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_stat_st_birthtime=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (sizeof ac_aggr.st_birthtime)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_stat_st_birthtime=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_stat_st_birthtime=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_birthtime" >&5
+echo "${ECHO_T}$ac_cv_member_struct_stat_st_birthtime" >&6
+if test $ac_cv_member_struct_stat_st_birthtime = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
+_ACEOF
+
+
+fi
+
 echo "$as_me:$LINENO: checking for struct stat.st_blocks" >&5
 echo $ECHO_N "checking for struct stat.st_blocks... $ECHO_C" >&6
 if test "${ac_cv_member_struct_stat_st_blocks+set}" = set; then
@@ -20266,6 +20486,73 @@ _ACEOF
 
 fi
 
+# Look for BSD style subsecond timestamps in struct stat
+echo "$as_me:$LINENO: checking for tv_nsec2 in struct stat" >&5
+echo $ECHO_N "checking for tv_nsec2 in struct stat... $ECHO_C" >&6
+if test "${ac_cv_stat_tv_nsec2+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/stat.h>
+int
+main ()
+{
+
+struct stat st;
+st.st_mtimespec.tv_nsec = 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_stat_tv_nsec2=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_stat_tv_nsec2=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+echo "$as_me:$LINENO: result: $ac_cv_stat_tv_nsec2" >&5
+echo "${ECHO_T}$ac_cv_stat_tv_nsec2" >&6
+if test "$ac_cv_stat_tv_nsec2" = yes
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STAT_TV_NSEC2 1
+_ACEOF
+
+fi
+
 # On HP/UX 11.0, mvwdelch is a block with a return statement
 echo "$as_me:$LINENO: checking whether mvwdelch is an expression" >&5
 echo $ECHO_N "checking whether mvwdelch is an expression... $ECHO_C" >&6
diff --git a/configure.in b/configure.in
index 7d6fe82..15a2a06 100644
--- a/configure.in
+++ b/configure.in
@@ -2424,6 +2424,8 @@ AC_STRUCT_TIMEZONE
 AC_CHECK_MEMBERS([struct stat.st_rdev])
 AC_CHECK_MEMBERS([struct stat.st_blksize])
 AC_CHECK_MEMBERS([struct stat.st_flags])
+AC_CHECK_MEMBERS([struct stat.st_gen])
+AC_CHECK_MEMBERS([struct stat.st_birthtime])
 AC_STRUCT_ST_BLOCKS
 
 AC_MSG_CHECKING(for time.h that defines altzone)
@@ -3042,6 +3044,23 @@ then
   [Define if you have struct stat.st_mtim.tv_nsec])
 fi
 
+# Look for BSD style subsecond timestamps in struct stat
+AC_MSG_CHECKING(for tv_nsec2 in struct stat)
+AC_CACHE_VAL(ac_cv_stat_tv_nsec2,
+AC_TRY_COMPILE([#include <sys/stat.h>], [
+struct stat st;
+st.st_mtimespec.tv_nsec = 1;
+],
+ac_cv_stat_tv_nsec2=yes,
+ac_cv_stat_tv_nsec2=no,
+ac_cv_stat_tv_nsec2=no))
+AC_MSG_RESULT($ac_cv_stat_tv_nsec2)
+if test "$ac_cv_stat_tv_nsec2" = yes
+then
+  AC_DEFINE(HAVE_STAT_TV_NSEC2, 1,
+  [Define if you have struct stat.st_mtimensec])
+fi
+
 # On HP/UX 11.0, mvwdelch is a block with a return statement
 AC_MSG_CHECKING(whether mvwdelch is an expression)
 AC_CACHE_VAL(ac_cv_mvwdelch_is_expression,
diff --git a/pyconfig.h.in b/pyconfig.h.in
index a60e4da..47723de 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -455,6 +455,9 @@
 /* Define if you have struct stat.st_mtim.tv_nsec */
 #undef HAVE_STAT_TV_NSEC
 
+/* Define if you have struct stat.st_mtimensec */
+#undef HAVE_STAT_TV_NSEC2
+
 /* Define if your compiler supports variable length function prototypes (e.g.
    void fprintf(FILE *, char *, ...);) *and* <stdarg.h> */
 #undef HAVE_STDARG_PROTOTYPES
@@ -483,6 +486,9 @@
 /* Define to 1 if you have the <stropts.h> header file. */
 #undef HAVE_STROPTS_H
 
+/* Define to 1 if `st_birthtime' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BIRTHTIME
+
 /* Define to 1 if `st_blksize' is member of `struct stat'. */
 #undef HAVE_STRUCT_STAT_ST_BLKSIZE
 
@@ -492,6 +498,9 @@
 /* Define to 1 if `st_flags' is member of `struct stat'. */
 #undef HAVE_STRUCT_STAT_ST_FLAGS
 
+/* Define to 1 if `st_gen' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_GEN
+
 /* Define to 1 if `st_rdev' is member of `struct stat'. */
 #undef HAVE_STRUCT_STAT_ST_RDEV
 
-- 
cgit v0.12

