##// END OF EJS Templates
namespaces: let namespaces override singlenode() definition...
namespaces: let namespaces override singlenode() definition Some namespaces have multiple nodes per name (meaning that their namemap() returns multiple nodes). One such namespace is the "topics" namespace (from the evolve repo). We also have our own internal namespace at Google (for review units) that has multiple nodes per name. These namespaces may not want to use the default "pick highest revnum" resolution that we currently use when resolving a name to a single node. As an example, they may decide that `hg co <name>` should check out a commit that's last in some sense even if an earlier commit had just been amended and thus had a higher revnum [1]. This patch gives the namespace the option to continue to return multiple nodes and to override how the best node is picked. Allowing namespaces to override that may also be useful as an optimization (it may be cheaper for the namespace to find just that node). I have been arguing (in D3715) for using all the nodes returned from namemap() when resolving the symbol to a revset, so e.g. `hg log -r stable` would resolve to *all* nodes on stable, not just the one with the highest revnum (except that I don't actually think we should change it for the branch namespace because of BC). Most people seem opposed to that. If we decide not to do it, I think we can deprecate the namemap() function in favor of the new singlenode() (I find it weird to have namespaces, like the branch namespace, where namemap() isn't nodemap()'s inverse). I therefore think this patch makes sense regardless of what we decide on that issue. [1] Actually, even the branch namespace would have wanted to override singlenode() if it had supported multiple nodes. That's because closes branch heads are mostly ignored, so "hg co default" will not check out the highest-revnum node if that's a closed head. Differential Revision: https://phab.mercurial-scm.org/D3852

File last commit:

