]> arthur.barton.de Git - bup.git/blobdiff - lib/bup/_helpers.c
Assume FS_IOC_GETFLAGS may trash output on error
[bup.git] / lib / bup / _helpers.c
index 2af13bb27d595e17aa5786cf18b96e0a2f049d10..9082dca72994079da1f900f8785f751a3d52715c 100644 (file)
 #define BUP_HAVE_FILE_ATTRS 1
 #endif
 
+/*
+ * Check for incomplete UTIMENSAT support (NetBSD 6), and if so,
+ * pretend we don't have it.
+ */
+#if !defined(AT_FDCWD) || !defined(AT_SYMLINK_NOFOLLOW)
+#undef HAVE_UTIMENSAT
+#endif
+
 #ifndef FS_NOCOW_FL
 // Of course, this assumes it's a bitfield value.
 #define FS_NOCOW_FL 0
 
 static int istty2 = 0;
 
+
+#ifndef htonll
+// This function should technically be macro'd out if it's going to be used
+// more than ocasionally.  As of this writing, it'll actually never be called
+// in real world bup scenarios (because our packs are < MAX_INT bytes).
+static uint64_t htonll(uint64_t value)
+{
+    static const int endian_test = 42;
+
+    if (*(char *)&endian_test == endian_test) // LSB-MSB
+       return ((uint64_t)htonl(value & 0xFFFFFFFF) << 32) | htonl(value >> 32);
+    return value; // already in network byte order MSB-LSB
+}
+#endif
+
+
 // At the moment any code that calls INTGER_TO_PY() will have to
 // disable -Wtautological-compare for clang.  See below.
 
@@ -578,18 +602,6 @@ static PyObject *merge_into(PyObject *self, PyObject *args)
     return PyLong_FromUnsignedLong(count);
 }
 
-// This function should technically be macro'd out if it's going to be used
-// more than ocasionally.  As of this writing, it'll actually never be called
-// in real world bup scenarios (because our packs are < MAX_INT bytes).
-static uint64_t htonll(uint64_t value)
-{
-    static const int endian_test = 42;
-
-    if (*(char *)&endian_test == endian_test) // LSB-MSB
-       return ((uint64_t)htonl(value & 0xFFFFFFFF) << 32) | htonl(value >> 32);
-    return value; // already in network byte order MSB-LSB
-}
-
 #define FAN_ENTRIES 256
 
 static PyObject *write_idx(PyObject *self, PyObject *args)
@@ -803,11 +815,21 @@ static PyObject *fadvise_done(PyObject *self, PyObject *args)
 }
 
 
+// Currently the Linux kernel and FUSE disagree over the type for
+// FS_IOC_GETFLAGS and FS_IOC_SETFLAGS.  The kernel actually uses int,
+// but FUSE chose long (matching the declaration in linux/fs.h).  So
+// if you use int, and then traverse a FUSE filesystem, you may
+// corrupt the stack.  But if you use long, then you may get invalid
+// results on big-endian systems.
+//
+// For now, we just use long, and then disable Linux attrs entirely
+// (with a warning) in helpers.py on systems that are affected.
+
 #ifdef BUP_HAVE_FILE_ATTRS
 static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args)
 {
     int rc;
-    unsigned int attr;
+    unsigned long attr;
     char *path;
     int fd;
 
@@ -818,16 +840,16 @@ static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args)
     if (fd == -1)
         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
 
-    attr = 0;
+    attr = 0;  // Handle int/long mismatch (see above)
     rc = ioctl(fd, FS_IOC_GETFLAGS, &attr);
     if (rc == -1)
     {
         close(fd);
         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
     }
-
     close(fd);
-    return Py_BuildValue("I", attr);
+    assert(attr <= UINT_MAX);  // Kernel type is actually int
+    return PyLong_FromUnsignedLong(attr);
 }
 #endif /* def BUP_HAVE_FILE_ATTRS */
 
