pathencode: add a SHA-1 hash function
This will be used by an upcoming patch.
This calls out to the Python hash implementation.
An earlier version of this function implemented SHA-1 directly, but
the amount of extra code didn't seem like a good tradeoff compared
to the small big-picture increase in performance (long paths are
uncommon).
--- a/mercurial/pathencode.c Wed Dec 12 13:09:33 2012 -0800
+++ b/mercurial/pathencode.c Wed Dec 12 13:09:34 2012 -0800
@@ -524,6 +524,59 @@
}
/*
+ * Avoiding a trip through Python would improve performance by 50%,
+ * but we don't encounter enough long names to be worth the code.
+ */
+static int sha1hash(char hash[20], const char *str, Py_ssize_t len)
+{
+ static PyObject *shafunc;
+ PyObject *shaobj, *hashobj;
+
+ if (shafunc == NULL) {
+ PyObject *util, *name = PyString_FromString("mercurial.util");
+
+ if (name == NULL)
+ return -1;
+
+ util = PyImport_Import(name);
+ Py_DECREF(name);
+
+ if (util == NULL) {
+ PyErr_SetString(PyExc_ImportError, "mercurial.util");
+ return -1;
+ }
+ shafunc = PyObject_GetAttrString(util, "sha1");
+ Py_DECREF(util);
+
+ if (shafunc == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "module 'mercurial.util' has no "
+ "attribute 'sha1'");
+ return -1;
+ }
+ }
+
+ shaobj = PyObject_CallFunction(shafunc, "s#", str, len);
+
+ if (shaobj == NULL)
+ return -1;
+
+ hashobj = PyObject_CallMethod(shaobj, "digest", "");
+ Py_DECREF(shaobj);
+
+ if (!PyString_Check(hashobj) || PyString_GET_SIZE(hashobj) != 20) {
+ PyErr_SetString(PyExc_TypeError,
+ "result of digest is not a 20-byte hash");
+ Py_DECREF(hashobj);
+ return -1;
+ }
+
+ memcpy(hash, PyString_AS_STRING(hashobj), 20);
+ Py_DECREF(hashobj);
+ return 0;
+}
+
+/*
* We currently implement only basic encoding.
*
* If a name is too long to encode due to Windows path name limits,