aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-09-21 15:53:14 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-10-24 15:57:18 +0200
commit7f89eb3cfff465cf32d03a2ae6919252eae67e9b (patch)
treeed776d71106000dfa34ad4de3402fff6fea6c56a
parentc4ab32879df8b5e83b0ebd091ce2c750f53f5633 (diff)
libutil: add a string list helper to replace some of the adhoc ones
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--bin/sqfs2tar/src/iterator.c20
-rw-r--r--bin/sqfs2tar/src/options.c41
-rw-r--r--bin/sqfs2tar/src/sqfs2tar.c4
-rw-r--r--bin/sqfs2tar/src/sqfs2tar.h4
-rw-r--r--bin/tar2sqfs/src/options.c43
-rw-r--r--bin/tar2sqfs/src/tar2sqfs.c4
-rw-r--r--bin/tar2sqfs/src/tar2sqfs.h4
-rw-r--r--include/util/strlist.h38
-rw-r--r--lib/util/Makemodule.am7
-rw-r--r--lib/util/src/strlist.c71
-rw-r--r--lib/util/test/strlist.c110
11 files changed, 266 insertions, 80 deletions
diff --git a/bin/sqfs2tar/src/iterator.c b/bin/sqfs2tar/src/iterator.c
index 42f01e2..7879d61 100644
--- a/bin/sqfs2tar/src/iterator.c
+++ b/bin/sqfs2tar/src/iterator.c
@@ -56,21 +56,21 @@ static bool keep_entry(const sqfs_dir_entry_t *ent)
{
size_t nlen;
- if (num_subdirs == 0)
+ if (subdirs.count == 0)
return true;
nlen = strlen(ent->name);
- for (size_t i = 0; i < num_subdirs; ++i) {
- size_t plen = strlen(subdirs[i]);
+ for (size_t i = 0; i < subdirs.count; ++i) {
+ size_t plen = strlen(subdirs.strings[i]);
if (nlen <= plen) {
- if ((nlen == plen || subdirs[i][nlen] == '/') &&
- strncmp(subdirs[i], ent->name, nlen) == 0) {
+ if ((nlen == plen || subdirs.strings[i][nlen] == '/') &&
+ strncmp(subdirs.strings[i], ent->name, nlen) == 0) {
return true;
}
} else if (ent->name[plen] == '/' &&
- strncmp(subdirs[i], ent->name, plen) == 0) {
+ strncmp(subdirs.strings[i], ent->name, plen) == 0) {
return true;
}
}
@@ -124,8 +124,8 @@ static int next(sqfs_dir_iterator_t *base, sqfs_dir_entry_t **out)
if (keep_entry(ent)) {
/* XXX: skip the entry, but we MUST recurse here! */
- if (num_subdirs == 1 && !keep_as_dir &&
- strlen(ent->name) <= strlen(subdirs[0])) {
+ if (subdirs.count == 1 && !keep_as_dir &&
+ strlen(ent->name) <= strlen(subdirs.strings[0])) {
sqfs_free(ent);
continue;
}
@@ -138,8 +138,8 @@ static int next(sqfs_dir_iterator_t *base, sqfs_dir_entry_t **out)
sqfs_free(ent);
}
- if (num_subdirs == 1 && !keep_as_dir) {
- size_t plen = strlen(subdirs[0]) + 1;
+ if (subdirs.count == 1 && !keep_as_dir) {
+ size_t plen = strlen(subdirs.strings[0]) + 1;
memmove(ent->name, ent->name + plen,
strlen(ent->name + plen) + 1);
diff --git a/bin/sqfs2tar/src/options.c b/bin/sqfs2tar/src/options.c
index ba1588d..82c1d0a 100644
--- a/bin/sqfs2tar/src/options.c
+++ b/bin/sqfs2tar/src/options.c
@@ -70,19 +70,15 @@ bool no_xattr = false;
bool no_links = false;
char *root_becomes = NULL;
-char **subdirs = NULL;
-size_t num_subdirs = 0;
-static size_t max_subdirs = 0;
+strlist_t subdirs = { 0, 0, 0 };
int compressor = 0;
const char *filename = NULL;
void process_args(int argc, char **argv)
{
- size_t idx, new_count;
const char *name;
int i, ret;
- char **new;
for (;;) {
i = getopt_long(argc, argv, short_opts, long_opts, NULL);
@@ -99,27 +95,10 @@ void process_args(int argc, char **argv)
}
break;
case 'd':
- if (num_subdirs == max_subdirs) {
- new_count = max_subdirs ? max_subdirs * 2 : 16;
- new = realloc(subdirs,
- new_count * sizeof(subdirs[0]));
- if (new == NULL)
- goto fail_errno;
-
- max_subdirs = new_count;
- subdirs = new;
- }
-
- subdirs[num_subdirs] = strdup(optarg);
- if (subdirs[num_subdirs] == NULL)
- goto fail_errno;
-
- if (canonicalize_name(subdirs[num_subdirs])) {
- perror(optarg);
+ if (strlist_append(&subdirs, optarg)) {
+ fputs("out-of-memory\n", stderr);
goto fail;
}
-
- ++num_subdirs;
break;
case 'r':
free(root_becomes);
@@ -175,6 +154,14 @@ void process_args(int argc, char **argv)
}
}
+ for (size_t idx = 0; idx < subdirs.count; ++idx) {
+ if (canonicalize_name(subdirs.strings[idx])) {
+ fprintf(stderr, "Invalid name `%s`\n",
+ subdirs.strings[idx]);
+ goto fail;
+ }
+ }
+
if (optind >= argc) {
fputs("Missing argument: squashfs image\n", stderr);
goto fail_arg;
@@ -187,7 +174,7 @@ void process_args(int argc, char **argv)
goto fail_arg;
}
- if (num_subdirs > 1)
+ if (subdirs.count > 1)
keep_as_dir = true;
return;
@@ -204,9 +191,7 @@ out_success:
ret = EXIT_SUCCESS;
goto out_exit;
out_exit:
- for (idx = 0; idx < num_subdirs; ++idx)
- free(subdirs[idx]);
+ strlist_cleanup(&subdirs);
free(root_becomes);
- free(subdirs);
exit(ret);
}
diff --git a/bin/sqfs2tar/src/sqfs2tar.c b/bin/sqfs2tar/src/sqfs2tar.c
index 0f83abf..7404221 100644
--- a/bin/sqfs2tar/src/sqfs2tar.c
+++ b/bin/sqfs2tar/src/sqfs2tar.c
@@ -171,9 +171,7 @@ int main(int argc, char **argv)
out:
sqfs_drop(it);
sqfs_drop(out_file);
- for (i = 0; i < num_subdirs; ++i)
- free(subdirs[i]);
- free(subdirs);
+ strlist_cleanup(&subdirs);
free(root_becomes);
return status;
}
diff --git a/bin/sqfs2tar/src/sqfs2tar.h b/bin/sqfs2tar/src/sqfs2tar.h
index a1a5927..4c9a8f2 100644
--- a/bin/sqfs2tar/src/sqfs2tar.h
+++ b/bin/sqfs2tar/src/sqfs2tar.h
@@ -11,6 +11,7 @@
#include "common.h"
#include "util/util.h"
+#include "util/strlist.h"
#include "tar/tar.h"
#include "xfrm/compress.h"
#include "io/xfrm.h"
@@ -30,8 +31,7 @@ extern bool no_xattr;
extern bool no_links;
extern char *root_becomes;
-extern char **subdirs;
-extern size_t num_subdirs;
+extern strlist_t subdirs;
extern int compressor;
extern const char *filename;
diff --git a/bin/tar2sqfs/src/options.c b/bin/tar2sqfs/src/options.c
index edc27ce..3443ce3 100644
--- a/bin/tar2sqfs/src/options.c
+++ b/bin/tar2sqfs/src/options.c
@@ -93,9 +93,7 @@ bool no_tail_pack = false;
bool no_symlink_retarget = false;
sqfs_writer_cfg_t cfg;
char *root_becomes = NULL;
-char **excludedirs = NULL;
-size_t num_excludedirs = 0;
-static size_t max_excludedirs = 0;
+strlist_t excludedirs = { 0, 0, 0 };
static void input_compressor_print_available(void)
{
@@ -119,10 +117,8 @@ static void input_compressor_print_available(void)
void process_args(int argc, char **argv)
{
- size_t idx, new_count;
bool have_compressor;
int i, ret;
- char **new;
sqfs_writer_cfg_init(&cfg);
@@ -222,29 +218,11 @@ void process_args(int argc, char **argv)
cfg.quiet = true;
break;
case 'E':
- if (num_excludedirs == max_excludedirs) {
- new_count = max_excludedirs ? max_excludedirs * 2 : 16;
- new = realloc(excludedirs,
- new_count * sizeof(excludedirs[0]));
- if (new == NULL)
- goto fail_errno;
-
- max_excludedirs = new_count;
- excludedirs = new;
- }
-
- excludedirs[num_excludedirs] = strdup(optarg);
- if (excludedirs[num_excludedirs] == NULL)
- goto fail_errno;
-
- if (canonicalize_name(excludedirs[num_excludedirs])) {
- perror(optarg);
+ if (strlist_append(&excludedirs, optarg)) {
+ fputs("out-of-memory\n", stderr);
goto fail;
}
-
- ++num_excludedirs;
break;
-
case 'h':
printf(usagestr, SQFS_DEFAULT_BLOCK_SIZE,
SQFS_DEVBLK_SIZE);
@@ -259,6 +237,14 @@ void process_args(int argc, char **argv)
}
}
+ for (size_t idx = 0; idx < excludedirs.count; ++idx) {
+ if (canonicalize_name(excludedirs.strings[idx])) {
+ fprintf(stderr, "Invalid name `%s`\n",
+ excludedirs.strings[idx]);
+ goto fail;
+ }
+ }
+
if (cfg.num_jobs < 1)
cfg.num_jobs = 1;
@@ -282,9 +268,6 @@ void process_args(int argc, char **argv)
goto fail_arg;
}
return;
-fail_errno:
- perror("parsing options");
- goto fail;
fail_arg:
fputs("Try `tar2sqfsr --help' for more information.\n", stderr);
goto fail;
@@ -295,9 +278,7 @@ out_success:
ret = EXIT_SUCCESS;
goto out_exit;
out_exit:
- for (idx = 0; idx < num_excludedirs; ++idx)
- free(excludedirs[idx]);
+ strlist_cleanup(&excludedirs);
free(root_becomes);
- free(excludedirs);
exit(ret);
}
diff --git a/bin/tar2sqfs/src/tar2sqfs.c b/bin/tar2sqfs/src/tar2sqfs.c
index acb42e2..99f012c 100644
--- a/bin/tar2sqfs/src/tar2sqfs.c
+++ b/bin/tar2sqfs/src/tar2sqfs.c
@@ -23,8 +23,8 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
- topts.excludedirs = excludedirs;
- topts.num_excludedirs = num_excludedirs;
+ topts.excludedirs = excludedirs.strings;
+ topts.num_excludedirs = excludedirs.count;
tar = tar_open_stream(input_file, &topts);
sqfs_drop(input_file);
diff --git a/bin/tar2sqfs/src/tar2sqfs.h b/bin/tar2sqfs/src/tar2sqfs.h
index d2049f2..a5b1089 100644
--- a/bin/tar2sqfs/src/tar2sqfs.h
+++ b/bin/tar2sqfs/src/tar2sqfs.h
@@ -12,6 +12,7 @@
#include "compat.h"
#include "util/util.h"
+#include "util/strlist.h"
#include "tar/tar.h"
#include "tar/format.h"
#include "xfrm/compress.h"
@@ -29,8 +30,7 @@ extern bool no_tail_pack;
extern bool no_symlink_retarget;
extern sqfs_writer_cfg_t cfg;
extern char *root_becomes;
-extern char **excludedirs;
-extern size_t num_excludedirs;
+extern strlist_t excludedirs;
void process_args(int argc, char **argv);
diff --git a/include/util/strlist.h b/include/util/strlist.h
new file mode 100644
index 0000000..ace4e20
--- /dev/null
+++ b/include/util/strlist.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/*
+ * strlist.h
+ *
+ * Copyright (C) 2023 David Oberhollenzer <goliath@infraroot.at>
+ */
+#ifndef UTIL_STRLIST_H
+#define UTIL_STRLIST_H
+
+#include "sqfs/predef.h"
+#include <string.h>
+
+typedef struct {
+ char **strings;
+ size_t count;
+ size_t capacity;
+} strlist_t;
+
+static SQFS_INLINE void strlist_init(strlist_t *list)
+{
+ memset(list, 0, sizeof(*list));
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SQFS_INTERNAL int strlist_init_copy(strlist_t *dst, const strlist_t *src);
+
+SQFS_INTERNAL void strlist_cleanup(strlist_t *list);
+
+SQFS_INTERNAL int strlist_append(strlist_t *list, const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UTIL_STRLIST_H */
diff --git a/lib/util/Makemodule.am b/lib/util/Makemodule.am
index 9b2065a..24fb50b 100644
--- a/lib/util/Makemodule.am
+++ b/lib/util/Makemodule.am
@@ -10,7 +10,7 @@ libutil_a_SOURCES = include/util/util.h include/util/str_table.h \
lib/util/src/source_date_epoch.c lib/util/src/file_cmp.c \
lib/util/src/hex_decode.c lib/util/src/base64_decode.c \
lib/util/src/get_line.c lib/util/src/split_line.c \
- lib/util/src/parse_int.c
+ lib/util/src/parse_int.c lib/util/src/strlist.c include/util/strlist.h
libutil_a_CFLAGS = $(AM_CFLAGS)
libutil_a_CPPFLAGS = $(AM_CPPFLAGS)
@@ -87,11 +87,14 @@ test_split_line_LDADD = libutil.a libcompat.a
test_parse_int_SOURCES = lib/util/test/parse_int.c
test_parse_int_LDADD = libutil.a libcompat.a
+test_strlist_SOURCES = lib/util/test/strlist.c
+test_strlist_LDADD = libutil.a libcompat.a
+
LIBUTIL_TESTS = \
test_str_table test_rbtree test_xxhash test_threadpool test_ismemzero \
test_canonicalize_name test_filename_sane test_filename_sane_w32 \
test_sdate_epoch test_hex_decode test_base64_decode test_get_line \
- test_split_line test_parse_int
+ test_split_line test_parse_int test_strlist
check_PROGRAMS += $(LIBUTIL_TESTS)
TESTS += $(LIBUTIL_TESTS)
diff --git a/lib/util/src/strlist.c b/lib/util/src/strlist.c
new file mode 100644
index 0000000..9d1fd78
--- /dev/null
+++ b/lib/util/src/strlist.c
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/*
+ * strlist.c
+ *
+ * Copyright (C) 2023 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "config.h"
+#include "util/strlist.h"
+#include "util/util.h"
+#include "compat.h"
+
+#include <stdlib.h>
+
+void strlist_cleanup(strlist_t *list)
+{
+ for (size_t i = 0; i < list->count; ++i)
+ free(list->strings[i]);
+
+ free(list->strings);
+ memset(list, 0, sizeof(*list));
+}
+
+int strlist_init_copy(strlist_t *dst, const strlist_t *src)
+{
+ memset(dst, 0, sizeof(*dst));
+
+ dst->strings = alloc_array(sizeof(char *), src->capacity);
+ if (dst->strings == NULL)
+ return -1;
+
+ dst->count = src->count;
+ dst->capacity = src->capacity;
+
+ for (size_t i = 0; i < src->count; ++i) {
+ dst->strings[i] = strdup(src->strings[i]);
+
+ if (dst->strings[i] == NULL) {
+ dst->count = i;
+ strlist_cleanup(dst);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int strlist_append(strlist_t *list, const char *str)
+{
+ if (list->count == list->capacity) {
+ size_t new_cap = list->capacity ? (list->capacity * 2) : 128;
+ size_t new_sz;
+ char **new;
+
+ if (SZ_MUL_OV(new_cap, sizeof(char *), &new_sz))
+ return -1;
+
+ new = realloc(list->strings, new_sz);
+ if (new == NULL)
+ return -1;
+
+ list->capacity = new_cap;
+ list->strings = new;
+ }
+
+ list->strings[list->count] = strdup(str);
+ if (list->strings[list->count] == NULL)
+ return -1;
+
+ list->count += 1;
+ return 0;
+}
diff --git a/lib/util/test/strlist.c b/lib/util/test/strlist.c
new file mode 100644
index 0000000..23587b3
--- /dev/null
+++ b/lib/util/test/strlist.c
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * strlist.c
+ *
+ * Copyright (C) 2023 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "config.h"
+#include "util/util.h"
+#include "util/test.h"
+#include "util/strlist.h"
+
+int main(int argc, char **argv)
+{
+ const char *str0, *str1, *str2;
+ strlist_t a, b;
+ int ret;
+ (void)argc; (void)argv;
+
+ str0 = "foo";
+ str1 = "bar";
+ str2 = "baz";
+
+ /* init */
+ strlist_init(&a);
+ TEST_NULL(a.strings);
+ TEST_EQUAL_UI(a.count, 0);
+ TEST_EQUAL_UI(a.capacity, 0);
+
+ /* append a string */
+ ret = strlist_append(&a, str0);
+ TEST_EQUAL_I(ret, 0);
+
+ TEST_EQUAL_UI(a.count, 1);
+ TEST_ASSERT(a.capacity >= a.count);
+
+ TEST_NOT_NULL(a.strings);
+ TEST_NOT_NULL(a.strings[0]);
+
+ TEST_STR_EQUAL(a.strings[0], str0);
+ TEST_ASSERT(a.strings[0] != str0);
+
+ /* append another */
+ ret = strlist_append(&a, str1);
+ TEST_EQUAL_I(ret, 0);
+
+ TEST_EQUAL_UI(a.count, 2);
+ TEST_ASSERT(a.capacity >= a.count);
+
+ TEST_NOT_NULL(a.strings);
+ TEST_NOT_NULL(a.strings[0]);
+ TEST_NOT_NULL(a.strings[1]);
+
+ TEST_ASSERT(a.strings[0] != str0);
+ TEST_ASSERT(a.strings[1] != str1);
+ TEST_STR_EQUAL(a.strings[0], str0);
+ TEST_STR_EQUAL(a.strings[1], str1);
+
+ /* and one more */
+ ret = strlist_append(&a, str2);
+ TEST_EQUAL_I(ret, 0);
+
+ TEST_EQUAL_UI(a.count, 3);
+ TEST_ASSERT(a.capacity >= a.count);
+
+ TEST_NOT_NULL(a.strings);
+ TEST_NOT_NULL(a.strings[0]);
+ TEST_NOT_NULL(a.strings[1]);
+ TEST_NOT_NULL(a.strings[2]);
+
+ TEST_ASSERT(a.strings[0] != str0);
+ TEST_ASSERT(a.strings[1] != str1);
+ TEST_ASSERT(a.strings[2] != str2);
+ TEST_STR_EQUAL(a.strings[0], str0);
+ TEST_STR_EQUAL(a.strings[1], str1);
+ TEST_STR_EQUAL(a.strings[2], str2);
+
+ /* copy */
+ strlist_init_copy(&b, &a);
+ TEST_NOT_NULL(b.strings);
+ TEST_EQUAL_UI(b.count, a.count);
+ TEST_EQUAL_UI(b.capacity, a.capacity);
+
+ TEST_ASSERT(b.strings != a.strings);
+
+ TEST_NOT_NULL(b.strings[0]);
+ TEST_NOT_NULL(b.strings[1]);
+ TEST_NOT_NULL(b.strings[2]);
+
+ TEST_ASSERT(b.strings[0] != a.strings[0]);
+ TEST_ASSERT(b.strings[1] != a.strings[1]);
+ TEST_ASSERT(b.strings[2] != a.strings[2]);
+
+ TEST_STR_EQUAL(b.strings[0], str0);
+ TEST_STR_EQUAL(b.strings[1], str1);
+ TEST_STR_EQUAL(b.strings[2], str2);
+
+ /* cleanup */
+ strlist_cleanup(&a);
+ strlist_cleanup(&b);
+
+ TEST_NULL(a.strings);
+ TEST_NULL(b.strings);
+
+ TEST_EQUAL_UI(a.count, 0);
+ TEST_EQUAL_UI(b.count, 0);
+
+ TEST_EQUAL_UI(a.capacity, 0);
+ TEST_EQUAL_UI(b.capacity, 0);
+ return EXIT_SUCCESS;
+}