diff options
Diffstat (limited to 'lib/sqfs/src/dir_reader/get_path.c')
-rw-r--r-- | lib/sqfs/src/dir_reader/get_path.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/lib/sqfs/src/dir_reader/get_path.c b/lib/sqfs/src/dir_reader/get_path.c new file mode 100644 index 0000000..847bfd3 --- /dev/null +++ b/lib/sqfs/src/dir_reader/get_path.c @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * get_path.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#define SQFS_BUILDING_DLL +#include "internal.h" + +#include <string.h> +#include <stdlib.h> + +int sqfs_tree_node_get_path(const sqfs_tree_node_t *node, char **out) +{ + const sqfs_tree_node_t *it; + size_t clen, len = 0; + char *str, *ptr; + + *out = NULL; + + if (node == NULL) + return SQFS_ERROR_ARG_INVALID; + + for (it = node; it->parent != NULL; it = it->parent) { + if (it->parent == node) + return SQFS_ERROR_LINK_LOOP; + + /* non-root nodes must have a valid name */ + clen = strlen((const char *)it->name); + + if (clen == 0) + return SQFS_ERROR_CORRUPTED; + + if (strchr((const char *)it->name, '/') != NULL) + return SQFS_ERROR_CORRUPTED; + + if (it->name[0] == '.') { + if (clen == 1 || (clen == 2 && it->name[1] == '.')) + return SQFS_ERROR_CORRUPTED; + } + + /* compute total path length */ + if (SZ_ADD_OV(clen, 1, &clen)) + return SQFS_ERROR_OVERFLOW; + + if (SZ_ADD_OV(len, clen, &len)) + return SQFS_ERROR_OVERFLOW; + } + + /* root node must not have a name */ + if (it->name[0] != '\0') + return SQFS_ERROR_ARG_INVALID; + + /* generate the path */ + if (node->parent == NULL) { + str = strdup("/"); + if (str == NULL) + return SQFS_ERROR_ALLOC; + } else { + if (SZ_ADD_OV(len, 1, &len)) + return SQFS_ERROR_OVERFLOW; + + str = malloc(len); + if (str == NULL) + return SQFS_ERROR_ALLOC; + + ptr = str + len - 1; + *ptr = '\0'; + + for (it = node; it->parent != NULL; it = it->parent) { + len = strlen((const char *)it->name); + ptr -= len; + + memcpy(ptr, (const char *)it->name, len); + *(--ptr) = '/'; + } + } + + *out = str; + return 0; +} |