summaryrefslogtreecommitdiffstats
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
authorLarry Hastings <larry@hastings.org>2011-09-09 02:29:07 (GMT)
committerLarry Hastings <larry@hastings.org>2011-09-09 02:29:07 (GMT)
commit9e3e70b33143be1082f01c14c1be25b0ff0be1bf (patch)
tree0ae3a49ec518b8ca73e0504ef764c66612a7d920 /Modules/posixmodule.c
parentd169fdcb632bbc024b348422e4988537bc7dfd1b (diff)
downloadcpython-9e3e70b33143be1082f01c14c1be25b0ff0be1bf.zip
cpython-9e3e70b33143be1082f01c14c1be25b0ff0be1bf.tar.gz
cpython-9e3e70b33143be1082f01c14c1be25b0ff0be1bf.tar.bz2
Issue #12904: os.utime, os.futimes, os.lutimes, and os.futimesat now write
atime and mtime with nanosecond precision on modern POSIX platforms.
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c152
1 files changed, 110 insertions, 42 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 9019415..d67cada 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -3417,6 +3417,30 @@ posix_uname(PyObject *self, PyObject *noargs)
}
#endif /* HAVE_UNAME */
+
+/*
+ * Classic POSIX utime functions supported microseconds (1m/sec).
+ * Newer POSIX functions support nanoseconds (1 billion per sec).
+ * posixmodule now uses the new functions where possible.
+ * This improves accuracy in many situations, for example shutil.copy2().
+ *
+ * The implementation isn't currently sophisticated enough to handle
+ * a platform where HAVE_UTIMENSAT is true but HAVE_FUTIMENS is false.
+ * Specifically, posix_futimes() would break.
+ *
+ * Supporting such a platform wouldn't be impossible; you'd need two
+ * extract_time() functions, or make its precision a parameter.
+ * Since such a platform seems unlikely we haven't bothered.
+ */
+#if defined(HAVE_UTIMENSAT)
+#define EXTRACT_TIME_PRECISION (1e9)
+#if !defined(HAVE_FUTIMENS)
+#error You HAVE_UTIMENSAT but not HAVE_FUTIMENS... please see accompanying comment.
+#endif
+#else
+#define EXTRACT_TIME_PRECISION (1e6)
+#endif
+
static int
extract_time(PyObject *t, time_t* sec, long* usec)
{
@@ -3435,7 +3459,8 @@ extract_time(PyObject *t, time_t* sec, long* usec)
if (intval == -1 && PyErr_Occurred())
return -1;
*sec = intval;
- *usec = (long)((tval - intval) * 1e6); /* can't exceed 1000000 */
+
+ *usec = (long)((tval - intval) * EXTRACT_TIME_PRECISION);
if (*usec < 0)
/* If rounding gave us a negative number,
truncate. */
@@ -3553,24 +3578,6 @@ done:
int res;
PyObject* arg;
-#if defined(HAVE_UTIMES)
- struct timeval buf[2];
-#define ATIME buf[0].tv_sec
-#define MTIME buf[1].tv_sec
-#elif defined(HAVE_UTIME_H)
-/* XXX should define struct utimbuf instead, above */
- struct utimbuf buf;
-#define ATIME buf.actime
-#define MTIME buf.modtime
-#define UTIME_ARG &buf
-#else /* HAVE_UTIMES */
- time_t buf[2];
-#define ATIME buf[0]
-#define MTIME buf[1]
-#define UTIME_ARG buf
-#endif /* HAVE_UTIMES */
-
-
if (!PyArg_ParseTuple(args, "O&O:utime",
PyUnicode_FSConverter, &opath, &arg))
return NULL;
@@ -3598,19 +3605,37 @@ done:
Py_DECREF(opath);
return NULL;
}
- ATIME = atime;
- MTIME = mtime;
-#ifdef HAVE_UTIMES
+
+ Py_BEGIN_ALLOW_THREADS
+ {
+#ifdef HAVE_UTIMENSAT
+ struct timespec buf[2];
+ buf[0].tv_sec = atime;
+ buf[0].tv_nsec = ausec;
+ buf[1].tv_sec = mtime;
+ buf[1].tv_nsec = musec;
+ res = utimensat(AT_FDCWD, path, buf, 0);
+#elif defined(HAVE_UTIMES)
+ struct timeval buf[2];
+ buf[0].tv_sec = atime;
buf[0].tv_usec = ausec;
+ buf[1].tv_sec = mtime;
buf[1].tv_usec = musec;
- Py_BEGIN_ALLOW_THREADS
res = utimes(path, buf);
- Py_END_ALLOW_THREADS
+#elif defined(HAVE_UTIME_H)
+ /* XXX should define struct utimbuf instead, above */
+ struct utimbuf buf;
+ buf.actime = atime;
+ buf.modtime = mtime;
+ res = utime(path, &buf);
#else
- Py_BEGIN_ALLOW_THREADS
- res = utime(path, UTIME_ARG);
+ time_t buf[2];
+ buf[0] = atime;
+ buf[1] = mtime;
+ res = utime(path, buf);
+#endif
+ }
Py_END_ALLOW_THREADS
-#endif /* HAVE_UTIMES */
}
if (res < 0) {
return posix_error_with_allocated_filename(opath);
@@ -3618,9 +3643,7 @@ done:
Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
-#undef UTIME_ARG
-#undef ATIME
-#undef MTIME
+#undef UTIME_EXTRACT
#endif /* MS_WINDOWS */
}
@@ -3637,7 +3660,7 @@ posix_futimes(PyObject *self, PyObject *args)
{
int res, fd;
PyObject* arg;
- struct timeval buf[2];
+ time_t atime, mtime;
long ausec, musec;
if (!PyArg_ParseTuple(args, "iO:futimes", &fd, &arg))
@@ -3656,17 +3679,31 @@ posix_futimes(PyObject *self, PyObject *args)
}
else {
if (extract_time(PyTuple_GET_ITEM(arg, 0),
- &(buf[0].tv_sec), &ausec) == -1) {
+ &atime, &ausec) == -1) {
return NULL;
}
if (extract_time(PyTuple_GET_ITEM(arg, 1),
- &(buf[1].tv_sec), &musec) == -1) {
+ &mtime, &musec) == -1) {
return NULL;
}
+ Py_BEGIN_ALLOW_THREADS
+ {
+#ifdef HAVE_FUTIMENS
+ struct timespec buf[2];
+ buf[0].tv_sec = atime;
+ buf[0].tv_nsec = ausec;
+ buf[1].tv_sec = mtime;
+ buf[1].tv_nsec = musec;
+ res = futimens(fd, buf);
+#else
+ struct timeval buf[2];
+ buf[0].tv_sec = atime;
buf[0].tv_usec = ausec;
+ buf[1].tv_sec = mtime;
buf[1].tv_usec = musec;
- Py_BEGIN_ALLOW_THREADS
res = futimes(fd, buf);
+#endif
+ }
Py_END_ALLOW_THREADS
}
if (res < 0)
@@ -3687,7 +3724,7 @@ posix_lutimes(PyObject *self, PyObject *args)
PyObject *opath, *arg;
const char *path;
int res;
- struct timeval buf[2];
+ time_t atime, mtime;
long ausec, musec;
if (!PyArg_ParseTuple(args, "O&O:lutimes",
@@ -3708,19 +3745,33 @@ posix_lutimes(PyObject *self, PyObject *args)
}
else {
if (extract_time(PyTuple_GET_ITEM(arg, 0),
- &(buf[0].tv_sec), &ausec) == -1) {
+ &atime, &ausec) == -1) {
Py_DECREF(opath);
return NULL;
}
if (extract_time(PyTuple_GET_ITEM(arg, 1),
- &(buf[1].tv_sec), &musec) == -1) {
+ &mtime, &musec) == -1) {
Py_DECREF(opath);
return NULL;
}
+ Py_BEGIN_ALLOW_THREADS
+ {
+#ifdef HAVE_UTIMENSAT
+ struct timespec buf[2];
+ buf[0].tv_sec = atime;
+ buf[0].tv_nsec = ausec;
+ buf[1].tv_sec = mtime;
+ buf[1].tv_nsec = musec;
+ res = utimensat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+#else
+ struct timeval buf[2];
+ buf[0].tv_sec = atime;
buf[0].tv_usec = ausec;
+ buf[1].tv_sec = mtime;
buf[1].tv_usec = musec;
- Py_BEGIN_ALLOW_THREADS
res = lutimes(path, buf);
+#endif
+ }
Py_END_ALLOW_THREADS
}
Py_DECREF(opath);
@@ -9558,8 +9609,8 @@ posix_futimesat(PyObject *self, PyObject *args)
char *path;
int res, dirfd;
PyObject* arg;
-
- struct timeval buf[2];
+ time_t atime, mtime;
+ long ausec, musec;
if (!PyArg_ParseTuple(args, "iO&O:futimesat",
&dirfd, PyUnicode_FSConverter, &opath, &arg))
@@ -9579,17 +9630,34 @@ posix_futimesat(PyObject *self, PyObject *args)
}
else {
if (extract_time(PyTuple_GET_ITEM(arg, 0),
- &(buf[0].tv_sec), &(buf[0].tv_usec)) == -1) {
+ &atime, &ausec) == -1) {
Py_DECREF(opath);
return NULL;
}
if (extract_time(PyTuple_GET_ITEM(arg, 1),
- &(buf[1].tv_sec), &(buf[1].tv_usec)) == -1) {
+ &mtime, &musec) == -1) {
Py_DECREF(opath);
return NULL;
}
+
Py_BEGIN_ALLOW_THREADS
+ {
+#ifdef HAVE_UTIMENSAT
+ struct timespec buf[2];
+ buf[0].tv_sec = atime;
+ buf[0].tv_nsec = ausec;
+ buf[1].tv_sec = mtime;
+ buf[1].tv_nsec = musec;
+ res = utimensat(dirfd, path, buf, 0);
+#else
+ struct timeval buf[2];
+ buf[0].tv_sec = atime;
+ buf[0].tv_usec = ausec;
+ buf[1].tv_sec = mtime;
+ buf[1].tv_usec = musec;
res = futimesat(dirfd, path, buf);
+#endif
+ }
Py_END_ALLOW_THREADS
}
Py_DECREF(opath);