r38125:f7a03989 default
r38505:4c068365 @58 default
Show More
pathencode.c
758 lines | 16.7 KiB | text/x-c | CLexer
Yuya Nishihara
parsers: switch to policy importer...
r32372 /*
pathencode.c - efficient path name encoding
Copyright 2012 Facebook
This software may be used and distributed according to the terms of
the GNU General Public License, incorporated herein by reference.
*/
/*
* An implementation of the name encoding scheme used by the fncache
* store. The common case is of a path < 120 bytes long, which is
* handled either in a single pass with no allocations or two passes
* with a single allocation. For longer paths, multiple passes are
* required.
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
/* state machine for the fast path */
enum path_state {
Augie Fackler
pathencode: allow clang-format oversight...
r36073 START, /* first byte of a path component */
A, /* "AUX" */
Yuya Nishihara
parsers: switch to policy importer...
r32372 AU,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
C, /* "CON" or "COMn" */
Yuya Nishihara
parsers: switch to policy importer...
r32372 CO,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 COMLPT, /* "COM" or "LPT" */
Yuya Nishihara
parsers: switch to policy importer...
r32372 COMLPTn,
L,
LP,
N,
NU,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 P, /* "PRN" */
Yuya Nishihara
parsers: switch to policy importer...
r32372 PR,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 LDOT, /* leading '.' */
DOT, /* '.' in a non-leading position */
H, /* ".h" */
HGDI, /* ".hg", ".d", or ".i" */
Yuya Nishihara
parsers: switch to policy importer...
r32372 SPACE,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 DEFAULT, /* byte of a path component after the first */
Yuya Nishihara
parsers: switch to policy importer...
r32372 };
/* state machine for dir-encoding */
enum dir_state {
DDOT,
DH,
DHGDI,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 DDEFAULT,
Yuya Nishihara
parsers: switch to policy importer...
r32372 };
static inline int inset(const uint32_t bitset[], char c)
{
return bitset[((uint8_t)c) >> 5] & (1 << (((uint8_t)c) & 31));
}
static inline void charcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
char c)
{
if (dest) {
assert(*destlen < destsize);
dest[*destlen] = c;
}
(*destlen)++;
}
static inline void memcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
const void *src, Py_ssize_t len)
{
if (dest) {
assert(*destlen + len < destsize);
memcpy((void *)&dest[*destlen], src, len);
}
*destlen += len;
}
static inline void hexencode(char *dest, Py_ssize_t *destlen, size_t destsize,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 uint8_t c)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
static const char hexdigit[] = "0123456789abcdef";
charcopy(dest, destlen, destsize, hexdigit[c >> 4]);
charcopy(dest, destlen, destsize, hexdigit[c & 15]);
}
/* 3-byte escape: tilde followed by two hex digits */
static inline void escape3(char *dest, Py_ssize_t *destlen, size_t destsize,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 char c)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
charcopy(dest, destlen, destsize, '~');
hexencode(dest, destlen, destsize, c);
}
Augie Fackler
pathencode: allow clang-format oversight...
r36073 static Py_ssize_t _encodedir(char *dest, size_t destsize, const char *src,
Py_ssize_t len)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
enum dir_state state = DDEFAULT;
Py_ssize_t i = 0, destlen = 0;
while (i < len) {
switch (state) {
case DDOT:
switch (src[i]) {
case 'd':
case 'i':
state = DHGDI;
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'h':
state = DH;
charcopy(dest, &destlen, destsize, src[i++]);
break;
default:
state = DDEFAULT;
break;
}
break;
case DH:
if (src[i] == 'g') {
state = DHGDI;
charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DDEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case DHGDI:
if (src[i] == '/') {
memcopy(dest, &destlen, destsize, ".hg", 3);
charcopy(dest, &destlen, destsize, src[i++]);
}
state = DDEFAULT;
break;
case DDEFAULT:
if (src[i] == '.')
state = DDOT;
charcopy(dest, &destlen, destsize, src[i++]);
break;
}
}
return destlen;
}
PyObject *encodedir(PyObject *self, PyObject *args)
{
Py_ssize_t len, newlen;
PyObject *pathobj, *newobj;
char *path;
if (!PyArg_ParseTuple(args, "O:encodedir", &pathobj))
return NULL;
if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
PyErr_SetString(PyExc_TypeError, "expected a string");
return NULL;
}
newlen = len ? _encodedir(NULL, 0, path, len + 1) : 1;
if (newlen == len + 1) {
Py_INCREF(pathobj);
return pathobj;
}
newobj = PyBytes_FromStringAndSize(NULL, newlen);
if (newobj) {
assert(PyBytes_Check(newobj));
Py_SIZE(newobj)--;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 _encodedir(PyBytes_AS_STRING(newobj), newlen, path, len + 1);
Yuya Nishihara
parsers: switch to policy importer...
r32372 }
return newobj;
}
static Py_ssize_t _encode(const uint32_t twobytes[8], const uint32_t onebyte[8],
Augie Fackler
pathencode: allow clang-format oversight...
r36073 char *dest, Py_ssize_t destlen, size_t destsize,
const char *src, Py_ssize_t len, int encodedir)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
enum path_state state = START;
Py_ssize_t i = 0;
/*
* Python strings end with a zero byte, which we use as a
* terminal token as they are not valid inside path names.
*/
while (i < len) {
switch (state) {
case START:
switch (src[i]) {
case '/':
charcopy(dest, &destlen, destsize, src[i++]);
break;
case '.':
state = LDOT;
escape3(dest, &destlen, destsize, src[i++]);
break;
case ' ':
state = DEFAULT;
escape3(dest, &destlen, destsize, src[i++]);
break;
case 'a':
state = A;
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'c':
state = C;
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'l':
state = L;
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'n':
state = N;
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'p':
state = P;
charcopy(dest, &destlen, destsize, src[i++]);
break;
default:
state = DEFAULT;
break;
}
break;
case A:
if (src[i] == 'u') {
state = AU;
charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case AU:
if (src[i] == 'x') {
state = THIRD;
i++;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case THIRD:
state = DEFAULT;
switch (src[i]) {
case '.':
case '/':
case '\0':
escape3(dest, &destlen, destsize, src[i - 1]);
break;
default:
i--;
break;
}
break;
case C:
if (src[i] == 'o') {
state = CO;
charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case CO:
if (src[i] == 'm') {
state = COMLPT;
i++;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else if (src[i] == 'n') {
Yuya Nishihara
parsers: switch to policy importer...
r32372 state = THIRD;
i++;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case COMLPT:
switch (src[i]) {
Augie Fackler
pathencode: allow clang-format oversight...
r36073 case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Yuya Nishihara
parsers: switch to policy importer...
r32372 state = COMLPTn;
i++;
break;
default:
state = DEFAULT;
charcopy(dest, &destlen, destsize, src[i - 1]);
break;
}
break;
case COMLPTn:
state = DEFAULT;
switch (src[i]) {
case '.':
case '/':
case '\0':
escape3(dest, &destlen, destsize, src[i - 2]);
charcopy(dest, &destlen, destsize, src[i - 1]);
break;
default:
Augie Fackler
pathencode: allow clang-format oversight...
r36073 memcopy(dest, &destlen, destsize, &src[i - 2],
2);
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
}
break;
case L:
if (src[i] == 'p') {
state = LP;
charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case LP:
if (src[i] == 't') {
state = COMLPT;
i++;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case N:
if (src[i] == 'u') {
state = NU;
charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case NU:
if (src[i] == 'l') {
state = THIRD;
i++;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case P:
if (src[i] == 'r') {
state = PR;
charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case PR:
if (src[i] == 'n') {
state = THIRD;
i++;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case LDOT:
switch (src[i]) {
case 'd':
case 'i':
state = HGDI;
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'h':
state = H;
charcopy(dest, &destlen, destsize, src[i++]);
break;
default:
state = DEFAULT;
break;
}
break;
case DOT:
switch (src[i]) {
case '/':
case '\0':
state = START;
memcopy(dest, &destlen, destsize, "~2e", 3);
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'd':
case 'i':
state = HGDI;
charcopy(dest, &destlen, destsize, '.');
charcopy(dest, &destlen, destsize, src[i++]);
break;
case 'h':
state = H;
memcopy(dest, &destlen, destsize, ".h", 2);
i++;
break;
default:
state = DEFAULT;
charcopy(dest, &destlen, destsize, '.');
break;
}
break;
case H:
if (src[i] == 'g') {
state = HGDI;
charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case HGDI:
if (src[i] == '/') {
state = START;
if (encodedir)
memcopy(dest, &destlen, destsize, ".hg",
Augie Fackler
pathencode: allow clang-format oversight...
r36073 3);
Yuya Nishihara
parsers: switch to policy importer...
r32372 charcopy(dest, &destlen, destsize, src[i++]);
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
state = DEFAULT;
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
case SPACE:
switch (src[i]) {
case '/':
case '\0':
state = START;
memcopy(dest, &destlen, destsize, "~20", 3);
charcopy(dest, &destlen, destsize, src[i++]);
break;
default:
state = DEFAULT;
charcopy(dest, &destlen, destsize, ' ');
break;
}
break;
case DEFAULT:
while (inset(onebyte, src[i])) {
charcopy(dest, &destlen, destsize, src[i++]);
if (i == len)
goto done;
}
switch (src[i]) {
case '.':
state = DOT;
i++;
break;
case ' ':
state = SPACE;
i++;
break;
case '/':
state = START;
charcopy(dest, &destlen, destsize, '/');
i++;
break;
default:
if (inset(onebyte, src[i])) {
do {
charcopy(dest, &destlen,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 destsize, src[i++]);
Yuya Nishihara
parsers: switch to policy importer...
r32372 } while (i < len &&
Augie Fackler
pathencode: allow clang-format oversight...
r36073 inset(onebyte, src[i]));
} else if (inset(twobytes, src[i])) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 char c = src[i++];
charcopy(dest, &destlen, destsize, '_');
charcopy(dest, &destlen, destsize,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 c == '_' ? '_' : c + 32);
} else
Yuya Nishihara
parsers: switch to policy importer...
r32372 escape3(dest, &destlen, destsize,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 src[i++]);
Yuya Nishihara
parsers: switch to policy importer...
r32372 break;
}
break;
}
}
done:
return destlen;
}
Augie Fackler
pathencode: allow clang-format oversight...
r36073 static Py_ssize_t basicencode(char *dest, size_t destsize, const char *src,
Py_ssize_t len)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
Augie Fackler
pathencode: allow clang-format oversight...
r36073 static const uint32_t twobytes[8] = {0, 0, 0x87fffffe};
Yuya Nishihara
parsers: switch to policy importer...
r32372
static const uint32_t onebyte[8] = {
Augie Fackler
pathencode: allow clang-format oversight...
r36073 1, 0x2bff3bfa, 0x68000001, 0x2fffffff,
Yuya Nishihara
parsers: switch to policy importer...
r32372 };
Py_ssize_t destlen = 0;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 return _encode(twobytes, onebyte, dest, destlen, destsize, src, len, 1);
Yuya Nishihara
parsers: switch to policy importer...
r32372 }
static const Py_ssize_t maxstorepathlen = 120;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 static Py_ssize_t _lowerencode(char *dest, size_t destsize, const char *src,
Py_ssize_t len)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
Augie Fackler
pathencode: allow clang-format oversight...
r36073 static const uint32_t onebyte[8] = {1, 0x2bfffbfb, 0xe8000001,
0x2fffffff};
Yuya Nishihara
parsers: switch to policy importer...
r32372
Augie Fackler
pathencode: allow clang-format oversight...
r36073 static const uint32_t lower[8] = {0, 0, 0x7fffffe};
Yuya Nishihara
parsers: switch to policy importer...
r32372
Py_ssize_t i, destlen = 0;
for (i = 0; i < len; i++) {
if (inset(onebyte, src[i]))
charcopy(dest, &destlen, destsize, src[i]);
else if (inset(lower, src[i]))
charcopy(dest, &destlen, destsize, src[i] + 32);
else
escape3(dest, &destlen, destsize, src[i]);
}
return destlen;
}
PyObject *lowerencode(PyObject *self, PyObject *args)
{
char *path;
Py_ssize_t len, newlen;
PyObject *ret;
Yuya Nishihara
py3: bulk-replace 'const char*' format specifier passed to PyArg_ParseTuple*()...
r36638 if (!PyArg_ParseTuple(args, PY23("s#:lowerencode", "y#:lowerencode"),
&path, &len))
Yuya Nishihara
parsers: switch to policy importer...
r32372 return NULL;
newlen = _lowerencode(NULL, 0, path, len);
ret = PyBytes_FromStringAndSize(NULL, newlen);
if (ret)
_lowerencode(PyBytes_AS_STRING(ret), newlen, path, len);
return ret;
}
/* See store.py:_auxencode for a description. */
Augie Fackler
pathencode: allow clang-format oversight...
r36073 static Py_ssize_t auxencode(char *dest, size_t destsize, const char *src,
Py_ssize_t len)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
static const uint32_t twobytes[8];
static const uint32_t onebyte[8] = {
Augie Fackler
pathencode: allow clang-format oversight...
r36073 ~0U, 0xffff3ffe, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
Yuya Nishihara
parsers: switch to policy importer...
r32372 };
return _encode(twobytes, onebyte, dest, 0, destsize, src, len, 0);
}
static PyObject *hashmangle(const char *src, Py_ssize_t len, const char sha[20])
{
static const Py_ssize_t dirprefixlen = 8;
static const Py_ssize_t maxshortdirslen = 68;
char *dest;
PyObject *ret;
Py_ssize_t i, d, p, lastslash = len - 1, lastdot = -1;
Py_ssize_t destsize, destlen = 0, slop, used;
while (lastslash >= 0 && src[lastslash] != '/') {
if (src[lastslash] == '.' && lastdot == -1)
lastdot = lastslash;
lastslash--;
}
#if 0
/* All paths should end in a suffix of ".i" or ".d".
Unfortunately, the file names in test-hybridencode.py
violate this rule. */
if (lastdot != len - 3) {
PyErr_SetString(PyExc_ValueError,
"suffix missing or wrong length");
return NULL;
}
#endif
/* If src contains a suffix, we will append it to the end of
the new string, so make room. */
destsize = 120;
if (lastdot >= 0)
destsize += len - lastdot - 1;
ret = PyBytes_FromStringAndSize(NULL, destsize);
if (ret == NULL)
return NULL;
dest = PyBytes_AS_STRING(ret);
memcopy(dest, &destlen, destsize, "dh/", 3);
/* Copy up to dirprefixlen bytes of each path component, up to
a limit of maxshortdirslen bytes. */
for (i = d = p = 0; i < lastslash; i++, p++) {
if (src[i] == '/') {
char d = dest[destlen - 1];
/* After truncation, a directory name may end
in a space or dot, which are unportable. */
if (d == '.' || d == ' ')
dest[destlen - 1] = '_';
/* The + 3 is to account for "dh/" in the beginning */
if (destlen > maxshortdirslen + 3)
break;
charcopy(dest, &destlen, destsize, src[i]);
p = -1;
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else if (p < dirprefixlen)
Yuya Nishihara
parsers: switch to policy importer...
r32372 charcopy(dest, &destlen, destsize, src[i]);
}
/* Rewind to just before the last slash copied. */
if (destlen > maxshortdirslen + 3)
do {
destlen--;
} while (destlen > 0 && dest[destlen] != '/');
if (destlen > 3) {
if (lastslash > 0) {
char d = dest[destlen - 1];
/* The last directory component may be
truncated, so make it safe. */
if (d == '.' || d == ' ')
dest[destlen - 1] = '_';
}
charcopy(dest, &destlen, destsize, '/');
}
/* Add a prefix of the original file's name. Its length
depends on the number of bytes left after accounting for
hash and suffix. */
used = destlen + 40;
if (lastdot >= 0)
used += len - lastdot - 1;
slop = maxstorepathlen - used;
if (slop > 0) {
Py_ssize_t basenamelen =
Augie Fackler
pathencode: allow clang-format oversight...
r36073 lastslash >= 0 ? len - lastslash - 2 : len - 1;
Yuya Nishihara
parsers: switch to policy importer...
r32372
if (basenamelen > slop)
basenamelen = slop;
if (basenamelen > 0)
memcopy(dest, &destlen, destsize, &src[lastslash + 1],
Augie Fackler
pathencode: allow clang-format oversight...
r36073 basenamelen);
Yuya Nishihara
parsers: switch to policy importer...
r32372 }
/* Add hash and suffix. */
for (i = 0; i < 20; i++)
hexencode(dest, &destlen, destsize, sha[i]);
if (lastdot >= 0)
memcopy(dest, &destlen, destsize, &src[lastdot],
Augie Fackler
pathencode: allow clang-format oversight...
r36073 len - lastdot - 1);
Yuya Nishihara
parsers: switch to policy importer...
r32372
assert(PyBytes_Check(ret));
Py_SIZE(ret) = destlen;
return ret;
}
/*
* 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) {
Augie Fackler
pathencode: remove unused variable...
r38125 PyObject *hashlib = PyImport_ImportModule("hashlib");
Yuya Nishihara
parsers: switch to policy importer...
r32372 if (hashlib == NULL) {
Augie Fackler
pathencode: improve error messages slightly...
r38067 PyErr_SetString(PyExc_ImportError,
"pathencode failed to find hashlib");
Yuya Nishihara
parsers: switch to policy importer...
r32372 return -1;
}
shafunc = PyObject_GetAttrString(hashlib, "sha1");
Py_DECREF(hashlib);
if (shafunc == NULL) {
PyErr_SetString(PyExc_AttributeError,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 "module 'hashlib' has no "
Augie Fackler
pathencode: improve error messages slightly...
r38067 "attribute 'sha1' in pathencode");
Yuya Nishihara
parsers: switch to policy importer...
r32372 return -1;
}
}
Augie Fackler
pathencode: hashlib.sha1() takes bytes not str on Python 3...
r38066 shaobj = PyObject_CallFunction(shafunc, PY23("s#", "y#"), str, len);
Yuya Nishihara
parsers: switch to policy importer...
r32372
if (shaobj == NULL)
return -1;
hashobj = PyObject_CallMethod(shaobj, "digest", "");
Py_DECREF(shaobj);
if (hashobj == NULL)
return -1;
if (!PyBytes_Check(hashobj) || PyBytes_GET_SIZE(hashobj) != 20) {
PyErr_SetString(PyExc_TypeError,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 "result of digest is not a 20-byte hash");
Yuya Nishihara
parsers: switch to policy importer...
r32372 Py_DECREF(hashobj);
return -1;
}
memcpy(hash, PyBytes_AS_STRING(hashobj), 20);
Py_DECREF(hashobj);
return 0;
}
#define MAXENCODE 4096 * 4
static PyObject *hashencode(const char *src, Py_ssize_t len)
{
char dired[MAXENCODE];
char lowered[MAXENCODE];
char auxed[MAXENCODE];
Py_ssize_t dirlen, lowerlen, auxlen, baselen;
char sha[20];
baselen = (len - 5) * 3;
if (baselen >= MAXENCODE) {
PyErr_SetString(PyExc_ValueError, "string too long");
return NULL;
}
dirlen = _encodedir(dired, baselen, src, len);
if (sha1hash(sha, dired, dirlen - 1) == -1)
return NULL;
lowerlen = _lowerencode(lowered, baselen, dired + 5, dirlen - 5);
auxlen = auxencode(auxed, baselen, lowered, lowerlen);
return hashmangle(auxed, auxlen, sha);
}
PyObject *pathencode(PyObject *self, PyObject *args)
{
Py_ssize_t len, newlen;
PyObject *pathobj, *newobj;
char *path;
if (!PyArg_ParseTuple(args, "O:pathencode", &pathobj))
return NULL;
if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
PyErr_SetString(PyExc_TypeError, "expected a string");
return NULL;
}
if (len > maxstorepathlen)
newlen = maxstorepathlen + 2;
else
newlen = len ? basicencode(NULL, 0, path, len + 1) : 1;
if (newlen <= maxstorepathlen + 1) {
if (newlen == len + 1) {
Py_INCREF(pathobj);
return pathobj;
}
newobj = PyBytes_FromStringAndSize(NULL, newlen);
if (newobj) {
assert(PyBytes_Check(newobj));
Py_SIZE(newobj)--;
basicencode(PyBytes_AS_STRING(newobj), newlen, path,
Augie Fackler
pathencode: allow clang-format oversight...
r36073 len + 1);
Yuya Nishihara
parsers: switch to policy importer...
r32372 }
Augie Fackler
pathencode: allow clang-format oversight...
r36073 } else
Yuya Nishihara
parsers: switch to policy importer...
r32372 newobj = hashencode(path, len + 1);
return newobj;
}