From bedec0d2c0489eff8f9666b9b8be0718ce77867e Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sun, 31 May 2026 09:25:42 +0000 Subject: [PATCH] salvage: add initial config helper --- include/nwsalvage.h | 28 +++++++ src/CMakeLists.txt | 2 +- src/nwsalvage.c | 120 +++++++++++++++++++++++++++ tests/salvage/CMakeLists.txt | 16 ++++ tests/salvage/salvage_config_smoke.c | 61 ++++++++++++++ 5 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 include/nwsalvage.h create mode 100644 src/nwsalvage.c create mode 100644 tests/salvage/salvage_config_smoke.c diff --git a/include/nwsalvage.h b/include/nwsalvage.h new file mode 100644 index 0000000..1a46cf3 --- /dev/null +++ b/include/nwsalvage.h @@ -0,0 +1,28 @@ +#ifndef _NWSALVAGE_H_ +#define _NWSALVAGE_H_ + +#include + +#define NWSALVAGE_ENABLE_INI_SECTION 48 +#define NWSALVAGE_REPOSITORY_INI_SECTION 49 + +#define NWSALVAGE_DEFAULT_ENABLED 1 +#define NWSALVAGE_DEFAULT_RECYCLE_NAME ".recycle" +#define NWSALVAGE_DEFAULT_METADATA_NAME ".salvage" +#define NWSALVAGE_REPOSITORY_NAME_MAX 64 + +struct nwsalvage_config { + int enabled; + char recycle_repository[NWSALVAGE_REPOSITORY_NAME_MAX]; + char metadata_repository[NWSALVAGE_REPOSITORY_NAME_MAX]; +}; + +int nwsalvage_config_defaults(struct nwsalvage_config *config); +int nwsalvage_config_set_repositories(struct nwsalvage_config *config, + const char *recycle_repository, + const char *metadata_repository); +int nwsalvage_config_parse_repositories(struct nwsalvage_config *config, + const char *line); +int nwsalvage_repository_name_valid(const char *name); + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd17d39..d449d74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,7 +60,7 @@ ELSE(ENABLE_INTERNAL_RIP_SAP) ENDIF(ENABLE_INTERNAL_RIP_SAP) add_executable(nwserv nwserv.c net1.c tools.c ${EMUTLI} ${EMUTLI1} ${NWROUTE_0} ) -add_executable(nwconn nwconn.c net1.c tools.c connect.c namspace.c nwvolume.c nwfile.c unxfile.c nwqconn.c nameos2.c namedos.c nwfname.c nwshare.c extpipe.c nwattrib.c trustee.c nwarchive.c nwatalk.c nwxattr.c ${EMUTLI} ) +add_executable(nwconn nwconn.c net1.c tools.c connect.c namspace.c nwvolume.c nwfile.c unxfile.c nwqconn.c nameos2.c namedos.c nwfname.c nwshare.c extpipe.c nwattrib.c trustee.c nwarchive.c nwatalk.c nwxattr.c nwsalvage.c ${EMUTLI} ) add_executable(ncpserv ncpserv.c net1.c tools.c ${EMUTLI} ) add_executable(nwclient nwclient.c net1.c tools.c ${EMUTLI} ) add_executable(nwbind nwbind.c net1.c tools.c nwdbm.c nwcrypt.c unxlog.c sema.c nwqueue.c unxfile.c ${EMUTLI} ) diff --git a/src/nwsalvage.c b/src/nwsalvage.c new file mode 100644 index 0000000..d95d266 --- /dev/null +++ b/src/nwsalvage.c @@ -0,0 +1,120 @@ +/* nwsalvage.c - NetWare salvage/recycle backend helpers */ +#include "nwsalvage.h" + +#include +#include +#include + +int nwsalvage_repository_name_valid(const char *name) +{ + size_t len; + + if (!name || !*name) { + errno = EINVAL; + return(0); + } + + len = strlen(name); + if (len >= NWSALVAGE_REPOSITORY_NAME_MAX) { + errno = ENAMETOOLONG; + return(0); + } + + if (!strcmp(name, ".") || !strcmp(name, "..")) { + errno = EINVAL; + return(0); + } + + if (strchr(name, '/') || strchr(name, '\\') || strchr(name, ':')) { + errno = EINVAL; + return(0); + } + + return(1); +} + +int nwsalvage_config_set_repositories(struct nwsalvage_config *config, + const char *recycle_repository, + const char *metadata_repository) +{ + if (!config || + !nwsalvage_repository_name_valid(recycle_repository) || + !nwsalvage_repository_name_valid(metadata_repository)) { + if (!errno) errno = EINVAL; + return(-1); + } + + strncpy(config->recycle_repository, recycle_repository, + sizeof(config->recycle_repository)); + config->recycle_repository[sizeof(config->recycle_repository) - 1] = '\0'; + + strncpy(config->metadata_repository, metadata_repository, + sizeof(config->metadata_repository)); + config->metadata_repository[sizeof(config->metadata_repository) - 1] = '\0'; + + return(0); +} + +int nwsalvage_config_defaults(struct nwsalvage_config *config) +{ + if (!config) { + errno = EINVAL; + return(-1); + } + + memset(config, 0, sizeof(*config)); + config->enabled = NWSALVAGE_DEFAULT_ENABLED; + return(nwsalvage_config_set_repositories(config, + NWSALVAGE_DEFAULT_RECYCLE_NAME, + NWSALVAGE_DEFAULT_METADATA_NAME)); +} + +static int parse_token(const char **cursor, char *out, size_t out_len) +{ + const char *p = *cursor; + size_t len = 0; + + while (*p && isspace((unsigned char)*p)) p++; + if (!*p) { + errno = EINVAL; + return(-1); + } + + while (p[len] && !isspace((unsigned char)p[len])) len++; + if (len >= out_len) { + errno = ENAMETOOLONG; + return(-1); + } + + memcpy(out, p, len); + out[len] = '\0'; + *cursor = p + len; + return(0); +} + +int nwsalvage_config_parse_repositories(struct nwsalvage_config *config, + const char *line) +{ + const char *p = line; + char recycle_repository[NWSALVAGE_REPOSITORY_NAME_MAX]; + char metadata_repository[NWSALVAGE_REPOSITORY_NAME_MAX]; + + if (!config || !line) { + errno = EINVAL; + return(-1); + } + + if (parse_token(&p, recycle_repository, sizeof(recycle_repository)) < 0 || + parse_token(&p, metadata_repository, sizeof(metadata_repository)) < 0) + return(-1); + + while (*p && isspace((unsigned char)*p)) p++; + if (*p) { + errno = EINVAL; + return(-1); + } + + return(nwsalvage_config_set_repositories(config, + recycle_repository, + metadata_repository)); +} diff --git a/tests/salvage/CMakeLists.txt b/tests/salvage/CMakeLists.txt index 919cb0e..5fda9f9 100644 --- a/tests/salvage/CMakeLists.txt +++ b/tests/salvage/CMakeLists.txt @@ -26,3 +26,19 @@ add_custom_target(salvage_layout_smoke ALL set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${SALVAGE_LAYOUT_SMOKE_SCRIPT} ) + +add_executable(salvage_config_smoke + salvage_config_smoke.c + ${CMAKE_SOURCE_DIR}/src/nwsalvage.c +) + +target_include_directories(salvage_config_smoke PRIVATE + ${CMAKE_SOURCE_DIR}/include +) + +add_custom_target(run_salvage_config_smoke ALL + COMMAND $ + DEPENDS salvage_config_smoke + COMMENT "Running salvage config smoke helper" + VERBATIM +) diff --git a/tests/salvage/salvage_config_smoke.c b/tests/salvage/salvage_config_smoke.c new file mode 100644 index 0000000..88fc4ff --- /dev/null +++ b/tests/salvage/salvage_config_smoke.c @@ -0,0 +1,61 @@ +/* Smoke test for the initial nwsalvage configuration helpers. */ +#include "nwsalvage.h" + +#include +#include + +static int expect_true(int condition, const char *message) +{ + if (!condition) { + fprintf(stderr, "FAIL: %s\n", message); + return(1); + } + return(0); +} + +int main(void) +{ + struct nwsalvage_config config; + int failures = 0; + + failures += expect_true(nwsalvage_config_defaults(&config) == 0, + "defaults are accepted"); + failures += expect_true(config.enabled == 1, + "salvage defaults to enabled"); + failures += expect_true(!strcmp(config.recycle_repository, ".recycle"), + "default recycle repository name"); + failures += expect_true(!strcmp(config.metadata_repository, ".salvage"), + "default metadata repository name"); + + failures += expect_true(nwsalvage_config_parse_repositories( + &config, " .recycle .salvage ") == 0, + "section 49 default line parses"); + failures += expect_true(!strcmp(config.recycle_repository, ".recycle"), + "parsed recycle repository name"); + failures += expect_true(!strcmp(config.metadata_repository, ".salvage"), + "parsed metadata repository name"); + + failures += expect_true(nwsalvage_config_parse_repositories( + &config, "recycle salvage") == 0, + "custom repository names parse"); + failures += expect_true(!strcmp(config.recycle_repository, "recycle"), + "custom recycle repository name"); + failures += expect_true(!strcmp(config.metadata_repository, "salvage"), + "custom metadata repository name"); + + failures += expect_true(nwsalvage_config_parse_repositories( + &config, "bad/name .salvage") < 0, + "repository names reject slash components"); + failures += expect_true(nwsalvage_config_parse_repositories( + &config, ".recycle") < 0, + "repository line requires two names"); + failures += expect_true(nwsalvage_config_parse_repositories( + &config, ".recycle .salvage extra") < 0, + "repository line rejects extra tokens"); + + if (failures) + return(1); + + puts("salvage config smoke passed"); + return(0); +}