+#ifdef HAVE_TM_TM_GMTOFF
+static PyObject *bup_localtime(PyObject *self, PyObject *args)
+{
+ long long lltime;
+ time_t ttime;
+ if (!PyArg_ParseTuple(args, "L", &lltime))
+ return NULL;
+ if (!INTEGRAL_ASSIGNMENT_FITS(&ttime, lltime))
+ return PyErr_Format(PyExc_OverflowError, "time value too large");
+
+ struct tm tm;
+ tzset();
+ if(localtime_r(&ttime, &tm) == NULL)
+ return PyErr_SetFromErrno(PyExc_OSError);
+
+ // Match the Python struct_time values.
+ return Py_BuildValue("[i,i,i,i,i,i,i,i,i,i,s]",
+ 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ tm.tm_wday, tm.tm_yday + 1,
+ tm.tm_isdst, tm.tm_gmtoff, tm.tm_zone);
+}
+#endif /* def HAVE_TM_TM_GMTOFF */
+
+
+#ifdef BUP_MINCORE_BUF_TYPE
+static PyObject *bup_mincore(PyObject *self, PyObject *args)
+{
+ Py_buffer src, dest;
+ PyObject *py_src_n, *py_src_off, *py_dest_off;
+
+ if (!PyArg_ParseTuple(args, cstr_argf "*OOw*O",
+ &src, &py_src_n, &py_src_off,
+ &dest, &py_dest_off))
+ return NULL;
+
+ PyObject *result = NULL;
+
+ unsigned long long src_n, src_off, dest_off;
+ if (!(bup_ullong_from_py(&src_n, py_src_n, "src_n")
+ && bup_ullong_from_py(&src_off, py_src_off, "src_off")
+ && bup_ullong_from_py(&dest_off, py_dest_off, "dest_off")))
+ goto clean_and_return;
+
+ unsigned long long src_region_end;
+ if (!uadd(&src_region_end, src_off, src_n)) {
+ result = PyErr_Format(PyExc_OverflowError, "(src_off + src_n) too large");
+ goto clean_and_return;
+ }
+ assert(src.len >= 0);
+ if (src_region_end > (unsigned long long) src.len) {
+ result = PyErr_Format(PyExc_OverflowError, "region runs off end of src");
+ goto clean_and_return;
+ }
+
+ unsigned long long dest_size;
+ if (!INTEGRAL_ASSIGNMENT_FITS(&dest_size, dest.len)) {
+ result = PyErr_Format(PyExc_OverflowError, "invalid dest size");
+ goto clean_and_return;
+ }
+ if (dest_off > dest_size) {
+ result = PyErr_Format(PyExc_OverflowError, "region runs off end of dest");
+ goto clean_and_return;
+ }
+
+ size_t length;
+ if (!INTEGRAL_ASSIGNMENT_FITS(&length, src_n)) {
+ result = PyErr_Format(PyExc_OverflowError, "src_n overflows size_t");
+ goto clean_and_return;
+ }
+ int rc = mincore((void *)(src.buf + src_off), src_n,
+ (BUP_MINCORE_BUF_TYPE *) (dest.buf + dest_off));
+ if (rc != 0) {
+ result = PyErr_SetFromErrno(PyExc_OSError);
+ goto clean_and_return;
+ }
+ result = Py_BuildValue("O", Py_None);
+
+ clean_and_return:
+ PyBuffer_Release(&src);
+ PyBuffer_Release(&dest);
+ return result;
+}
+#endif /* def BUP_MINCORE_BUF_TYPE */
+
+
+static PyObject *tuple_from_cstrs(char **cstrs)
+{
+ // Assumes list is null terminated
+ size_t n = 0;
+ while(cstrs[n] != NULL)
+ n++;
+
+ Py_ssize_t sn;
+ if (!INTEGRAL_ASSIGNMENT_FITS(&sn, n))
+ return PyErr_Format(PyExc_OverflowError, "string array too large");
+
+ PyObject *result = PyTuple_New(sn);
+ Py_ssize_t i = 0;
+ for (i = 0; i < sn; i++)
+ {
+ PyObject *gname = Py_BuildValue(cstr_argf, cstrs[i]);
+ if (gname == NULL)
+ {
+ Py_DECREF(result);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(result, i, gname);
+ }
+ return result;
+}
+
+static long getpw_buf_size;
+
+static PyObject *pwd_struct_to_py(const struct passwd *pwd, int rc)
+{
+ // 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);
+}
+
+static PyObject *bup_getpwuid(PyObject *self, PyObject *args)
+{
+ unsigned long uid;
+ if (!PyArg_ParseTuple(args, "k", &uid))
+ return NULL;
+
+ 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;
+}
+
+static PyObject *bup_getpwnam(PyObject *self, PyObject *args)
+{
+ PyObject *py_name;
+ 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;
+}
+
+static long getgr_buf_size;
+
+static PyObject *grp_struct_to_py(const struct group *grp, int rc)
+{
+ // 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);
+}
+
+static PyObject *bup_getgrgid(PyObject *self, PyObject *args)
+{
+ unsigned long gid;
+ if (!PyArg_ParseTuple(args, "k", &gid))
+ return NULL;
+
+ 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;
+}
+
+static PyObject *bup_getgrnam(PyObject *self, PyObject *args)
+{
+ PyObject *py_name;
+ 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;
+}
+
+static PyObject *bup_gethostname(PyObject *mod, PyObject *ignore)
+{
+#ifdef HOST_NAME_MAX
+ char buf[HOST_NAME_MAX + 1] = {};
+#else
+ /* 'SUSv2 guarantees that "Host names are limited to 255 bytes".' */
+ char buf[256] = {};
+#endif
+
+ if (gethostname(buf, sizeof(buf) - 1))
+ return PyErr_SetFromErrno(PyExc_IOError);
+ return PyBytes_FromString(buf);
+}
+