From: ethan-thompson Date: Fri, 6 Feb 2026 18:35:12 +0000 (+0000) Subject: feature: Added mkdir and rmdir xlats and updated docs and tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a1c403d7edef0c9ce7841b8baf7401141db466a1;p=thirdparty%2Ffreeradius-server.git feature: Added mkdir and rmdir xlats and updated docs and tests Signed-off-by: ethan-thompson --- diff --git a/doc/antora/modules/reference/pages/xlat/file/mkdir.adoc b/doc/antora/modules/reference/pages/xlat/file/mkdir.adoc new file mode 100644 index 00000000000..1bda63d8f4b --- /dev/null +++ b/doc/antora/modules/reference/pages/xlat/file/mkdir.adoc @@ -0,0 +1,21 @@ += mkdir + +The `mkdir` function creates directories and subdirectories. If the directory exists or was created successfully, it returns `true`. Otherwise if it could not be created, it returns `false. + +[#syntax] +== Syntax + +`%file.mkdir(_string_)` + +.Return: _bool_ + +.Create a directory +==== +[source,unlang] +---- +%file.mkdir("/var/log/radius/auth") +---- +==== + +// Copyright (C) 2026 Network RADIUS SAS. Licenced under CC-by-NC 4.0. +// This documentation was developed by Network RADIUS SAS. diff --git a/doc/antora/modules/reference/pages/xlat/file/rmdir.adoc b/doc/antora/modules/reference/pages/xlat/file/rmdir.adoc new file mode 100644 index 00000000000..8b837747ae7 --- /dev/null +++ b/doc/antora/modules/reference/pages/xlat/file/rmdir.adoc @@ -0,0 +1,21 @@ += rmdir + +The `rmdir` function removes a directory. If the directory exists and could be removed, it returns `true`. Otherwise if the directory does not exist, or if the directory could not be removed, it returns `false. + +[#syntax] +== Syntax + +`%file.rmdir(_string_)` + +.Return: _bool_ + +.Removing a directory +==== +[source,unlang] +---- +%file.rmdir("/var/log/radius/auth") +---- +==== + +// Copyright (C) 2026 Network RADIUS SAS. Licenced under CC-by-NC 4.0. +// This documentation was developed by Network RADIUS SAS. diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index ecc89338943..5c4893883c1 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -844,6 +844,48 @@ static xlat_action_t xlat_func_file_touch(TALLOC_CTX *ctx, fr_dcursor_t *out, UN return XLAT_ACTION_DONE; } +static xlat_action_t xlat_func_file_mkdir(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, + request_t *request, fr_value_box_list_t *args) +{ + fr_value_box_t *dst, *vb; + char const *dirname; + + XLAT_ARGS(args, &vb); + fr_assert(vb->type == FR_TYPE_STRING); + dirname = vb->vb_strvalue; + + MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL)); + fr_dcursor_append(out, dst); + + dst->vb_bool = (fr_mkdir(NULL, dirname, -1, 0700, NULL, NULL) == 0); + if (!dst->vb_bool) { + REDEBUG3("Failed creating directory %s - %s", dirname, fr_syserror(errno)); + } + + return XLAT_ACTION_DONE; +} + +static xlat_action_t xlat_func_file_rmdir(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, + request_t *request, fr_value_box_list_t *args) +{ + fr_value_box_t *dst, *vb; + char const *dirname; + + XLAT_ARGS(args, &vb); + fr_assert(vb->type == FR_TYPE_STRING); + dirname = vb->vb_strvalue; + + MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL)); + fr_dcursor_append(out, dst); + + dst->vb_bool = (rmdir(dirname) == 0); + if (!dst->vb_bool) { + REDEBUG3("Failed removing directory %s - %s", dirname, fr_syserror(errno)); + } + + return XLAT_ACTION_DONE; +} + static xlat_arg_parser_t const xlat_func_taint_args[] = { { .required = true, .type = FR_TYPE_VOID }, { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID }, @@ -4759,6 +4801,8 @@ do { \ XLAT_REGISTER_ARGS("file.size", xlat_func_file_size, FR_TYPE_UINT64, xlat_func_file_name_args); XLAT_REGISTER_ARGS("file.tail", xlat_func_file_tail, FR_TYPE_STRING, xlat_func_file_name_count_args); XLAT_REGISTER_ARGS("file.cat", xlat_func_file_cat, FR_TYPE_OCTETS, xlat_func_file_cat_args); + XLAT_REGISTER_ARGS("file.mkdir", xlat_func_file_mkdir, FR_TYPE_BOOL, xlat_func_file_name_args); + XLAT_REGISTER_ARGS("file.rmdir", xlat_func_file_rmdir, FR_TYPE_BOOL, xlat_func_file_name_args); XLAT_REGISTER_ARGS("immutable", xlat_func_immutable_attr, FR_TYPE_NULL, xlat_pair_cursor_args); XLAT_NEW("pairs.immutable"); diff --git a/src/tests/xlat/file.txt b/src/tests/xlat/file.txt index cd7e54f8e2b..99b2778bfe0 100644 --- a/src/tests/xlat/file.txt +++ b/src/tests/xlat/file.txt @@ -37,6 +37,23 @@ match no xlat_expr "foo/bar/" + %file.escape(%taint('..baz')) match foo/bar/_x2e_x2ebaz +xlat_expr %file.mkdir('src/tests/xlat/file/new-dir') +xlat_expr %file.exists('src/tests/xlat/file/new-dir') +match yes + +xlat_expr %file.rmdir('src/tests/xlat/file/new-dir') +xlat_expr %file.exists('src/tests/xlat/file/new-dir') +match no + +xlat_expr %file.mkdir('src/tests/xlat/file/nested/dir') +xlat_expr %file.exists('src/tests/xlat/file/nested/dir') +match yes + +xlat_expr %file.rmdir('src/tests/xlat/file/nested/dir') +xlat_expr %file.rmdir('src/tests/xlat/file/nested') +xlat_expr %file.exists('src/tests/xlat/file/nested/dir') +match no + # # Can now do expressions as function arguments #