From 85982e45546486479d09d0409d0c70b7b73a1013 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Wed, 18 Dec 2013 22:16:44 -0600 Subject: [PATCH] Don't require non-negative timespec ns; fix stat timestamp conversions. Previously we required that the system timespec tv_nsec values be non-negative -- stop that. POSIX doesn't specify, and there's no real need for us to care, since all significant timestamp manipulations are now handled as integer nanosecond values, not (sec, ns) pairs. Change stat_struct_to_py() (used by bup_stat()/bup_lstat()) to use INTEGER_TO_PY() to convert the timestamp st_atime/st_mtime/st_ctime values so that we don't have to care about the sign/size of the underlying type (which should be time_t). Signed-off-by: Rob Browning --- lib/bup/_helpers.c | 73 ++++++--------------------------------------- lib/bup/t/txstat.py | 2 +- lib/bup/xstat.py | 5 +--- 3 files changed, 11 insertions(+), 69 deletions(-) diff --git a/lib/bup/_helpers.c b/lib/bup/_helpers.c index 673ae8a..65160bf 100644 --- a/lib/bup/_helpers.c +++ b/lib/bup/_helpers.c @@ -948,48 +948,6 @@ static PyObject *bup_lutimes(PyObject *self, PyObject *args) #endif -static void set_invalid_timespec_msg(const char *field, - const long long sec, - const long nsec, - const char *filename, - int fd) -{ - if (filename != NULL) - PyErr_Format(PyExc_ValueError, - "invalid %s timespec (%lld %ld) for file \"%s\"", - field, sec, nsec, filename); - else - PyErr_Format(PyExc_ValueError, - "invalid %s timespec (%lld %ld) for file descriptor %d", - field, sec, nsec, fd); -} - - -static int normalize_timespec_values(const char *name, - long long *sec, - long *nsec, - const char *filename, - int fd) -{ - if (*nsec < -999999999 || *nsec > 999999999) - { - set_invalid_timespec_msg(name, *sec, *nsec, filename, fd); - return 0; - } - if (*nsec < 0) - { - if (*sec == LONG_MIN) - { - set_invalid_timespec_msg(name, *sec, *nsec, filename, fd); - return 0; - } - *nsec += 1000000000; - *sec -= 1; - } - return 1; -} - - #define INTEGER_TO_PY(x) \ (((x) >= 0) ? PyLong_FromUnsignedLongLong(x) : PyLong_FromLongLong(x)) @@ -998,24 +956,11 @@ static PyObject *stat_struct_to_py(const struct stat *st, const char *filename, int fd) { - long long atime = st->st_atime; - long long mtime = st->st_mtime; - long long ctime = st->st_ctime; - long atime_ns = BUP_STAT_ATIME_NS(st); - long mtime_ns = BUP_STAT_MTIME_NS(st); - long ctime_ns = BUP_STAT_CTIME_NS(st); - - if (!normalize_timespec_values("atime", &atime, &atime_ns, filename, fd)) - return NULL; - if (!normalize_timespec_values("mtime", &mtime, &mtime_ns, filename, fd)) - return NULL; - if (!normalize_timespec_values("ctime", &ctime, &ctime_ns, filename, fd)) - return NULL; - // We can check the known (via POSIX) signed and unsigned types at // compile time, but not (easily) the unspecified types, so handle - // those via INTEGER_TO_PY(). - return Py_BuildValue("OKOOOOOL(Ll)(Ll)(Ll)", + // those via INTEGER_TO_PY(). Assumes ns values will fit in a + // long. + return Py_BuildValue("OKOOOOOL(Ol)(Ol)(Ol)", INTEGER_TO_PY(st->st_mode), (unsigned PY_LONG_LONG) st->st_ino, INTEGER_TO_PY(st->st_dev), @@ -1024,12 +969,12 @@ static PyObject *stat_struct_to_py(const struct stat *st, INTEGER_TO_PY(st->st_gid), INTEGER_TO_PY(st->st_rdev), (PY_LONG_LONG) st->st_size, - (PY_LONG_LONG) atime, - (long) atime_ns, - (PY_LONG_LONG) mtime, - (long) mtime_ns, - (PY_LONG_LONG) ctime, - (long) ctime_ns); + INTEGER_TO_PY(st->st_atime), + (long) BUP_STAT_ATIME_NS(st), + INTEGER_TO_PY(st->st_mtime), + (long) BUP_STAT_MTIME_NS(st), + INTEGER_TO_PY(st->st_ctime), + (long) BUP_STAT_CTIME_NS(st)); } diff --git a/lib/bup/t/txstat.py b/lib/bup/t/txstat.py index 1d4bad3..412e71d 100644 --- a/lib/bup/t/txstat.py +++ b/lib/bup/t/txstat.py @@ -12,7 +12,7 @@ def test_fstime(): WVPASSEQ(xstat.timespec_to_nsecs((-1, 0)), -10**9) WVPASSEQ(xstat.timespec_to_nsecs((-1, 10**9 / 2)), -500000000) WVPASSEQ(xstat.timespec_to_nsecs((-2, 10**9 / 2)), -1500000000) - WVEXCEPT(Exception, xstat.timespec_to_nsecs, (0, -1)) + WVPASSEQ(xstat.timespec_to_nsecs((0, -1)), -1) WVPASSEQ(type(xstat.timespec_to_nsecs((2, 22222222))), type(0)) WVPASSEQ(type(xstat.timespec_to_nsecs((-2, 22222222))), type(0)) diff --git a/lib/bup/xstat.py b/lib/bup/xstat.py index 23483f5..8daa2c2 100644 --- a/lib/bup/xstat.py +++ b/lib/bup/xstat.py @@ -20,15 +20,12 @@ except AttributeError, e: def timespec_to_nsecs((ts_s, ts_ns)): - # c.f. _helpers.c: timespec_vals_to_py_ns() - if ts_ns < 0 or ts_ns > 999999999: - raise Exception('invalid timespec nsec value') return ts_s * 10**9 + ts_ns def nsecs_to_timespec(ns): """Return (s, ns) where ns is always non-negative - and t = s + ns / 10e8""" # metadata record rep (and libc rep) + and t = s + ns / 10e8""" # metadata record rep ns = int(ns) return (ns / 10**9, ns % 10**9) -- 2.39.2