static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args)
{
int rc;
- unsigned long attr;
+ unsigned int attr;
char *path;
int fd;
}
close(fd);
- return Py_BuildValue("k", attr);
+ return Py_BuildValue("I", attr);
}
#endif /* def BUP_HAVE_FILE_ATTRS */
static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
{
int rc;
- unsigned long orig_attr, attr;
+ unsigned int orig_attr, attr;
char *path;
int fd;
- if (!PyArg_ParseTuple(args, "sk", &path, &attr))
+ if (!PyArg_ParseTuple(args, "sI", &path, &attr))
return NULL;
fd = open(path, O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_NOFOLLOW);
#endif /* def BUP_HAVE_FILE_ATTRS */
+#ifndef HAVE_UTIMENSAT
+#ifndef HAVE_UTIMES
+#error "cannot find utimensat or utimes()"
+#endif
+#ifndef HAVE_LUTIMES
+#error "cannot find utimensat or lutimes()"
+#endif
+#endif
+
+
#if defined(HAVE_UTIMENSAT) || defined(HAVE_FUTIMES) || defined(HAVE_LUTIMES)
static int bup_parse_xutime_args(char **path,
access, access_ns,
modification, modification_ns))
return 0;
-
- if (isnan(*access))
- {
- PyErr_SetString(PyExc_ValueError, "access time is NaN");
- return 0;
- }
- else if (isinf(*access))
- {
- PyErr_SetString(PyExc_ValueError, "access time is infinite");
- return 0;
- }
- else if (isnan(*modification))
- {
- PyErr_SetString(PyExc_ValueError, "modification time is NaN");
- return 0;
- }
- else if (isinf(*modification))
- {
- PyErr_SetString(PyExc_ValueError, "modification time is infinite");
- return 0;
- }
-
- if (isnan(*access_ns))
- {
- PyErr_SetString(PyExc_ValueError, "access time ns is NaN");
- return 0;
- }
- else if (isinf(*access_ns))
- {
- PyErr_SetString(PyExc_ValueError, "access time ns is infinite");
- return 0;
- }
- else if (isnan(*modification_ns))
- {
- PyErr_SetString(PyExc_ValueError, "modification time ns is NaN");
- return 0;
- }
- else if (isinf(*modification_ns))
- {
- PyErr_SetString(PyExc_ValueError, "modification time ns is infinite");
- return 0;
- }
-
return 1;
}
|| defined(HAVE_LUTIMES) */
+#define INTEGRAL_ASSIGNMENT_FITS(dest, src) \
+ ({ \
+ *(dest) = (src); \
+ *(dest) == (src) && (*(dest) < 1) == ((src) < 1); \
+ })
+
+
+#define ASSIGN_PYLONG_TO_INTEGRAL(dest, pylong, overflow) \
+ ({ \
+ int result = 0; \
+ *(overflow) = 0; \
+ const long long ltmp = PyLong_AsLongLong(pylong); \
+ if (ltmp == -1 && PyErr_Occurred()) \
+ { \
+ if (PyErr_ExceptionMatches(PyExc_OverflowError)) \
+ { \
+ const unsigned long ultmp = PyLong_AsUnsignedLongLong(pylong); \
+ if (ultmp == (unsigned long long) -1 && PyErr_Occurred()) \
+ { \
+ if (PyErr_ExceptionMatches(PyExc_OverflowError)) \
+ { \
+ PyErr_Clear(); \
+ *(overflow) = 1; \
+ } \
+ } \
+ if (INTEGRAL_ASSIGNMENT_FITS((dest), ultmp)) \
+ result = 1; \
+ else \
+ *(overflow) = 1; \
+ } \
+ } \
+ else \
+ { \
+ if (INTEGRAL_ASSIGNMENT_FITS((dest), ltmp)) \
+ result = 1; \
+ else \
+ *(overflow) = 1; \
+ } \
+ result; \
+ })
+
+
#ifdef HAVE_UTIMENSAT
-static PyObject *bup_xutime_ns(PyObject *self, PyObject *args,
- int follow_symlinks)
+static PyObject *bup_utimensat(PyObject *self, PyObject *args)
{
int rc;
+ int fd, flag;
char *path;
- long access, access_ns, modification, modification_ns;
+ PyObject *access_py, *modification_py;
struct timespec ts[2];
- if (!bup_parse_xutime_args(&path, &access, &access_ns,
- &modification, &modification_ns,
- self, args))
- return NULL;
+ if (!PyArg_ParseTuple(args, "is((Ol)(Ol))i",
+ &fd,
+ &path,
+ &access_py, &(ts[0].tv_nsec),
+ &modification_py, &(ts[1].tv_nsec),
+ &flag))
+ return NULL;
- ts[0].tv_sec = access;
- ts[0].tv_nsec = access_ns;
- ts[1].tv_sec = modification;
- ts[1].tv_nsec = modification_ns;
- rc = utimensat(AT_FDCWD, path, ts,
- follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
+ int overflow;
+ if (!ASSIGN_PYLONG_TO_INTEGRAL(&(ts[0].tv_sec), access_py, &overflow))
+ {
+ if (overflow)
+ PyErr_SetString(PyExc_ValueError,
+ "unable to convert access time seconds for utimensat");
+ return NULL;
+ }
+ if (!ASSIGN_PYLONG_TO_INTEGRAL(&(ts[1].tv_sec), modification_py, &overflow))
+ {
+ if (overflow)
+ PyErr_SetString(PyExc_ValueError,
+ "unable to convert modification time seconds for utimensat");
+ return NULL;
+ }
+ rc = utimensat(fd, path, ts, flag);
if (rc != 0)
return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
return Py_BuildValue("O", Py_None);
}
-
-#define BUP_HAVE_BUP_UTIME_NS 1
-static PyObject *bup_utime_ns(PyObject *self, PyObject *args)
-{
- return bup_xutime_ns(self, args, 1);
-}
-
-
-#define BUP_HAVE_BUP_LUTIME_NS 1
-static PyObject *bup_lutime_ns(PyObject *self, PyObject *args)
-{
- return bup_xutime_ns(self, args, 0);
-}
-
-
-#else /* not defined(HAVE_UTIMENSAT) */
+#endif /* def HAVE_UTIMENSAT */
#ifdef HAVE_UTIMES
#endif /* def HAVE_LUTIMES */
-#endif /* not defined(HAVE_UTIMENSAT) */
-
-
#ifdef HAVE_STAT_ST_ATIM
# define BUP_STAT_ATIME_NS(st) (st)->st_atim.tv_nsec
# define BUP_STAT_MTIME_NS(st) (st)->st_mtim.tv_nsec
}
-#define CHECK_VALUE_FITS(name, value, src_type, dest_type, max_value) \
-if (sizeof(src_type) >= sizeof(dest_type) && (value) > (max_value)) \
-{ \
- PyErr_SetString(PyExc_OverflowError, \
- name " cannot be converted to integer"); \
- return NULL; \
-}
+#define INTEGER_TO_PY(x) \
+ (((x) >= 0) ? PyLong_FromUnsignedLongLong(x) : PyLong_FromLongLong(x))
static PyObject *stat_struct_to_py(const struct stat *st,
return NULL;
// We can check the known (via POSIX) signed and unsigned types at
- // compile time, but not (easily) the unspecified types. Ideally,
- // some of these will be optimized out at compile time.
- CHECK_VALUE_FITS("stat st_mode", st->st_mode, mode_t, PY_LONG_LONG, PY_LLONG_MAX);
- CHECK_VALUE_FITS("stat st_dev", st->st_dev, dev_t, PY_LONG_LONG, PY_LLONG_MAX);
- CHECK_VALUE_FITS("stat st_uid", st->st_uid, uid_t, PY_LONG_LONG, PY_LLONG_MAX);
- CHECK_VALUE_FITS("stat st_gid", st->st_uid, uid_t, PY_LONG_LONG, PY_LLONG_MAX);
- CHECK_VALUE_FITS("stat st_nlink", st->st_nlink, nlink_t, PY_LONG_LONG, PY_LLONG_MAX);
- CHECK_VALUE_FITS("stat st_rdev", st->st_rdev, dev_t, PY_LONG_LONG, PY_LLONG_MAX);
-
- return Py_BuildValue("LKLLLLLL(Ll)(Ll)(Ll)",
- (PY_LONG_LONG) st->st_mode,
+ // compile time, but not (easily) the unspecified types, so handle
+ // those via INTEGER_TO_PY().
+ return Py_BuildValue("OKOOOOOL(Ll)(Ll)(Ll)",
+ INTEGER_TO_PY(st->st_mode),
(unsigned PY_LONG_LONG) st->st_ino,
- (PY_LONG_LONG) st->st_dev,
- (PY_LONG_LONG) st->st_nlink,
- (PY_LONG_LONG) st->st_uid,
- (PY_LONG_LONG) st->st_gid,
- (PY_LONG_LONG) st->st_rdev,
+ INTEGER_TO_PY(st->st_dev),
+ INTEGER_TO_PY(st->st_nlink),
+ INTEGER_TO_PY(st->st_uid),
+ 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,
{ "set_linux_file_attr", bup_set_linux_file_attr, METH_VARARGS,
"Set the Linux attributes for the given file." },
#endif
+#ifdef HAVE_UTIMENSAT
+ { "bup_utimensat", bup_utimensat, METH_VARARGS,
+ "Change path timestamps with nanosecond precision (POSIX)." },
+#endif
#ifdef BUP_HAVE_BUP_UTIME_NS
{ "bup_utime_ns", bup_utime_ns, METH_VARARGS,
"Change path timestamps with up to nanosecond precision." },
PyObject *m = Py_InitModule("_helpers", helper_methods);
if (m == NULL)
return;
+
+#ifdef HAVE_UTIMENSAT
+ {
+ PyObject *value;
+ value = INTEGER_TO_PY(AT_FDCWD);
+ PyObject_SetAttrString(m, "AT_FDCWD", value);
+ Py_DECREF(value);
+ value = INTEGER_TO_PY(AT_SYMLINK_NOFOLLOW);
+ PyObject_SetAttrString(m, "AT_SYMLINK_NOFOLLOW", value);
+ Py_DECREF(value);
+ value = INTEGER_TO_PY(UTIME_NOW);
+ PyObject_SetAttrString(m, "UTIME_NOW", value);
+ Py_DECREF(value);
+ }
+#endif
+
e = getenv("BUP_FORCE_TTY");
istty2 = isatty(2) || (atoi(e ? e : "0") & 2);
unpythonize_argv();