##// END OF EJS Templates
cext: fix Python 3.11 compatibility - Py_SIZE is not an lvalue (issue6610)...
Mads Kiilerich -
r49153:e3580733 stable
parent child Browse files
Show More
@@ -1,803 +1,803 b''
1 1 /*
2 2 pathencode.c - efficient path name encoding
3 3
4 4 Copyright 2012 Facebook
5 5
6 6 This software may be used and distributed according to the terms of
7 7 the GNU General Public License, incorporated herein by reference.
8 8 */
9 9
10 10 /*
11 11 * An implementation of the name encoding scheme used by the fncache
12 12 * store. The common case is of a path < 120 bytes long, which is
13 13 * handled either in a single pass with no allocations or two passes
14 14 * with a single allocation. For longer paths, multiple passes are
15 15 * required.
16 16 */
17 17
18 18 #define PY_SSIZE_T_CLEAN
19 19 #include <Python.h>
20 20 #include <assert.h>
21 21 #include <ctype.h>
22 22 #include <stdlib.h>
23 23 #include <string.h>
24 24 #include "pythoncapi_compat.h"
25 25
26 26 #include "util.h"
27 27
28 28 /* state machine for the fast path */
29 29 enum path_state {
30 30 START, /* first byte of a path component */
31 31 A, /* "AUX" */
32 32 AU,
33 33 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
34 34 C, /* "CON" or "COMn" */
35 35 CO,
36 36 COMLPT, /* "COM" or "LPT" */
37 37 COMLPTn,
38 38 L,
39 39 LP,
40 40 N,
41 41 NU,
42 42 P, /* "PRN" */
43 43 PR,
44 44 LDOT, /* leading '.' */
45 45 DOT, /* '.' in a non-leading position */
46 46 H, /* ".h" */
47 47 HGDI, /* ".hg", ".d", or ".i" */
48 48 SPACE,
49 49 DEFAULT, /* byte of a path component after the first */
50 50 };
51 51
52 52 /* state machine for dir-encoding */
53 53 enum dir_state {
54 54 DDOT,
55 55 DH,
56 56 DHGDI,
57 57 DDEFAULT,
58 58 };
59 59
60 60 static inline int inset(const uint32_t bitset[], char c)
61 61 {
62 62 return bitset[((uint8_t)c) >> 5] & (1 << (((uint8_t)c) & 31));
63 63 }
64 64
65 65 static inline void charcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
66 66 char c)
67 67 {
68 68 if (dest) {
69 69 assert(*destlen < destsize);
70 70 dest[*destlen] = c;
71 71 }
72 72 (*destlen)++;
73 73 }
74 74
75 75 static inline void memcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
76 76 const void *src, Py_ssize_t len)
77 77 {
78 78 if (dest) {
79 79 assert(*destlen + len < destsize);
80 80 memcpy((void *)&dest[*destlen], src, len);
81 81 }
82 82 *destlen += len;
83 83 }
84 84
85 85 static inline void hexencode(char *dest, Py_ssize_t *destlen, size_t destsize,
86 86 uint8_t c)
87 87 {
88 88 static const char hexdigit[] = "0123456789abcdef";
89 89
90 90 charcopy(dest, destlen, destsize, hexdigit[c >> 4]);
91 91 charcopy(dest, destlen, destsize, hexdigit[c & 15]);
92 92 }
93 93
94 94 /* 3-byte escape: tilde followed by two hex digits */
95 95 static inline void escape3(char *dest, Py_ssize_t *destlen, size_t destsize,
96 96 char c)
97 97 {
98 98 charcopy(dest, destlen, destsize, '~');
99 99 hexencode(dest, destlen, destsize, c);
100 100 }
101 101
102 102 static Py_ssize_t _encodedir(char *dest, size_t destsize, const char *src,
103 103 Py_ssize_t len)
104 104 {
105 105 enum dir_state state = DDEFAULT;
106 106 Py_ssize_t i = 0, destlen = 0;
107 107
108 108 while (i < len) {
109 109 switch (state) {
110 110 case DDOT:
111 111 switch (src[i]) {
112 112 case 'd':
113 113 case 'i':
114 114 state = DHGDI;
115 115 charcopy(dest, &destlen, destsize, src[i++]);
116 116 break;
117 117 case 'h':
118 118 state = DH;
119 119 charcopy(dest, &destlen, destsize, src[i++]);
120 120 break;
121 121 default:
122 122 state = DDEFAULT;
123 123 break;
124 124 }
125 125 break;
126 126 case DH:
127 127 if (src[i] == 'g') {
128 128 state = DHGDI;
129 129 charcopy(dest, &destlen, destsize, src[i++]);
130 130 } else {
131 131 state = DDEFAULT;
132 132 }
133 133 break;
134 134 case DHGDI:
135 135 if (src[i] == '/') {
136 136 memcopy(dest, &destlen, destsize, ".hg", 3);
137 137 charcopy(dest, &destlen, destsize, src[i++]);
138 138 }
139 139 state = DDEFAULT;
140 140 break;
141 141 case DDEFAULT:
142 142 if (src[i] == '.') {
143 143 state = DDOT;
144 144 }
145 145 charcopy(dest, &destlen, destsize, src[i++]);
146 146 break;
147 147 }
148 148 }
149 149
150 150 return destlen;
151 151 }
152 152
153 153 PyObject *encodedir(PyObject *self, PyObject *args)
154 154 {
155 155 Py_ssize_t len, newlen;
156 156 PyObject *pathobj, *newobj;
157 157 char *path;
158 158
159 159 if (!PyArg_ParseTuple(args, "O:encodedir", &pathobj)) {
160 160 return NULL;
161 161 }
162 162
163 163 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
164 164 PyErr_SetString(PyExc_TypeError, "expected a string");
165 165 return NULL;
166 166 }
167 167
168 168 newlen = len ? _encodedir(NULL, 0, path, len + 1) : 1;
169 169
170 170 if (newlen == len + 1) {
171 171 Py_INCREF(pathobj);
172 172 return pathobj;
173 173 }
174 174
175 175 newobj = PyBytes_FromStringAndSize(NULL, newlen);
176 176
177 177 if (newobj) {
178 178 assert(PyBytes_Check(newobj));
179 Py_SIZE(newobj)--;
179 Py_SET_SIZE(newobj, Py_SIZE(newobj) - 1);
180 180 _encodedir(PyBytes_AS_STRING(newobj), newlen, path, len + 1);
181 181 }
182 182
183 183 return newobj;
184 184 }
185 185
186 186 static Py_ssize_t _encode(const uint32_t twobytes[8], const uint32_t onebyte[8],
187 187 char *dest, Py_ssize_t destlen, size_t destsize,
188 188 const char *src, Py_ssize_t len, int encodedir)
189 189 {
190 190 enum path_state state = START;
191 191 Py_ssize_t i = 0;
192 192
193 193 /*
194 194 * Python strings end with a zero byte, which we use as a
195 195 * terminal token as they are not valid inside path names.
196 196 */
197 197
198 198 while (i < len) {
199 199 switch (state) {
200 200 case START:
201 201 switch (src[i]) {
202 202 case '/':
203 203 charcopy(dest, &destlen, destsize, src[i++]);
204 204 break;
205 205 case '.':
206 206 state = LDOT;
207 207 escape3(dest, &destlen, destsize, src[i++]);
208 208 break;
209 209 case ' ':
210 210 state = DEFAULT;
211 211 escape3(dest, &destlen, destsize, src[i++]);
212 212 break;
213 213 case 'a':
214 214 state = A;
215 215 charcopy(dest, &destlen, destsize, src[i++]);
216 216 break;
217 217 case 'c':
218 218 state = C;
219 219 charcopy(dest, &destlen, destsize, src[i++]);
220 220 break;
221 221 case 'l':
222 222 state = L;
223 223 charcopy(dest, &destlen, destsize, src[i++]);
224 224 break;
225 225 case 'n':
226 226 state = N;
227 227 charcopy(dest, &destlen, destsize, src[i++]);
228 228 break;
229 229 case 'p':
230 230 state = P;
231 231 charcopy(dest, &destlen, destsize, src[i++]);
232 232 break;
233 233 default:
234 234 state = DEFAULT;
235 235 break;
236 236 }
237 237 break;
238 238 case A:
239 239 if (src[i] == 'u') {
240 240 state = AU;
241 241 charcopy(dest, &destlen, destsize, src[i++]);
242 242 } else {
243 243 state = DEFAULT;
244 244 }
245 245 break;
246 246 case AU:
247 247 if (src[i] == 'x') {
248 248 state = THIRD;
249 249 i++;
250 250 } else {
251 251 state = DEFAULT;
252 252 }
253 253 break;
254 254 case THIRD:
255 255 state = DEFAULT;
256 256 switch (src[i]) {
257 257 case '.':
258 258 case '/':
259 259 case '\0':
260 260 escape3(dest, &destlen, destsize, src[i - 1]);
261 261 break;
262 262 default:
263 263 i--;
264 264 break;
265 265 }
266 266 break;
267 267 case C:
268 268 if (src[i] == 'o') {
269 269 state = CO;
270 270 charcopy(dest, &destlen, destsize, src[i++]);
271 271 } else {
272 272 state = DEFAULT;
273 273 }
274 274 break;
275 275 case CO:
276 276 if (src[i] == 'm') {
277 277 state = COMLPT;
278 278 i++;
279 279 } else if (src[i] == 'n') {
280 280 state = THIRD;
281 281 i++;
282 282 } else {
283 283 state = DEFAULT;
284 284 }
285 285 break;
286 286 case COMLPT:
287 287 switch (src[i]) {
288 288 case '1':
289 289 case '2':
290 290 case '3':
291 291 case '4':
292 292 case '5':
293 293 case '6':
294 294 case '7':
295 295 case '8':
296 296 case '9':
297 297 state = COMLPTn;
298 298 i++;
299 299 break;
300 300 default:
301 301 state = DEFAULT;
302 302 charcopy(dest, &destlen, destsize, src[i - 1]);
303 303 break;
304 304 }
305 305 break;
306 306 case COMLPTn:
307 307 state = DEFAULT;
308 308 switch (src[i]) {
309 309 case '.':
310 310 case '/':
311 311 case '\0':
312 312 escape3(dest, &destlen, destsize, src[i - 2]);
313 313 charcopy(dest, &destlen, destsize, src[i - 1]);
314 314 break;
315 315 default:
316 316 memcopy(dest, &destlen, destsize, &src[i - 2],
317 317 2);
318 318 break;
319 319 }
320 320 break;
321 321 case L:
322 322 if (src[i] == 'p') {
323 323 state = LP;
324 324 charcopy(dest, &destlen, destsize, src[i++]);
325 325 } else {
326 326 state = DEFAULT;
327 327 }
328 328 break;
329 329 case LP:
330 330 if (src[i] == 't') {
331 331 state = COMLPT;
332 332 i++;
333 333 } else {
334 334 state = DEFAULT;
335 335 }
336 336 break;
337 337 case N:
338 338 if (src[i] == 'u') {
339 339 state = NU;
340 340 charcopy(dest, &destlen, destsize, src[i++]);
341 341 } else {
342 342 state = DEFAULT;
343 343 }
344 344 break;
345 345 case NU:
346 346 if (src[i] == 'l') {
347 347 state = THIRD;
348 348 i++;
349 349 } else {
350 350 state = DEFAULT;
351 351 }
352 352 break;
353 353 case P:
354 354 if (src[i] == 'r') {
355 355 state = PR;
356 356 charcopy(dest, &destlen, destsize, src[i++]);
357 357 } else {
358 358 state = DEFAULT;
359 359 }
360 360 break;
361 361 case PR:
362 362 if (src[i] == 'n') {
363 363 state = THIRD;
364 364 i++;
365 365 } else {
366 366 state = DEFAULT;
367 367 }
368 368 break;
369 369 case LDOT:
370 370 switch (src[i]) {
371 371 case 'd':
372 372 case 'i':
373 373 state = HGDI;
374 374 charcopy(dest, &destlen, destsize, src[i++]);
375 375 break;
376 376 case 'h':
377 377 state = H;
378 378 charcopy(dest, &destlen, destsize, src[i++]);
379 379 break;
380 380 default:
381 381 state = DEFAULT;
382 382 break;
383 383 }
384 384 break;
385 385 case DOT:
386 386 switch (src[i]) {
387 387 case '/':
388 388 case '\0':
389 389 state = START;
390 390 memcopy(dest, &destlen, destsize, "~2e", 3);
391 391 charcopy(dest, &destlen, destsize, src[i++]);
392 392 break;
393 393 case 'd':
394 394 case 'i':
395 395 state = HGDI;
396 396 charcopy(dest, &destlen, destsize, '.');
397 397 charcopy(dest, &destlen, destsize, src[i++]);
398 398 break;
399 399 case 'h':
400 400 state = H;
401 401 memcopy(dest, &destlen, destsize, ".h", 2);
402 402 i++;
403 403 break;
404 404 default:
405 405 state = DEFAULT;
406 406 charcopy(dest, &destlen, destsize, '.');
407 407 break;
408 408 }
409 409 break;
410 410 case H:
411 411 if (src[i] == 'g') {
412 412 state = HGDI;
413 413 charcopy(dest, &destlen, destsize, src[i++]);
414 414 } else {
415 415 state = DEFAULT;
416 416 }
417 417 break;
418 418 case HGDI:
419 419 if (src[i] == '/') {
420 420 state = START;
421 421 if (encodedir) {
422 422 memcopy(dest, &destlen, destsize, ".hg",
423 423 3);
424 424 }
425 425 charcopy(dest, &destlen, destsize, src[i++]);
426 426 } else {
427 427 state = DEFAULT;
428 428 }
429 429 break;
430 430 case SPACE:
431 431 switch (src[i]) {
432 432 case '/':
433 433 case '\0':
434 434 state = START;
435 435 memcopy(dest, &destlen, destsize, "~20", 3);
436 436 charcopy(dest, &destlen, destsize, src[i++]);
437 437 break;
438 438 default:
439 439 state = DEFAULT;
440 440 charcopy(dest, &destlen, destsize, ' ');
441 441 break;
442 442 }
443 443 break;
444 444 case DEFAULT:
445 445 while (inset(onebyte, src[i])) {
446 446 charcopy(dest, &destlen, destsize, src[i++]);
447 447 if (i == len) {
448 448 goto done;
449 449 }
450 450 }
451 451 switch (src[i]) {
452 452 case '.':
453 453 state = DOT;
454 454 i++;
455 455 break;
456 456 case ' ':
457 457 state = SPACE;
458 458 i++;
459 459 break;
460 460 case '/':
461 461 state = START;
462 462 charcopy(dest, &destlen, destsize, '/');
463 463 i++;
464 464 break;
465 465 default:
466 466 if (inset(onebyte, src[i])) {
467 467 do {
468 468 charcopy(dest, &destlen,
469 469 destsize, src[i++]);
470 470 } while (i < len &&
471 471 inset(onebyte, src[i]));
472 472 } else if (inset(twobytes, src[i])) {
473 473 char c = src[i++];
474 474 charcopy(dest, &destlen, destsize, '_');
475 475 charcopy(dest, &destlen, destsize,
476 476 c == '_' ? '_' : c + 32);
477 477 } else {
478 478 escape3(dest, &destlen, destsize,
479 479 src[i++]);
480 480 }
481 481 break;
482 482 }
483 483 break;
484 484 }
485 485 }
486 486 done:
487 487 return destlen;
488 488 }
489 489
490 490 static Py_ssize_t basicencode(char *dest, size_t destsize, const char *src,
491 491 Py_ssize_t len)
492 492 {
493 493 static const uint32_t twobytes[8] = {0, 0, 0x87fffffe};
494 494
495 495 static const uint32_t onebyte[8] = {
496 496 1,
497 497 0x2bff3bfa,
498 498 0x68000001,
499 499 0x2fffffff,
500 500 };
501 501
502 502 Py_ssize_t destlen = 0;
503 503
504 504 return _encode(twobytes, onebyte, dest, destlen, destsize, src, len, 1);
505 505 }
506 506
507 507 static const Py_ssize_t maxstorepathlen = 120;
508 508
509 509 static Py_ssize_t _lowerencode(char *dest, size_t destsize, const char *src,
510 510 Py_ssize_t len)
511 511 {
512 512 static const uint32_t onebyte[8] = {1, 0x2bfffbfb, 0xe8000001,
513 513 0x2fffffff};
514 514
515 515 static const uint32_t lower[8] = {0, 0, 0x7fffffe};
516 516
517 517 Py_ssize_t i, destlen = 0;
518 518
519 519 for (i = 0; i < len; i++) {
520 520 if (inset(onebyte, src[i])) {
521 521 charcopy(dest, &destlen, destsize, src[i]);
522 522 } else if (inset(lower, src[i])) {
523 523 charcopy(dest, &destlen, destsize, src[i] + 32);
524 524 } else {
525 525 escape3(dest, &destlen, destsize, src[i]);
526 526 }
527 527 }
528 528
529 529 return destlen;
530 530 }
531 531
532 532 PyObject *lowerencode(PyObject *self, PyObject *args)
533 533 {
534 534 char *path;
535 535 Py_ssize_t len, newlen;
536 536 PyObject *ret;
537 537
538 538 if (!PyArg_ParseTuple(args, PY23("s#:lowerencode", "y#:lowerencode"),
539 539 &path, &len)) {
540 540 return NULL;
541 541 }
542 542
543 543 newlen = _lowerencode(NULL, 0, path, len);
544 544 ret = PyBytes_FromStringAndSize(NULL, newlen);
545 545 if (ret) {
546 546 _lowerencode(PyBytes_AS_STRING(ret), newlen, path, len);
547 547 }
548 548
549 549 return ret;
550 550 }
551 551
552 552 /* See store.py:_auxencode for a description. */
553 553 static Py_ssize_t auxencode(char *dest, size_t destsize, const char *src,
554 554 Py_ssize_t len)
555 555 {
556 556 static const uint32_t twobytes[8];
557 557
558 558 static const uint32_t onebyte[8] = {
559 559 ~0U, 0xffff3ffe, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
560 560 };
561 561
562 562 return _encode(twobytes, onebyte, dest, 0, destsize, src, len, 0);
563 563 }
564 564
565 565 static PyObject *hashmangle(const char *src, Py_ssize_t len, const char sha[20])
566 566 {
567 567 static const Py_ssize_t dirprefixlen = 8;
568 568 static const Py_ssize_t maxshortdirslen = 68;
569 569 char *dest;
570 570 PyObject *ret;
571 571
572 572 Py_ssize_t i, d, p, lastslash = len - 1, lastdot = -1;
573 573 Py_ssize_t destsize, destlen = 0, slop, used;
574 574
575 575 while (lastslash >= 0 && src[lastslash] != '/') {
576 576 if (src[lastslash] == '.' && lastdot == -1) {
577 577 lastdot = lastslash;
578 578 }
579 579 lastslash--;
580 580 }
581 581
582 582 #if 0
583 583 /* All paths should end in a suffix of ".i" or ".d".
584 584 Unfortunately, the file names in test-hybridencode.py
585 585 violate this rule. */
586 586 if (lastdot != len - 3) {
587 587 PyErr_SetString(PyExc_ValueError,
588 588 "suffix missing or wrong length");
589 589 return NULL;
590 590 }
591 591 #endif
592 592
593 593 /* If src contains a suffix, we will append it to the end of
594 594 the new string, so make room. */
595 595 destsize = 120;
596 596 if (lastdot >= 0) {
597 597 destsize += len - lastdot - 1;
598 598 }
599 599
600 600 ret = PyBytes_FromStringAndSize(NULL, destsize);
601 601 if (ret == NULL) {
602 602 return NULL;
603 603 }
604 604
605 605 dest = PyBytes_AS_STRING(ret);
606 606 memcopy(dest, &destlen, destsize, "dh/", 3);
607 607
608 608 /* Copy up to dirprefixlen bytes of each path component, up to
609 609 a limit of maxshortdirslen bytes. */
610 610 for (i = d = p = 0; i < lastslash; i++, p++) {
611 611 if (src[i] == '/') {
612 612 char d = dest[destlen - 1];
613 613 /* After truncation, a directory name may end
614 614 in a space or dot, which are unportable. */
615 615 if (d == '.' || d == ' ') {
616 616 dest[destlen - 1] = '_';
617 617 /* The + 3 is to account for "dh/" in the
618 618 * beginning */
619 619 }
620 620 if (destlen > maxshortdirslen + 3) {
621 621 break;
622 622 }
623 623 charcopy(dest, &destlen, destsize, src[i]);
624 624 p = -1;
625 625 } else if (p < dirprefixlen) {
626 626 charcopy(dest, &destlen, destsize, src[i]);
627 627 }
628 628 }
629 629
630 630 /* Rewind to just before the last slash copied. */
631 631 if (destlen > maxshortdirslen + 3) {
632 632 do {
633 633 destlen--;
634 634 } while (destlen > 0 && dest[destlen] != '/');
635 635 }
636 636
637 637 if (destlen > 3) {
638 638 if (lastslash > 0) {
639 639 char d = dest[destlen - 1];
640 640 /* The last directory component may be
641 641 truncated, so make it safe. */
642 642 if (d == '.' || d == ' ') {
643 643 dest[destlen - 1] = '_';
644 644 }
645 645 }
646 646
647 647 charcopy(dest, &destlen, destsize, '/');
648 648 }
649 649
650 650 /* Add a prefix of the original file's name. Its length
651 651 depends on the number of bytes left after accounting for
652 652 hash and suffix. */
653 653 used = destlen + 40;
654 654 if (lastdot >= 0) {
655 655 used += len - lastdot - 1;
656 656 }
657 657 slop = maxstorepathlen - used;
658 658 if (slop > 0) {
659 659 Py_ssize_t basenamelen =
660 660 lastslash >= 0 ? len - lastslash - 2 : len - 1;
661 661
662 662 if (basenamelen > slop) {
663 663 basenamelen = slop;
664 664 }
665 665 if (basenamelen > 0) {
666 666 memcopy(dest, &destlen, destsize, &src[lastslash + 1],
667 667 basenamelen);
668 668 }
669 669 }
670 670
671 671 /* Add hash and suffix. */
672 672 for (i = 0; i < 20; i++) {
673 673 hexencode(dest, &destlen, destsize, sha[i]);
674 674 }
675 675
676 676 if (lastdot >= 0) {
677 677 memcopy(dest, &destlen, destsize, &src[lastdot],
678 678 len - lastdot - 1);
679 679 }
680 680
681 681 assert(PyBytes_Check(ret));
682 682 Py_SET_SIZE(ret, destlen);
683 683
684 684 return ret;
685 685 }
686 686
687 687 /*
688 688 * Avoiding a trip through Python would improve performance by 50%,
689 689 * but we don't encounter enough long names to be worth the code.
690 690 */
691 691 static int sha1hash(char hash[20], const char *str, Py_ssize_t len)
692 692 {
693 693 static PyObject *shafunc;
694 694 PyObject *shaobj, *hashobj;
695 695
696 696 if (shafunc == NULL) {
697 697 PyObject *hashlib = PyImport_ImportModule("hashlib");
698 698 if (hashlib == NULL) {
699 699 PyErr_SetString(PyExc_ImportError,
700 700 "pathencode failed to find hashlib");
701 701 return -1;
702 702 }
703 703 shafunc = PyObject_GetAttrString(hashlib, "sha1");
704 704 Py_DECREF(hashlib);
705 705
706 706 if (shafunc == NULL) {
707 707 PyErr_SetString(PyExc_AttributeError,
708 708 "module 'hashlib' has no "
709 709 "attribute 'sha1' in pathencode");
710 710 return -1;
711 711 }
712 712 }
713 713
714 714 shaobj = PyObject_CallFunction(shafunc, PY23("s#", "y#"), str, len);
715 715
716 716 if (shaobj == NULL) {
717 717 return -1;
718 718 }
719 719
720 720 hashobj = PyObject_CallMethod(shaobj, "digest", "");
721 721 Py_DECREF(shaobj);
722 722 if (hashobj == NULL) {
723 723 return -1;
724 724 }
725 725
726 726 if (!PyBytes_Check(hashobj) || PyBytes_GET_SIZE(hashobj) != 20) {
727 727 PyErr_SetString(PyExc_TypeError,
728 728 "result of digest is not a 20-byte hash");
729 729 Py_DECREF(hashobj);
730 730 return -1;
731 731 }
732 732
733 733 memcpy(hash, PyBytes_AS_STRING(hashobj), 20);
734 734 Py_DECREF(hashobj);
735 735 return 0;
736 736 }
737 737
738 738 #define MAXENCODE 4096 * 4
739 739
740 740 static PyObject *hashencode(const char *src, Py_ssize_t len)
741 741 {
742 742 char dired[MAXENCODE];
743 743 char lowered[MAXENCODE];
744 744 char auxed[MAXENCODE];
745 745 Py_ssize_t dirlen, lowerlen, auxlen, baselen;
746 746 char sha[20];
747 747
748 748 baselen = (len - 5) * 3;
749 749 if (baselen >= MAXENCODE) {
750 750 PyErr_SetString(PyExc_ValueError, "string too long");
751 751 return NULL;
752 752 }
753 753
754 754 dirlen = _encodedir(dired, baselen, src, len);
755 755 if (sha1hash(sha, dired, dirlen - 1) == -1) {
756 756 return NULL;
757 757 }
758 758 lowerlen = _lowerencode(lowered, baselen, dired + 5, dirlen - 5);
759 759 auxlen = auxencode(auxed, baselen, lowered, lowerlen);
760 760 return hashmangle(auxed, auxlen, sha);
761 761 }
762 762
763 763 PyObject *pathencode(PyObject *self, PyObject *args)
764 764 {
765 765 Py_ssize_t len, newlen;
766 766 PyObject *pathobj, *newobj;
767 767 char *path;
768 768
769 769 if (!PyArg_ParseTuple(args, "O:pathencode", &pathobj)) {
770 770 return NULL;
771 771 }
772 772
773 773 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
774 774 PyErr_SetString(PyExc_TypeError, "expected a string");
775 775 return NULL;
776 776 }
777 777
778 778 if (len > maxstorepathlen) {
779 779 newlen = maxstorepathlen + 2;
780 780 } else {
781 781 newlen = len ? basicencode(NULL, 0, path, len + 1) : 1;
782 782 }
783 783
784 784 if (newlen <= maxstorepathlen + 1) {
785 785 if (newlen == len + 1) {
786 786 Py_INCREF(pathobj);
787 787 return pathobj;
788 788 }
789 789
790 790 newobj = PyBytes_FromStringAndSize(NULL, newlen);
791 791
792 792 if (newobj) {
793 793 assert(PyBytes_Check(newobj));
794 Py_SIZE(newobj)--;
794 Py_SET_SIZE(newobj, Py_SIZE(newobj) - 1);
795 795 basicencode(PyBytes_AS_STRING(newobj), newlen, path,
796 796 len + 1);
797 797 }
798 798 } else {
799 799 newobj = hashencode(path, len + 1);
800 800 }
801 801
802 802 return newobj;
803 803 }
General Comments 0
You need to be logged in to leave comments. Login now