diff options
Diffstat (limited to 'firmware/common/pathfuncs.c')
-rw-r--r-- | firmware/common/pathfuncs.c | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/firmware/common/pathfuncs.c b/firmware/common/pathfuncs.c index ff3de7b616..0fbac68221 100644 --- a/firmware/common/pathfuncs.c +++ b/firmware/common/pathfuncs.c | |||
@@ -447,10 +447,22 @@ void path_remove_dot_segments (char *dstpath, const char *path) | |||
447 | *dstp = 0; | 447 | *dstp = 0; |
448 | } | 448 | } |
449 | 449 | ||
450 | /* helper function copy n chars of a string to a dst buffer of dst_sz | ||
451 | * returns the length of the string it created or attempted to create | ||
452 | */ | ||
453 | static inline size_t copynchars(char *dst, size_t dst_sz, const char *src, size_t src_max) | ||
454 | { | ||
455 | int cpychrs = -1; | ||
456 | if (src_max < -1u) /* we could be dealing with unterminated strings */ | ||
457 | cpychrs = src_max; | ||
458 | /* testing shows this to be on par with using discreet functions and safer ;) */ | ||
459 | int ret = snprintf(dst, dst_sz, "%.*s", cpychrs, src); | ||
460 | if (ret >= 0) | ||
461 | return ret; | ||
462 | |||
463 | return 0; /* Error */ | ||
464 | } | ||
450 | /* Appends one path to another, adding separators between components if needed. | 465 | /* Appends one path to another, adding separators between components if needed. |
451 | * basepath_max can be used to truncate the basepath if desired | ||
452 | * NOTE: basepath is truncated after copying to the buffer so there must be enough | ||
453 | * free space for the entirety of the basepath even if the resulting string would fit | ||
454 | * | 466 | * |
455 | * Return value and behavior is otherwise as strlcpy so that truncation may be | 467 | * Return value and behavior is otherwise as strlcpy so that truncation may be |
456 | * detected. | 468 | * detected. |
@@ -458,45 +470,52 @@ void path_remove_dot_segments (char *dstpath, const char *path) | |||
458 | * For basepath and component: | 470 | * For basepath and component: |
459 | * PA_SEP_HARD adds a separator even if the base path is empty | 471 | * PA_SEP_HARD adds a separator even if the base path is empty |
460 | * PA_SEP_SOFT adds a separator only if the base path is not empty | 472 | * PA_SEP_SOFT adds a separator only if the base path is not empty |
473 | * | ||
474 | * basepath_max can be used to truncate the basepath if desired | ||
475 | * component_max can be used to truncate the component if desired | ||
476 | * | ||
477 | * (Supply -1u to disable truncation) | ||
461 | */ | 478 | */ |
462 | size_t path_append_ex(char *buf, const char *basepath, size_t basepath_max, | 479 | size_t path_append_ex(char *buf, const char *basepath, size_t basepath_max, |
463 | const char *component, size_t bufsize) | 480 | const char *component, size_t component_max, size_t bufsize) |
464 | { | 481 | { |
465 | size_t len; | 482 | size_t len; |
483 | bool check_base = (basepath_max == 0); | ||
466 | bool separate = false; | 484 | bool separate = false; |
467 | const char *base = basepath && basepath[0] ? basepath : buf; | 485 | const char *base = basepath && !check_base && basepath[0] ? basepath : buf; |
486 | |||
468 | if (!base) | 487 | if (!base) |
469 | return bufsize; /* won't work to get lengths from buf */ | 488 | return bufsize; /* won't work to get lengths from buf */ |
470 | 489 | ||
471 | if (!buf) | 490 | if (!buf) |
491 | { | ||
492 | static char fbuf; /* fake buffer to elide later null checks */ | ||
493 | buf = &fbuf; | ||
472 | bufsize = 0; | 494 | bufsize = 0; |
473 | 495 | } | |
496 | if (!component) | ||
497 | { | ||
498 | check_base = true; | ||
499 | component = ""; | ||
500 | } | ||
474 | if (path_is_absolute(component)) | 501 | if (path_is_absolute(component)) |
475 | { | 502 | { |
476 | /* 'component' is absolute; replace all */ | 503 | /* 'component' is absolute; replace all */ |
477 | basepath = component; | 504 | basepath = component; |
505 | basepath_max = component_max; | ||
478 | component = ""; | 506 | component = ""; |
479 | basepath_max = -1u; | ||
480 | } | 507 | } |
481 | 508 | ||
482 | /* if basepath is not null or empty, buffer contents are replaced, | 509 | /* if basepath is not null or empty, buffer contents are replaced, |
483 | otherwise buf contains the base path */ | 510 | otherwise buf contains the base path */ |
484 | |||
485 | if (base == buf) | 511 | if (base == buf) |
486 | len = strlen(buf); | 512 | len = strlen(buf); |
487 | else | 513 | else |
488 | { | 514 | len = copynchars(buf, bufsize, basepath, basepath_max); |
489 | len = strlcpy(buf, basepath, bufsize); | ||
490 | if (basepath_max < len) | ||
491 | { | ||
492 | len = basepath_max; | ||
493 | buf[basepath_max] = '\0'; | ||
494 | } | ||
495 | } | ||
496 | 515 | ||
497 | if (!basepath || !component || basepath_max == 0) | 516 | if (!basepath || basepath_max == 0 || check_base) |
498 | separate = !len || base[len-1] != PATH_SEPCH; | 517 | separate = !len || base[len-1] != PATH_SEPCH; |
499 | else if (component[0]) | 518 | else if (component[0] && component_max > 0) |
500 | separate = len && base[len-1] != PATH_SEPCH; | 519 | separate = len && base[len-1] != PATH_SEPCH; |
501 | 520 | ||
502 | /* caller might lie about size of buf yet use buf as the base */ | 521 | /* caller might lie about size of buf yet use buf as the base */ |
@@ -509,14 +528,22 @@ size_t path_append_ex(char *buf, const char *basepath, size_t basepath_max, | |||
509 | if (separate && (len++, bufsize > 0) && --bufsize > 0) | 528 | if (separate && (len++, bufsize > 0) && --bufsize > 0) |
510 | *buf++ = PATH_SEPCH; | 529 | *buf++ = PATH_SEPCH; |
511 | 530 | ||
512 | return len + strlcpy(buf, component ?: "", bufsize); | 531 | return len + copynchars(buf, bufsize, component, component_max); |
513 | } | 532 | } |
514 | 533 | ||
515 | 534 | /* Appends one path to another, adding separators between components if needed. | |
535 | * | ||
536 | * Return value and behavior is otherwise as strlcpy so that truncation may be | ||
537 | * detected. | ||
538 | * | ||
539 | * For basepath and component: | ||
540 | * PA_SEP_HARD adds a separator even if the base path is empty | ||
541 | * PA_SEP_SOFT adds a separator only if the base path is not empty | ||
542 | */ | ||
516 | size_t path_append(char *buf, const char *basepath, | 543 | size_t path_append(char *buf, const char *basepath, |
517 | const char *component, size_t bufsize) | 544 | const char *component, size_t bufsize) |
518 | { | 545 | { |
519 | return path_append_ex(buf, basepath, -1u, component, bufsize); | 546 | return path_append_ex(buf, basepath, -1u, component, -1u, bufsize); |
520 | } | 547 | } |
521 | /* Returns the location and length of the next path component, consuming the | 548 | /* Returns the location and length of the next path component, consuming the |
522 | * input in the process. | 549 | * input in the process. |