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