diff options
author | William Wilgus <wilgus.william@gmail.com> | 2023-11-11 00:01:34 -0500 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2023-11-19 12:00:02 -0500 |
commit | dbe20d453d5e93bd0f1188a8851c6cf4fd230b26 (patch) | |
tree | 943a01d0aaf051bb7ad47d390bcb848058cb2404 /firmware/common | |
parent | a7d0ff200066ff4d102ffff9e24d3c2b8ef7fde5 (diff) | |
download | rockbox-dbe20d453d5e93bd0f1188a8851c6cf4fd230b26.tar.gz rockbox-dbe20d453d5e93bd0f1188a8851c6cf4fd230b26.zip |
Extend path_append_ex to truncate compname, remove some strmemdupa
remove some duplicated strings previously allocd off the stack
just removing string duplications that are easily handled with truncation
now available with path_append_ex()
this also has an advantage of less stack used in worst case scenarios
Change-Id: I3a43e33ef8a8c36599e4c6c036a0ccdd8ed0c883
Diffstat (limited to 'firmware/common')
-rw-r--r-- | firmware/common/dircache.c | 89 | ||||
-rw-r--r-- | firmware/common/file.c | 5 | ||||
-rw-r--r-- | firmware/common/file_internal.c | 9 | ||||
-rw-r--r-- | firmware/common/pathfuncs.c | 69 |
4 files changed, 119 insertions, 53 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 41564194d0..c5062d47ed 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -2488,44 +2488,81 @@ struct get_path_sub_data | |||
2488 | 2488 | ||
2489 | static ssize_t get_path_sub(int idx, struct get_path_sub_data *data) | 2489 | static ssize_t get_path_sub(int idx, struct get_path_sub_data *data) |
2490 | { | 2490 | { |
2491 | |||
2492 | #ifdef HAVE_MULTIVOLUME | ||
2493 | #define NAMEBUFLEN (MAX(VOL_MAX_LEN+1, MAX_TINYNAME+1)) | ||
2494 | #else | ||
2495 | #define NAMEBUFLEN (MAX_TINYNAME+1) | ||
2496 | #endif | ||
2497 | char namebuf[NAMEBUFLEN]; | ||
2498 | #undef NAMEBUFLEN | ||
2499 | |||
2491 | if (idx == 0) | 2500 | if (idx == 0) |
2492 | return -1; /* entry is an orphan split from any root */ | 2501 | return -1; /* entry is an orphan split from any root */ |
2493 | 2502 | ||
2494 | ssize_t len; | 2503 | char *cename = ""; |
2495 | char *cename; | 2504 | size_t cename_len = (-1u); |
2505 | ssize_t len = 0; | ||
2506 | int next_idx = idx; | ||
2507 | int count = 1; /* +1 for the idx incoming */ | ||
2508 | int remain; | ||
2496 | 2509 | ||
2497 | if (idx > 0) | 2510 | do /* go all the way up to the root */ |
2498 | { | 2511 | { |
2499 | struct dircache_entry *ce = get_entry(idx); | 2512 | count++; |
2513 | if (next_idx > (int)dircache.numentries) | ||
2514 | return -1; /* ERROR! */ | ||
2515 | next_idx = dircache_runinfo.pentry[next_idx].up; | ||
2516 | } while (next_idx > 0); | ||
2500 | 2517 | ||
2501 | data->serialhash = dc_hash_serialnum(ce->serialnum, data->serialhash); | 2518 | if (next_idx < 0) /* root */ |
2519 | { | ||
2520 | data->serialhash = dc_hash_serialnum(get_idx_dcvolp(next_idx)->serialnum, | ||
2521 | data->serialhash); | ||
2522 | #ifdef HAVE_MULTIVOLUME | ||
2523 | /* prepend the volume specifier */ | ||
2524 | cename = namebuf; | ||
2525 | get_volume_name(IF_MV_VOL(-next_idx - 1), cename); | ||
2526 | #endif /* HAVE_MULTIVOLUME */ | ||
2527 | } | ||
2502 | 2528 | ||
2503 | /* go all the way up then move back down from the root */ | 2529 | /* we have the volume name write it to the buffer */ |
2504 | len = get_path_sub(ce->up, data) - 1; | 2530 | goto write_path_component; |
2505 | if (len < 0) | 2531 | /* if not MULTIVOLUME it will just be adding '/' */ |
2506 | return -2; | ||
2507 | 2532 | ||
2508 | cename = alloca(DC_MAX_NAME + 1); | 2533 | while (next_idx > 0 && count > 0) |
2509 | entry_name_copy(cename, ce); | ||
2510 | } | ||
2511 | else /* idx < 0 */ | ||
2512 | { | 2534 | { |
2513 | len = 0; | 2535 | struct dircache_entry *ce = &dircache_runinfo.pentry[next_idx]; |
2514 | cename = ""; | 2536 | if (remain <= 0) |
2537 | { | ||
2538 | data->serialhash = dc_hash_serialnum(ce->serialnum, data->serialhash); | ||
2539 | if (LIKELY(!ce->tinyname)) | ||
2540 | { | ||
2541 | cename = get_name(ce->name); | ||
2542 | cename_len = CE_NAMESIZE(ce->namelen); | ||
2543 | } | ||
2544 | else | ||
2545 | { | ||
2546 | cename = namebuf; | ||
2547 | entry_name_copy(cename, ce); | ||
2548 | cename_len = -1u; | ||
2549 | } | ||
2550 | write_path_component: | ||
2551 | len += path_append_ex(data->buf + len, PA_SEP_HARD, -1u, cename, cename_len, | ||
2552 | data->size > (size_t)len ? data->size - len : 0); | ||
2515 | 2553 | ||
2516 | #ifdef HAVE_MULTIVOLUME | 2554 | count--; |
2517 | /* prepend the volume specifier */ | 2555 | remain = count - 1; |
2518 | int volume = IF_MV_VOL(-idx - 1); | 2556 | next_idx = idx; |
2519 | cename = alloca(VOL_MAX_LEN+1); | 2557 | } |
2520 | get_volume_name(volume, cename); | 2558 | else |
2521 | #endif /* HAVE_MULTIVOLUME */ | 2559 | { |
2560 | remain--; | ||
2561 | next_idx = ce->up; | ||
2562 | } | ||
2522 | 2563 | ||
2523 | data->serialhash = dc_hash_serialnum(get_idx_dcvolp(idx)->serialnum, | ||
2524 | data->serialhash); | ||
2525 | } | 2564 | } |
2526 | 2565 | return len; | |
2527 | return len + path_append(data->buf + len, PA_SEP_HARD, cename, | ||
2528 | data->size > (size_t)len ? data->size - len : 0); | ||
2529 | } | 2566 | } |
2530 | 2567 | ||
2531 | /** | 2568 | /** |
diff --git a/firmware/common/file.c b/firmware/common/file.c index 202410db81..2012e2ff80 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c | |||
@@ -1056,7 +1056,7 @@ int rename(const char *old, const char *new) | |||
1056 | FILE_ERROR(EINVAL, -4); | 1056 | FILE_ERROR(EINVAL, -4); |
1057 | } | 1057 | } |
1058 | 1058 | ||
1059 | const char * const oldname = strmemdupa(oldinfo.name, oldinfo.length); | 1059 | //const char * const oldname = strmemdupa(oldinfo.name, oldinfo.length); |
1060 | const char * const newname = strmemdupa(newinfo.name, newinfo.length); | 1060 | const char * const newname = strmemdupa(newinfo.name, newinfo.length); |
1061 | bool is_overwrite = false; | 1061 | bool is_overwrite = false; |
1062 | 1062 | ||
@@ -1076,7 +1076,8 @@ int rename(const char *old, const char *new) | |||
1076 | FILE_ERROR(ERRNO, rc * 10 - 5); | 1076 | FILE_ERROR(ERRNO, rc * 10 - 5); |
1077 | } | 1077 | } |
1078 | } | 1078 | } |
1079 | else if (!strcmp(newname, oldname)) /* case-only is ok */ | 1079 | else if (!strncmp(newname, oldinfo.name, oldinfo.length) && /* case-only is ok */ |
1080 | newname[oldinfo.length] == '\0') /* make sure of actual match */ | ||
1080 | { | 1081 | { |
1081 | DEBUGF("No name change (success)\n"); | 1082 | DEBUGF("No name change (success)\n"); |
1082 | rc = 0; | 1083 | rc = 0; |
diff --git a/firmware/common/file_internal.c b/firmware/common/file_internal.c index a73d9beaa2..8e0df576bf 100644 --- a/firmware/common/file_internal.c +++ b/firmware/common/file_internal.c | |||
@@ -433,7 +433,7 @@ static NO_INLINE int open_path_component(struct pathwalk *walkp, | |||
433 | int rc; | 433 | int rc; |
434 | 434 | ||
435 | /* create a null-terminated copy of the component name */ | 435 | /* create a null-terminated copy of the component name */ |
436 | char *compname = strmemdupa(compp->name, compp->length); | 436 | //char *compname = strmemdupa(compp->name, compp->length); |
437 | 437 | ||
438 | unsigned int callflags = walkp->callflags; | 438 | unsigned int callflags = walkp->callflags; |
439 | struct pathwalk_component *parentp = compp->nextp; | 439 | struct pathwalk_component *parentp = compp->nextp; |
@@ -455,7 +455,8 @@ static NO_INLINE int open_path_component(struct pathwalk *walkp, | |||
455 | if (rc > 1 && !(callflags & FF_NOISO)) | 455 | if (rc > 1 && !(callflags & FF_NOISO)) |
456 | iso_decode_d_name(dir_fatent.name); | 456 | iso_decode_d_name(dir_fatent.name); |
457 | 457 | ||
458 | if (!strcasecmp(compname, dir_fatent.name)) | 458 | if (!strncasecmp(compp->name, dir_fatent.name, compp->length) && |
459 | dir_fatent.name[compp->length] == '\0') /* make sure of actual match */ | ||
459 | break; | 460 | break; |
460 | } | 461 | } |
461 | 462 | ||
@@ -474,8 +475,8 @@ static NO_INLINE int open_path_component(struct pathwalk *walkp, | |||
474 | &compp->info.fatfile); | 475 | &compp->info.fatfile); |
475 | if (rc < 0) | 476 | if (rc < 0) |
476 | { | 477 | { |
477 | DEBUGF("I/O error opening file/directory %s (%d)\n", | 478 | DEBUGF("I/O error opening file/directory %.*s (%d)\n", |
478 | compname, rc); | 479 | compp->length, compp->name, rc); |
479 | return -EIO; | 480 | return -EIO; |
480 | } | 481 | } |
481 | 482 | ||
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. |