##// END OF EJS Templates
hgweb: use a capped reader for WSGI input stream...
hgweb: use a capped reader for WSGI input stream Per PEP 3333, the input stream from WSGI should respect EOF and prevent reads past the end of the request body. However, not all WSGI servers guarantee this. Notably, our BaseHTTPServer based built-in HTTP server doesn't. Instead, it exposes the raw socket and you can read() from it all you want, getting the connection in a bad state by doing so. We have a "cappedreader" utility class that proxies a file object and prevents reading past a limit. This commit converts the WSGI input stream into a capped reader when the input length is advertised via Content-Length headers. "cappedreader" only exposes a read() method. PEP 3333 states that the input stream MUST also support readline(), readlines(hint), and __iter__(). However, since our WSGI application code only calls read() and since we're not manipulating the stream exposed by the WSGI server, we're not violating the spec here. Differential Revision: https://phab.mercurial-scm.org/D2768

File last commit:

r36638:186c6df3 default
r36870:290fc4c3 default
Show More
pathencode.c
764 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) {
PyObject *hashlib, *name = PyBytes_FromString("hashlib");
if (name == NULL)
return -1;
hashlib = PyImport_Import(name);
Py_DECREF(name);
if (hashlib == NULL) {
PyErr_SetString(PyExc_ImportError, "hashlib");
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 "
"attribute 'sha1'");
Yuya Nishihara
parsers: switch to policy importer...
r32372 return -1;
}
}
shaobj = PyObject_CallFunction(shafunc, "s#", str, len);
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;
}