+#if defined(linux) && defined(FS_IOC_GETFLAGS)
+static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args)
+{
+ int rc;
+ unsigned long attr;
+ char *path;
+ int fd;
+
+ if (!PyArg_ParseTuple(args, "s", &path))
+ return NULL;
+
+ fd = open(path, O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_NOFOLLOW);
+ if (fd == -1)
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
+
+ attr = 0;
+ rc = ioctl(fd, FS_IOC_GETFLAGS, &attr);
+ if (rc == -1)
+ {
+ close(fd);
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
+ }
+
+ close(fd);
+ return Py_BuildValue("k", attr);
+}
+
+
+static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
+{
+ int rc;
+ unsigned long attr;
+ char *path;
+ int fd;
+
+ if (!PyArg_ParseTuple(args, "sk", &path, &attr))
+ return NULL;
+
+ fd = open(path, O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_NOFOLLOW);
+ if (fd == -1)
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
+
+ rc = ioctl(fd, FS_IOC_SETFLAGS, &attr);
+ if (rc == -1)
+ {
+ close(fd);
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
+ }
+
+ close(fd);
+ return Py_BuildValue("i", 1);
+}
+#endif /* def linux */
+
+#ifdef HAVE_UTIMENSAT
+#if defined(_ATFILE_SOURCE) \
+ || _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
+#define HAVE_BUP_UTIMENSAT 1
+
+static PyObject *bup_utimensat(PyObject *self, PyObject *args)
+{
+ int rc, dirfd, flags;
+ char *path;
+ long access, access_ns, modification, modification_ns;
+ struct timespec ts[2];
+
+ if (!PyArg_ParseTuple(args, "is((ll)(ll))i",
+ &dirfd,
+ &path,
+ &access, &access_ns,
+ &modification, &modification_ns,
+ &flags))
+ return NULL;
+
+ if (isnan(access))
+ {
+ PyErr_SetString(PyExc_ValueError, "access time is NaN");
+ return NULL;
+ }
+ else if (isinf(access))
+ {
+ PyErr_SetString(PyExc_ValueError, "access time is infinite");
+ return NULL;
+ }
+ else if (isnan(modification))
+ {
+ PyErr_SetString(PyExc_ValueError, "modification time is NaN");
+ return NULL;
+ }
+ else if (isinf(modification))
+ {
+ PyErr_SetString(PyExc_ValueError, "modification time is infinite");
+ return NULL;
+ }
+
+ if (isnan(access_ns))
+ {
+ PyErr_SetString(PyExc_ValueError, "access time ns is NaN");
+ return NULL;
+ }
+ else if (isinf(access_ns))
+ {
+ PyErr_SetString(PyExc_ValueError, "access time ns is infinite");
+ return NULL;
+ }
+ else if (isnan(modification_ns))
+ {
+ PyErr_SetString(PyExc_ValueError, "modification time ns is NaN");
+ return NULL;
+ }
+ else if (isinf(modification_ns))
+ {
+ PyErr_SetString(PyExc_ValueError, "modification time ns is infinite");
+ 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(dirfd, path, ts, flags);
+ if (rc != 0)
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
+
+ return Py_BuildValue("i", 1);
+}
+
+#endif /* defined(_ATFILE_SOURCE)
+ || _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L */
+#endif /* HAVE_UTIMENSAT */
+
+#ifdef linux /* and likely others */
+
+#define HAVE_BUP_STAT 1
+static PyObject *bup_stat(PyObject *self, PyObject *args)
+{
+ int rc;
+ char *filename;
+
+ if (!PyArg_ParseTuple(args, "s", &filename))
+ return NULL;
+
+ struct stat st;
+ rc = stat(filename, &st);
+ if (rc != 0)
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+
+ return Py_BuildValue("kkkkkkkk"
+ "(ll)"
+ "(ll)"
+ "(ll)",
+ (unsigned long) st.st_mode,
+ (unsigned long) st.st_ino,
+ (unsigned long) st.st_dev,
+ (unsigned long) st.st_nlink,
+ (unsigned long) st.st_uid,
+ (unsigned long) st.st_gid,
+ (unsigned long) st.st_rdev,
+ (unsigned long) st.st_size,
+ (long) st.st_atime,
+ (long) st.st_atim.tv_nsec,
+ (long) st.st_mtime,
+ (long) st.st_mtim.tv_nsec,
+ (long) st.st_ctime,
+ (long) st.st_ctim.tv_nsec);
+}
+
+
+#define HAVE_BUP_LSTAT 1
+static PyObject *bup_lstat(PyObject *self, PyObject *args)
+{
+ int rc;
+ char *filename;
+
+ if (!PyArg_ParseTuple(args, "s", &filename))
+ return NULL;
+
+ struct stat st;
+ rc = lstat(filename, &st);
+ if (rc != 0)
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+
+ return Py_BuildValue("kkkkkkkk"
+ "(ll)"
+ "(ll)"
+ "(ll)",
+ (unsigned long) st.st_mode,
+ (unsigned long) st.st_ino,
+ (unsigned long) st.st_dev,
+ (unsigned long) st.st_nlink,
+ (unsigned long) st.st_uid,
+ (unsigned long) st.st_gid,
+ (unsigned long) st.st_rdev,
+ (unsigned long) st.st_size,
+ (long) st.st_atime,
+ (long) st.st_atim.tv_nsec,
+ (long) st.st_mtime,
+ (long) st.st_mtim.tv_nsec,
+ (long) st.st_ctime,
+ (long) st.st_ctim.tv_nsec);
+}
+
+
+#define HAVE_BUP_FSTAT 1
+static PyObject *bup_fstat(PyObject *self, PyObject *args)
+{
+ int rc, fd;
+
+ if (!PyArg_ParseTuple(args, "i", &fd))
+ return NULL;
+
+ struct stat st;
+ rc = fstat(fd, &st);
+ if (rc != 0)
+ return PyErr_SetFromErrno(PyExc_OSError);
+
+ return Py_BuildValue("kkkkkkkk"
+ "(ll)"
+ "(ll)"
+ "(ll)",
+ (unsigned long) st.st_mode,
+ (unsigned long) st.st_ino,
+ (unsigned long) st.st_dev,
+ (unsigned long) st.st_nlink,
+ (unsigned long) st.st_uid,
+ (unsigned long) st.st_gid,
+ (unsigned long) st.st_rdev,
+ (unsigned long) st.st_size,
+ (long) st.st_atime,
+ (long) st.st_atim.tv_nsec,
+ (long) st.st_mtime,
+ (long) st.st_mtim.tv_nsec,
+ (long) st.st_ctime,
+ (long) st.st_ctim.tv_nsec);
+}
+
+#endif /* def linux */
+
+
+static PyMethodDef helper_methods[] = {