Commit ee5b4d786 for clamav.net

commit ee5b4d786705fd462900c0d4fb47d1607c3a8293
Author: Val S. <mx.val@icloud.com>
Date:   Thu Nov 13 16:35:08 2025 -0500

    Windows: Fix issue creating new temp subdirectory

    On Windows, when scanning some files with `--leave-temps` enabled and
    with `--tempdir` set to something like `C:\temp`, it may fail to create
    a new subdirectory to store the temp files because the absolute file
    path is too long for the `mkdir()` function.

    The `mkdir()` function may fail on Windows if the filepath is longer than
    the legacy MAX_PATH.
    Fixing this in C or C++ is rather difficult, requiring either a registry
    key + application manifest change, or else converting the path to UTF16
    and UNC format (i.e. `"\\?\C:\temp"`) to pass to `CreateDirectoryW()`.

    The solution in this commit is to use the Rust `std` library instead. It
    is able to handle the longer file paths without issue.

    CLAM-2924

diff --git a/libclamav/others.c b/libclamav/others.c
index ee3cf32eb..d191ae25f 100644
--- a/libclamav/others.c
+++ b/libclamav/others.c
@@ -1771,6 +1771,10 @@ cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t typ
     char *new_temp_path = NULL;
     char *fmap_basename = NULL;

+#ifdef _WIN32
+    FFIError *mkdir_w32_error = NULL;
+#endif
+
     old_recursion_level = ctx->recursion_level;

     // Check the regular limits
@@ -1869,11 +1873,21 @@ cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t typ
             }
         }

+#ifdef _WIN32
+
+        if (!mkdir_w32(new_temp_path, &mkdir_w32_error)) {
+            cli_errmsg("cli_magic_scan: Can't create tmp sub-directory (%s) for scan. Error: %s\n", new_temp_path, ffierror_fmt(mkdir_w32_error));
+            ffierror_free(mkdir_w32_error);
+            status = CL_EACCES;
+            goto done;
+        }
+#else
         if (mkdir(new_temp_path, 0700)) {
-            cli_errmsg("cli_magic_scan: Can't create tmp sub-directory for scan: %s.\n", new_temp_path);
+            cli_errmsg("cli_magic_scan: Can't create tmp sub-directory (%s) for scan. Error: %s\n", new_temp_path, strerror(errno));
             status = CL_EACCES;
             goto done;
         }
+#endif

         ctx->recursion_stack[ctx->recursion_level].tmpdir = new_temp_path;
         ctx->this_layer_tmpdir                            = new_temp_path;
diff --git a/libclamav_rust/cbindgen.toml b/libclamav_rust/cbindgen.toml
index d404dc84a..52d4f4e35 100644
--- a/libclamav_rust/cbindgen.toml
+++ b/libclamav_rust/cbindgen.toml
@@ -59,6 +59,7 @@ include = [
   "scanners::scan_onenote",
   "scanners::cli_scanalz",
   "util::glob_rm",
+  "util::mkdir_w32",
 ]

 # prefix = "CAPI_"
diff --git a/libclamav_rust/src/util.rs b/libclamav_rust/src/util.rs
index fdd41b40c..c07793666 100644
--- a/libclamav_rust/src/util.rs
+++ b/libclamav_rust/src/util.rs
@@ -165,3 +165,20 @@ pub unsafe extern "C" fn glob_rm(glob_str: *const c_char, err: *mut *mut FFIErro

     true
 }
+
+/// C interface to create a directory
+///
+/// # Safety
+///
+/// No parameters may be NULL.
+#[export_name = "mkdir_w32"]
+pub unsafe extern "C" fn mkdir_w32(path: *const c_char, err: *mut *mut FFIError) -> bool {
+    let path = validate_str_param!(path);
+
+    if let Err(e) = std::fs::create_dir_all(&path) {
+        warn!("Failed to create directory: {path:?}");
+        return ffi_error!(err = err, Error::IoError(e));
+    }
+
+    true
+}