##// END OF EJS Templates
manifest: proxy to revlog instance instead of inheriting...
manifest: proxy to revlog instance instead of inheriting Previously, manifestrevlog inherited revlog.revlog and therefore exposed all its APIs. This inevitably resulted in consumers calling low-level revlog APIs. As part of abstracting storage, we want to formalize the interface for manifest storage. The revlog API is much too large to define as the interface. Like we did for filelog, this commit divorces the manifest class from revlog so that we can standardize on a smaller API surface. The way I went about this commit was I broke the inheritance, ran tests, and added proxies until all tests passed. Like filelog, there are a handful of attributes that don't belong on the interface. And like filelog, we'll tease these out in the future. As part of this, we formalize an interface for manifest storage and add checks that manifestrevlog conforms to the interface. Adding proxies will introduce some overhead due to extra attribute lookups and function calls. On the mozilla-unified repository: $ hg verify before: real 627.220 secs (user 525.870+0.000 sys 18.800+0.000) after: real 628.930 secs (user 532.050+0.000 sys 18.320+0.000) $ hg serve (for a clone) before: user 223.580+0.000 sys 14.270+0.000 after: user 227.720+0.000 sys 13.920+0.000 $ hg clone before: user 506.390+0.000 sys 29.720+0.000 after: user 513.080+0.000 sys 28.280+0.000 There appears to be some overhead here. But it appears to be 1-2%. I think that is an appropriate price to pay for storage abstraction, which will eventually let us have much nicer things. If the overhead is noticed in other operations (whose CPU time isn't likely dwarfed by fulltext resolution) or if we want to cut down on the overhead, we could dynamically build up a type whose methods are effectively aliased to a revlog instance's. I'm inclined to punt on that problem for now. We may have to do it for the changelog. At which point it could be implemented in a generic way and ported to filelog and manifestrevlog easily enough I would think. .. api:: manifest.manifestrevlog no longer inherits from revlog The manifestrevlog class now wraps a revlog instance instead of inheriting from revlog. Various attributes and methods on instances are no longer available. Differential Revision: https://phab.mercurial-scm.org/D4386

File last commit:

r38724:992e1082 default
r39350:7f5e6d3e default
Show More
pathencode.c
761 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] = {
Yuya Nishihara
cext: reformat with clang-format 6.0...
r38724 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;
}