]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
feature: Added mkdir and rmdir xlats and updated docs and tests
authorethan-thompson <ethan.thompson@networkradius.com>
Fri, 6 Feb 2026 18:35:12 +0000 (18:35 +0000)
committerAlan DeKok <aland@freeradius.org>
Fri, 6 Feb 2026 20:26:27 +0000 (15:26 -0500)
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
doc/antora/modules/reference/pages/xlat/file/mkdir.adoc [new file with mode: 0644]
doc/antora/modules/reference/pages/xlat/file/rmdir.adoc [new file with mode: 0644]
src/lib/unlang/xlat_builtin.c
src/tests/xlat/file.txt

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 (file)
index 0000000..1bda63d
--- /dev/null
@@ -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 (file)
index 0000000..8b83774
--- /dev/null
@@ -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.
index ecc89338943e117705f9bc3020b3ae5e0703b442..5c4893883c1273767a97253fbec87bceb58671c0 100644 (file)
@@ -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");
index cd7e54f8e2bb1fd2c143bde61ba681e21dc5ccd8..99b2778bfe0d84a4483dbb4e96e89d4cf04b0abc 100644 (file)
@@ -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
 #