X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=lib%2Fbup%2F_helpers.c;h=391597ff04a6eba86d1a253b7d310a396bf30245;hb=34b775ca5063220f6faab56d1b82dcd42f8ac9fa;hp=b39db0ad9477e759cdd6d256505864b39e809753;hpb=4d61a6859cf2c1c4385fd8ffd3cf3cac43ea525c;p=bup.git diff --git a/lib/bup/_helpers.c b/lib/bup/_helpers.c index b39db0a..391597f 100644 --- a/lib/bup/_helpers.c +++ b/lib/bup/_helpers.c @@ -5,6 +5,7 @@ // According to Python, its header has to go first: // http://docs.python.org/2/c-api/intro.html#include-files +// http://docs.python.org/3/c-api/intro.html#include-files #include #include @@ -46,20 +47,36 @@ #include #endif -#ifdef BUP_HAVE_READLINE -#if ! defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < BUP_RL_EXPECTED_XOPEN_SOURCE -# warning "_XOPEN_SOURCE version is too low for readline" +#if defined(BUP_RL_EXPECTED_XOPEN_SOURCE) \ + && (!defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < BUP_RL_EXPECTED_XOPEN_SOURCE) +# warning "_XOPEN_SOURCE version is incorrect for readline" #endif -#include -#include + +#ifdef BUP_HAVE_READLINE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstrict-prototypes" +# ifdef BUP_READLINE_INCLUDES_IN_SUBDIR +# include +# include +# else +# include +# include +# endif +# pragma GCC diagnostic pop #endif #include "bupsplit.h" +#include "bup/intprops.h" #if defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) #define BUP_HAVE_FILE_ATTRS 1 #endif +#if PY_MAJOR_VERSION > 2 +# define BUP_USE_PYTHON_UTIME 1 +#endif + +#ifndef BUP_USE_PYTHON_UTIME // just for Python 2 now /* * Check for incomplete UTIMENSAT support (NetBSD 6), and if so, * pretend we don't have it. @@ -67,6 +84,7 @@ #if !defined(AT_FDCWD) || !defined(AT_SYMLINK_NOFOLLOW) #undef HAVE_UTIMENSAT #endif +#endif // defined BUP_USE_PYTHON_UTIME #ifndef FS_NOCOW_FL // Of course, this assumes it's a bitfield value. @@ -107,19 +125,13 @@ static void *checked_calloc(size_t n, size_t size) return result; } -#ifndef BUP_HAVE_BUILTIN_MUL_OVERFLOW - -#define checked_malloc checked_calloc - -#else // defined BUP_HAVE_BUILTIN_MUL_OVERFLOW - static void *checked_malloc(size_t n, size_t size) { size_t total; - if (__builtin_mul_overflow(n, size, &total)) + if (!INT_MULTIPLY_OK(n, size, &total)) { PyErr_Format(PyExc_OverflowError, - "request to allocate %lu items of size %lu is too large", + "request to allocate %zu items of size %zu is too large", n, size); return NULL; } @@ -129,8 +141,6 @@ static void *checked_malloc(size_t n, size_t size) return result; } -#endif // defined BUP_HAVE_BUILTIN_MUL_OVERFLOW - #ifndef htonll // This function should technically be macro'd out if it's going to be used @@ -146,29 +156,10 @@ static uint64_t htonll(uint64_t value) } #endif - -// Disabling sign-compare here should be fine since we're explicitly -// checking for a sign mismatch, i.e. if the signs don't match, then -// it doesn't matter what the value comparison says. -// FIXME: ... so should we reverse the order? -#define INTEGRAL_ASSIGNMENT_FITS(dest, src) \ - ({ \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wsign-compare\""); \ - *(dest) = (src); \ - int result = *(dest) == (src) && (*(dest) < 1) == ((src) < 1); \ - _Pragma("GCC diagnostic pop"); \ - result; \ - }) - - -// At the moment any code that calls INTEGER_TO_PY() will have to -// disable -Wtautological-compare for clang. See below. +#define INTEGRAL_ASSIGNMENT_FITS(dest, src) INT_ADD_OK(src, 0, dest) #define INTEGER_TO_PY(x) \ - (((x) >= 0) ? PyLong_FromUnsignedLongLong(x) : PyLong_FromLongLong(x)) - - + EXPR_SIGNED(x) ? PyLong_FromLongLong(x) : PyLong_FromUnsignedLongLong(x) #if PY_MAJOR_VERSION < 3 static int bup_ulong_from_pyint(unsigned long *x, PyObject *py, @@ -231,7 +222,7 @@ static int bup_uint_from_py(unsigned int *x, PyObject *py, const char *name) PyErr_Format(PyExc_OverflowError, "%s too big for unsigned int", name); return 0; } - *x = tmp; + *x = (unsigned int) tmp; return 1; } @@ -333,58 +324,6 @@ static PyObject *bup_cat_bytes(PyObject *self, PyObject *args) } - -// Probably we should use autoconf or something and set HAVE_PY_GETARGCARGV... -#if __WIN32__ || __CYGWIN__ - -// There's no 'ps' on win32 anyway, and Py_GetArgcArgv() isn't available. -static void unpythonize_argv(void) { } - -#else // not __WIN32__ - -// For some reason this isn't declared in Python.h -extern void Py_GetArgcArgv(int *argc, char ***argv); - -static void unpythonize_argv(void) -{ - int argc, i; - char **argv, *arge; - - Py_GetArgcArgv(&argc, &argv); - - for (i = 0; i < argc-1; i++) - { - if (argv[i] + strlen(argv[i]) + 1 != argv[i+1]) - { - // The argv block doesn't work the way we expected; it's unsafe - // to mess with it. - return; - } - } - - arge = argv[argc-1] + strlen(argv[argc-1]) + 1; - - if (strstr(argv[0], "python") && argv[1] == argv[0] + strlen(argv[0]) + 1) - { - char *p; - size_t len, diff; - p = strrchr(argv[1], '/'); - if (p) - { - p++; - diff = p - argv[0]; - len = arge - p; - memmove(argv[0], p, len); - memset(arge - diff, 0, diff); - for (i = 0; i < argc; i++) - argv[i] = argv[i+1] ? argv[i+1]-diff : NULL; - } - } -} - -#endif // not __WIN32__ or __CYGWIN__ - - static int write_all(int fd, const void *buf, const size_t count) { size_t written = 0; @@ -399,15 +338,11 @@ static int write_all(int fd, const void *buf, const size_t count) } -static int uadd(unsigned long long *dest, - const unsigned long long x, - const unsigned long long y) +static inline int uadd(unsigned long long *dest, + const unsigned long long x, + const unsigned long long y) { - const unsigned long long result = x + y; - if (result < x || result < y) - return 0; - *dest = result; - return 1; + return INT_ADD_OK(x, y, dest); } @@ -655,7 +590,7 @@ static PyObject *splitbuf(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "t#", &buf, &len)) return NULL; assert(len <= INT_MAX); - out = bupsplit_find_ofs(buf, len, &bits); + out = bupsplit_find_ofs(buf, (int) len, &bits); } if (out) assert(bits >= BUP_BLOBBITS); return Py_BuildValue("ii", out, bits); @@ -906,7 +841,8 @@ struct idx { static void _fix_idx_order(struct idx **idxs, Py_ssize_t *last_i) { struct idx *idx; - int low, mid, high, c = 0; + Py_ssize_t low, mid, high; + int c = 0; idx = idxs[*last_i]; if (idxs[*last_i]->cur >= idxs[*last_i]->end) @@ -1068,7 +1004,7 @@ static PyObject *write_idx(PyObject *self, PyObject *args) PyObject *part; unsigned int total = 0; uint32_t count; - int i, j, ofs64_count; + int i; uint32_t *fan_ptr, *crc_ptr, *ofs_ptr; uint64_t *ofs64_ptr; struct sha *sha_ptr; @@ -1100,16 +1036,21 @@ static PyObject *write_idx(PyObject *self, PyObject *args) ofs64_ptr = (uint64_t *)&ofs_ptr[total]; count = 0; - ofs64_count = 0; + uint32_t ofs64_count = 0; for (i = 0; i < FAN_ENTRIES; ++i) { - int plen; part = PyList_GET_ITEM(idx, i); PyList_Sort(part); - plen = PyList_GET_SIZE(part); - count += plen; + uint32_t plen; + if (!INTEGRAL_ASSIGNMENT_FITS(&plen, PyList_GET_SIZE(part)) + || UINT32_MAX - count < plen) { + PyErr_Format(PyExc_OverflowError, "too many objects in index part"); + goto clean_and_return; + } + count += plen; *fan_ptr++ = htonl(count); - for (j = 0; j < plen; ++j) + uint32_t j; + for (j = 0; j < plen; ++j) { unsigned char *sha = NULL; Py_ssize_t sha_len = 0; @@ -1177,7 +1118,7 @@ static PyObject *write_random(PyObject *self, PyObject *args) { unsigned i; for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) - buf[i] = random(); + buf[i] = (uint32_t) random(); ret = write(fd, buf, sizeof(buf)); if (ret < 0) ret = 0; @@ -1193,7 +1134,7 @@ static PyObject *write_random(PyObject *self, PyObject *args) { unsigned i; for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) - buf[i] = random(); + buf[i] = (uint32_t) random(); ret = write(fd, buf, len % 1024); if (ret < 0) ret = 0; @@ -1215,7 +1156,7 @@ static PyObject *random_sha(PyObject *self, PyObject *args) if (!seeded) { assert(sizeof(shabuf) == 20); - srandom(time(NULL)); + srandom((unsigned int) time(NULL)); seeded = 1; } @@ -1224,7 +1165,7 @@ static PyObject *random_sha(PyObject *self, PyObject *args) memset(shabuf, 0, sizeof(shabuf)); for (i=0; i < 20/4; i++) - shabuf[i] = random(); + shabuf[i] = (uint32_t) random(); return Py_BuildValue(rbuf_argf, shabuf, 20); } @@ -1382,6 +1323,7 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args) #endif /* def BUP_HAVE_FILE_ATTRS */ +#ifndef BUP_USE_PYTHON_UTIME // just for Python 2 now #ifndef HAVE_UTIMENSAT #ifndef HAVE_UTIMES #error "cannot find utimensat or utimes()" @@ -1390,6 +1332,7 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args) #error "cannot find utimensat or lutimes()" #endif #endif +#endif // defined BUP_USE_PYTHON_UTIME #define ASSIGN_PYLONG_TO_INTEGRAL(dest, pylong, overflow) \ ({ \ @@ -1426,6 +1369,7 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args) }) +#ifndef BUP_USE_PYTHON_UTIME // just for Python 2 now #ifdef HAVE_UTIMENSAT static PyObject *bup_utimensat(PyObject *self, PyObject *args) @@ -1543,6 +1487,8 @@ static PyObject *bup_lutimes(PyObject *self, PyObject *args) } #endif /* def HAVE_LUTIMES */ +#endif // defined BUP_USE_PYTHON_UTIME + #ifdef HAVE_STAT_ST_ATIM # define BUP_STAT_ATIME_NS(st) (st)->st_atim.tv_nsec @@ -1559,9 +1505,6 @@ static PyObject *bup_lutimes(PyObject *self, PyObject *args) #endif -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-compare" // For INTEGER_TO_PY(). - static PyObject *stat_struct_to_py(const struct stat *st, const char *filename, int fd) @@ -1587,7 +1530,6 @@ static PyObject *stat_struct_to_py(const struct stat *st, (long) BUP_STAT_CTIME_NS(st)); } -#pragma clang diagnostic pop // ignored "-Wtautological-compare" static PyObject *bup_stat(PyObject *self, PyObject *args) { @@ -1706,7 +1648,7 @@ static PyObject *bup_mincore(PyObject *self, PyObject *args) result = PyErr_Format(PyExc_OverflowError, "src_n overflows size_t"); goto clean_and_return; } - int rc = mincore((void *)(src.buf + src_off), src_n, + int rc = mincore((void *)(src.buf + src_off), length, (BUP_MINCORE_BUF_TYPE *) (dest.buf + dest_off)); if (rc != 0) { result = PyErr_SetFromErrno(PyExc_OSError); @@ -1721,6 +1663,81 @@ static PyObject *bup_mincore(PyObject *self, PyObject *args) } #endif /* def BUP_MINCORE_BUF_TYPE */ +static unsigned int vuint_encode(long long val, char *buf) +{ + unsigned int len = 0; + + if (val < 0) { + PyErr_SetString(PyExc_Exception, "vuints must not be negative"); + return 0; + } + + do { + buf[len] = val & 0x7f; + + val >>= 7; + if (val) + buf[len] |= 0x80; + + len++; + } while (val); + + return len; +} + +static unsigned int vint_encode(long long val, char *buf) +{ + unsigned int len = 1; + char sign = 0; + + if (val < 0) { + sign = 0x40; + val = -val; + } + + buf[0] = (val & 0x3f) | sign; + val >>= 6; + if (val) + buf[0] |= 0x80; + + while (val) { + buf[len] = val & 0x7f; + val >>= 7; + if (val) + buf[len] |= 0x80; + len++; + } + + return len; +} + +static PyObject *bup_vuint_encode(PyObject *self, PyObject *args) +{ + long long val; + // size the buffer appropriately - need 8 bits to encode each 7 + char buf[(sizeof(val) + 1) / 7 * 8]; + + if (!PyArg_ParseTuple(args, "L", &val)) + return NULL; + + unsigned int len = vuint_encode(val, buf); + if (!len) + return NULL; + + return PyBytes_FromStringAndSize(buf, len); +} + +static PyObject *bup_vint_encode(PyObject *self, PyObject *args) +{ + long long val; + // size the buffer appropriately - need 8 bits to encode each 7 + char buf[(sizeof(val) + 1) / 7 * 8]; + + if (!PyArg_ParseTuple(args, "L", &val)) + return NULL; + + return PyBytes_FromStringAndSize(buf, vint_encode(val, buf)); +} static PyObject *tuple_from_cstrs(char **cstrs) { @@ -1748,48 +1765,54 @@ static PyObject *tuple_from_cstrs(char **cstrs) return result; } +static PyObject *appropriate_errno_ex(void) +{ + switch (errno) { + case ENOMEM: + return PyErr_NoMemory(); + case EIO: + case EMFILE: + case ENFILE: + // In 3.3 IOError was merged into OSError. + return PyErr_SetFromErrno(PyExc_IOError); + default: + return PyErr_SetFromErrno(PyExc_OSError); + } +} -static long getpw_buf_size; -static PyObject *pwd_struct_to_py(const struct passwd *pwd, int rc) +static PyObject *pwd_struct_to_py(const struct passwd *pwd) { // 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(). - if (pwd != NULL) - return Py_BuildValue(cstr_argf cstr_argf "OO" - cstr_argf cstr_argf cstr_argf, - pwd->pw_name, - pwd->pw_passwd, - INTEGER_TO_PY(pwd->pw_uid), - INTEGER_TO_PY(pwd->pw_gid), - pwd->pw_gecos, - pwd->pw_dir, - pwd->pw_shell); - if (rc == 0) - return Py_BuildValue("O", Py_None); - if (rc == EIO || rc == EMFILE || rc == ENFILE) - return PyErr_SetFromErrno(PyExc_IOError); - if (rc < 0) - return PyErr_SetFromErrno(PyExc_OSError); - assert(0); + if (pwd == NULL) + Py_RETURN_NONE; + return Py_BuildValue(cstr_argf cstr_argf "OO" + cstr_argf cstr_argf cstr_argf, + pwd->pw_name, + pwd->pw_passwd, + INTEGER_TO_PY(pwd->pw_uid), + INTEGER_TO_PY(pwd->pw_gid), + pwd->pw_gecos, + pwd->pw_dir, + pwd->pw_shell); } static PyObject *bup_getpwuid(PyObject *self, PyObject *args) { - unsigned long uid; - if (!PyArg_ParseTuple(args, "k", &uid)) + unsigned long long py_uid; + if (!PyArg_ParseTuple(args, "K", &py_uid)) return NULL; + uid_t uid; + if (!INTEGRAL_ASSIGNMENT_FITS(&uid, py_uid)) + return PyErr_Format(PyExc_OverflowError, "uid too large for uid_t"); - struct passwd pwd, *result_pwd; - char *buf = PyMem_Malloc(getpw_buf_size); - if (buf == NULL) - return NULL; - - int rc = getpwuid_r(uid, &pwd, buf, getpw_buf_size, &result_pwd); - PyObject *result = pwd_struct_to_py(result_pwd, rc); - PyMem_Free(buf); - return result; + errno = 0; + struct passwd *pwd = getpwuid(uid); + if (!pwd && errno) + return appropriate_errno_ex(); + return pwd_struct_to_py(pwd); } static PyObject *bup_getpwnam(PyObject *self, PyObject *args) @@ -1798,59 +1821,46 @@ static PyObject *bup_getpwnam(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "S", &py_name)) return NULL; - struct passwd pwd, *result_pwd; - char *buf = PyMem_Malloc(getpw_buf_size); - if (buf == NULL) - return NULL; - char *name = PyBytes_AS_STRING(py_name); - int rc = getpwnam_r(name, &pwd, buf, getpw_buf_size, &result_pwd); - PyObject *result = pwd_struct_to_py(result_pwd, rc); - PyMem_Free(buf); - return result; + errno = 0; + struct passwd *pwd = getpwnam(name); + if (!pwd && errno) + return appropriate_errno_ex(); + return pwd_struct_to_py(pwd); } -static long getgr_buf_size; - -static PyObject *grp_struct_to_py(const struct group *grp, int rc) +static PyObject *grp_struct_to_py(const struct group *grp) { // 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(). - if (grp != NULL) { - PyObject *members = tuple_from_cstrs(grp->gr_mem); - if (members == NULL) - return NULL; - return Py_BuildValue(cstr_argf cstr_argf "OO", - grp->gr_name, - grp->gr_passwd, - INTEGER_TO_PY(grp->gr_gid), - members); - } - if (rc == 0) - return Py_BuildValue("O", Py_None); - if (rc == EIO || rc == EMFILE || rc == ENFILE) - return PyErr_SetFromErrno(PyExc_IOError); - if (rc < 0) - return PyErr_SetFromErrno(PyExc_OSError); - assert (0); + if (grp == NULL) + Py_RETURN_NONE; + + PyObject *members = tuple_from_cstrs(grp->gr_mem); + if (members == NULL) + return NULL; + return Py_BuildValue(cstr_argf cstr_argf "OO", + grp->gr_name, + grp->gr_passwd, + INTEGER_TO_PY(grp->gr_gid), + members); } static PyObject *bup_getgrgid(PyObject *self, PyObject *args) { - unsigned long gid; - if (!PyArg_ParseTuple(args, "k", &gid)) + unsigned long long py_gid; + if (!PyArg_ParseTuple(args, "K", &py_gid)) return NULL; + gid_t gid; + if (!INTEGRAL_ASSIGNMENT_FITS(&gid, py_gid)) + return PyErr_Format(PyExc_OverflowError, "gid too large for gid_t"); - struct group grp, *result_grp; - char *buf = PyMem_Malloc(getgr_buf_size); - if (buf == NULL) - return NULL; - - int rc = getgrgid_r(gid, &grp, buf, getgr_buf_size, &result_grp); - PyObject *result = grp_struct_to_py(result_grp, rc); - PyMem_Free(buf); - return result; + errno = 0; + struct group *grp = getgrgid(gid); + if (!grp && errno) + return appropriate_errno_ex(); + return grp_struct_to_py(grp); } static PyObject *bup_getgrnam(PyObject *self, PyObject *args) @@ -1859,18 +1869,15 @@ static PyObject *bup_getgrnam(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "S", &py_name)) return NULL; - struct group grp, *result_grp; - char *buf = PyMem_Malloc(getgr_buf_size); - if (buf == NULL) - return NULL; - char *name = PyBytes_AS_STRING(py_name); - int rc = getgrnam_r(name, &grp, buf, getgr_buf_size, &result_grp); - PyObject *result = grp_struct_to_py(result_grp, rc); - PyMem_Free(buf); - return result; + errno = 0; + struct group *grp = getgrnam(name); + if (!grp && errno) + return appropriate_errno_ex(); + return grp_struct_to_py(grp); } + static PyObject *bup_gethostname(PyObject *mod, PyObject *ignore) { #ifdef HOST_NAME_MAX @@ -1968,15 +1975,11 @@ bup_set_completer_word_break_characters(PyObject *self, PyObject *args) static PyObject * bup_get_completer_word_break_characters(PyObject *self, PyObject *args) { - if (!PyArg_ParseTuple(args, "")) - return NULL; return PyBytes_FromString(rl_completer_word_break_characters); } static PyObject *bup_get_line_buffer(PyObject *self, PyObject *args) { - if (!PyArg_ParseTuple(args, "")) - return NULL; return PyBytes_FromString(rl_line_buffer); } @@ -2227,6 +2230,95 @@ static PyObject *bup_apply_acl(PyObject *self, PyObject *args) } #endif +static PyObject *bup_limited_vint_pack(PyObject *self, PyObject *args) +{ + const char *fmt; + PyObject *packargs, *result; + Py_ssize_t sz, i, bufsz; + char *buf, *pos, *end; + + if (!PyArg_ParseTuple(args, "sO", &fmt, &packargs)) + return NULL; + + if (!PyTuple_Check(packargs)) + return PyErr_Format(PyExc_Exception, "pack() arg must be tuple"); + + sz = PyTuple_GET_SIZE(packargs); + if (sz != (Py_ssize_t)strlen(fmt)) + return PyErr_Format(PyExc_Exception, + "number of arguments (%ld) does not match format string (%ld)", + (unsigned long)sz, (unsigned long)strlen(fmt)); + + if (sz > INT_MAX / 20) + return PyErr_Format(PyExc_Exception, "format is far too long"); + + // estimate no more than 20 bytes for each on average, the maximum + // vint/vuint we can encode is anyway 10 bytes, so this gives us + // some headroom for a few strings before we need to realloc ... + bufsz = sz * 20; + buf = malloc(bufsz); + if (!buf) + return PyErr_NoMemory(); + + pos = buf; + end = buf + bufsz; + for (i = 0; i < sz; i++) { + PyObject *item = PyTuple_GET_ITEM(packargs, i); + const char *bytes; + + switch (fmt[i]) { + case 'V': { + long long val = PyLong_AsLongLong(item); + if (val == -1 && PyErr_Occurred()) + return PyErr_Format(PyExc_OverflowError, + "pack arg %d invalid", (int)i); + if (end - pos < 10) + goto overflow; + pos += vuint_encode(val, pos); + break; + } + case 'v': { + long long val = PyLong_AsLongLong(item); + if (val == -1 && PyErr_Occurred()) + return PyErr_Format(PyExc_OverflowError, + "pack arg %d invalid", (int)i); + if (end - pos < 10) + goto overflow; + pos += vint_encode(val, pos); + break; + } + case 's': { + bytes = PyBytes_AsString(item); + if (!bytes) + goto error; + if (end - pos < 10) + goto overflow; + Py_ssize_t val = PyBytes_GET_SIZE(item); + pos += vuint_encode(val, pos); + if (end - pos < val) + goto overflow; + memcpy(pos, bytes, val); + pos += val; + break; + } + default: + PyErr_Format(PyExc_Exception, "unknown xpack format string item %c", + fmt[i]); + goto error; + } + } + + result = PyBytes_FromStringAndSize(buf, pos - buf); + free(buf); + return result; + + overflow: + PyErr_SetString(PyExc_OverflowError, "buffer (potentially) overflowed"); + error: + free(buf); + return NULL; +} + static PyMethodDef helper_methods[] = { { "write_sparsely", bup_write_sparsely, METH_VARARGS, "Write buf excepting zeros at the end. Return trailing zero count." }, @@ -2266,6 +2358,8 @@ static PyMethodDef helper_methods[] = { { "set_linux_file_attr", bup_set_linux_file_attr, METH_VARARGS, "Set the Linux attributes for the given file." }, #endif + +#ifndef BUP_USE_PYTHON_UTIME // just for Python 2 now #ifdef HAVE_UTIMENSAT { "bup_utimensat", bup_utimensat, METH_VARARGS, "Change path timestamps with nanosecond precision (POSIX)." }, @@ -2279,6 +2373,8 @@ static PyMethodDef helper_methods[] = { "Change path timestamps with microsecond precision;" " don't follow symlinks." }, #endif +#endif // defined BUP_USE_PYTHON_UTIME + { "stat", bup_stat, METH_VARARGS, "Extended version of stat." }, { "lstat", bup_lstat, METH_VARARGS, @@ -2342,6 +2438,10 @@ static PyMethodDef helper_methods[] = { "apply_acl(name, acl, def=None)\n\n" "Given a file/dirname (bytes) and the ACLs to restore, do that." }, #endif /* HAVE_ACLS */ + { "vuint_encode", bup_vuint_encode, METH_VARARGS, "encode an int to vuint" }, + { "vint_encode", bup_vint_encode, METH_VARARGS, "encode an int to vint" }, + { "limited_vint_pack", bup_limited_vint_pack, METH_VARARGS, + "Try to pack vint/vuint/str, throwing OverflowError when unable." }, { NULL, NULL, 0, NULL }, // sentinel }; @@ -2387,6 +2487,9 @@ static int setup_module(PyObject *m) // Just be sure (relevant when passing timestamps back to Python above). assert(sizeof(PY_LONG_LONG) <= sizeof(long long)); assert(sizeof(unsigned PY_LONG_LONG) <= sizeof(unsigned long long)); + // At least for INTEGER_TO_PY + assert(sizeof(intmax_t) <= sizeof(long long)); + assert(sizeof(uintmax_t) <= sizeof(unsigned long long)); test_integral_assignment_fits(); @@ -2401,8 +2504,6 @@ static int setup_module(PyObject *m) } char *e; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-compare" // For INTEGER_TO_PY(). { PyObject *value; value = INTEGER_TO_PY(INT_MAX); @@ -2412,6 +2513,8 @@ static int setup_module(PyObject *m) PyObject_SetAttrString(m, "UINT_MAX", value); Py_DECREF(value); } + +#ifndef BUP_USE_PYTHON_UTIME // just for Python 2 now #ifdef HAVE_UTIMENSAT { PyObject *value; @@ -2426,6 +2529,8 @@ static int setup_module(PyObject *m) Py_DECREF(value); } #endif +#endif // defined BUP_USE_PYTHON_UTIME + #ifdef BUP_HAVE_MINCORE_INCORE { PyObject *value; @@ -2434,19 +2539,9 @@ static int setup_module(PyObject *m) Py_DECREF(value); } #endif -#pragma clang diagnostic pop // ignored "-Wtautological-compare" - - getpw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX); - if (getpw_buf_size == -1) - getpw_buf_size = 16384; - - getgr_buf_size = sysconf(_SC_GETGR_R_SIZE_MAX); - if (getgr_buf_size == -1) - getgr_buf_size = 16384; e = getenv("BUP_FORCE_TTY"); get_state(m)->istty2 = isatty(2) || (atoi(e ? e : "0") & 2); - unpythonize_argv(); return 1; } @@ -2456,11 +2551,13 @@ static int setup_module(PyObject *m) PyMODINIT_FUNC init_helpers(void) { PyObject *m = Py_InitModule("_helpers", helper_methods); - if (m == NULL) + if (m == NULL) { + PyErr_SetString(PyExc_RuntimeError, "bup._helpers init failed"); return; - + } if (!setup_module(m)) { + PyErr_SetString(PyExc_RuntimeError, "bup._helpers set up failed"); Py_DECREF(m); return; }