From 4f05a9d066337a883d8d82b531ff8db5c989e5b9 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Thu, 31 Mar 2022 20:38:24 +0100 Subject: [PATCH] Add path_strip_last_volume This gets the volume that the path eventually refers to by parsing the last volume specifier and returning the part of the path after it (which does not contain any volume specifiers). The initial part of the path therefore contains everything up to and including the last volume specifier. Change-Id: I9a935543256f8f22e0b8b1e3c88d4e47bd9dae8a --- firmware/common/pathfuncs.c | 39 +++++++++++++++++++++++++++++++++++-- firmware/export/pathfuncs.h | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/firmware/common/pathfuncs.c b/firmware/common/pathfuncs.c index 5242ec2d32..b942fdf022 100644 --- a/firmware/common/pathfuncs.c +++ b/firmware/common/pathfuncs.c @@ -109,8 +109,8 @@ static const unsigned char storage_dec_indexes[STORAGE_NUM_TYPES+1] = /* Returns on which volume this is and sets *nameptr to the portion of the * path after the volume specifier, which could be the null if the path is * just a volume root. If *nameptr > name, then a volume specifier was - * found. If 'greedy' is 'true', then it all separators after the volume - * specifier are consumed, if one was found. + * found. If 'greedy' is 'true', then all separators after the volume + * specifier are consumed. */ int path_strip_volume(const char *name, const char **nameptr, bool greedy) { @@ -167,6 +167,41 @@ psv_out: return volume; } +/* Strip the last volume component in the path and return the remainder of + * the path in *nameptr. If 'greedy' is 'true', then all separators after + * the volume specifier are consumed. + */ +int path_strip_last_volume(const char *name, const char **nameptr, bool greedy) +{ + const char *p = name + strlen(name); + + while (p > name) + { + /* skip the component */ + while (p > name && p[-1] != PATH_SEPCH) + --p; + + /* bail if we reached the beginning */ + if (p <= name+1) + break; + + /* point at the seprator */ + --p; + + /* try to strip the volume and return it if found */ + int volume = path_strip_volume(p, nameptr, greedy); + if (volume != ROOT_VOLUME) + return volume; + + /* skip any extra separators */ + while (p > name && p[-1] == PATH_SEPCH) + --p; + } + + /* return whatever is at the beginning of the path */ + return path_strip_volume(name, nameptr, greedy); +} + /* Returns the volume specifier decorated with the storage type name. * Assumes the supplied buffer size is at least {VOL_MAX_LEN}+1. */ diff --git a/firmware/export/pathfuncs.h b/firmware/export/pathfuncs.h index 385d534714..d4fa4eb460 100644 --- a/firmware/export/pathfuncs.h +++ b/firmware/export/pathfuncs.h @@ -79,6 +79,7 @@ static inline bool name_is_dot_dot(const char *name) #ifdef HAVE_MULTIVOLUME int path_strip_volume(const char *name, const char **nameptr, bool greedy); +int path_strip_last_volume(const char *name, const char **nameptr, bool greedy); int get_volume_name(int volume, char *name); int make_volume_root(int volume, char *dst); #endif