@@ -837,7 +859,8 @@ static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args)
 static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
 {
     int rc;
-    unsigned int orig_attr, attr;
+    unsigned long orig_attr;
+    unsigned int attr;
     char *path;
     PyObject *py_attr;
     int fd;
@@ -861,13 +884,15 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
     | FS_TOPDIR_FL | FS_NOCOW_FL;
 
     // The extents flag can't be removed, so don't (see chattr(1) and chattr.c).
+    orig_attr = 0; // Handle int/long mismatch (see above)
     rc = ioctl(fd, FS_IOC_GETFLAGS, &orig_attr);
+    assert(orig_attr <= UINT_MAX);  // Kernel type is actually int
     if (rc == -1)
     {
         close(fd);
         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
     }
-    attr |= (orig_attr & FS_EXTENT_FL);
+    attr |= ((unsigned int) orig_attr) & FS_EXTENT_FL;
 
     rc = ioctl(fd, FS_IOC_SETFLAGS, &attr);
     if (rc == -1)
@@ -903,13 +928,13 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
     ({                                                     \
         int result = 0;                                                 \
         *(overflow) = 0;                                                \
-        const long long ltmp = PyLong_AsLongLong(pylong);               \
-        if (ltmp == -1 && PyErr_Occurred())                             \
+        const long long lltmp = PyLong_AsLongLong(pylong);              \
+        if (lltmp == -1 && PyErr_Occurred())                            \
         {                                                               \
             if (PyErr_ExceptionMatches(PyExc_OverflowError))            \
             {                                                           \
-                const unsigned long ultmp = PyLong_AsUnsignedLongLong(pylong); \
-                if (ultmp == (unsigned long long) -1 && PyErr_Occurred()) \
+                const unsigned long long ulltmp = PyLong_AsUnsignedLongLong(pylong); \
+                if (ulltmp == (unsigned long long) -1 && PyErr_Occurred()) \
                 {                                                       \
                     if (PyErr_ExceptionMatches(PyExc_OverflowError))    \
                     {                                                   \
@@ -917,7 +942,7 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
                         *(overflow) = 1;                                \
                     }                                                   \
                 }                                                       \
-                if (INTEGRAL_ASSIGNMENT_FITS((dest), ultmp))            \
+                if (INTEGRAL_ASSIGNMENT_FITS((dest), ulltmp))           \
                     result = 1;                                         \
                 else                                                    \
                     *(overflow) = 1;                                    \
@@ -925,7 +950,7 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
         }                                                               \
         else                                                            \
         {                                                               \
-            if (INTEGRAL_ASSIGNMENT_FITS((dest), ltmp))                 \
+            if (INTEGRAL_ASSIGNMENT_FITS((dest), lltmp))                \
                 result = 1;                                             \
             else                                                        \
                 *(overflow) = 1;                                        \
@@ -1222,9 +1247,9 @@ PyMODINIT_FUNC init_helpers(void)
     if (m == NULL)
         return;
 
-#ifdef HAVE_UTIMENSAT
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wtautological-compare" // For INTEGER_TO_PY().
+#ifdef HAVE_UTIMENSAT
     {
         PyObject *value;
         value = INTEGER_TO_PY(AT_FDCWD);
@@ -1237,8 +1262,20 @@ PyMODINIT_FUNC init_helpers(void)
         PyObject_SetAttrString(m, "UTIME_NOW", value);
         Py_DECREF(value);
     }
-#pragma clang diagnostic pop  // ignored "-Wtautological-compare"
 #endif
+    {
+        PyObject *value;
+        const long arg_max = sysconf(_SC_ARG_MAX);
+        if (arg_max == -1)
+        {
+            fprintf(stderr, "Cannot find SC_ARG_MAX, please report a bug.\n");
+            exit(1);
+        }
+        value = INTEGER_TO_PY(arg_max);
+        PyObject_SetAttrString(m, "SC_ARG_MAX", value);
+        Py_DECREF(value);
+    }
+#pragma clang diagnostic pop  // ignored "-Wtautological-compare"
 
     e = getenv("BUP_FORCE_TTY");
     istty2 = isatty(2) || (atoi(e ? e : "0") & 2);