Appendfile: release regex-match store every thousand files. Bug 3047
[exim.git] / src / src / transports / appendfile.c
index 43fe883f6a064ecedcac290a70d99038f0d3100b..91b35307901e5eba28d6f9cf3dcfb735947d22fb 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim maintainers 2020 - 2023 */
 /* Copyright (c) University of Cambridge 1995 - 2020 */
-/* Copyright (c) The Exim maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 
 #include "../exim.h"
@@ -152,6 +153,10 @@ static const char *mailbox_formats[] = {
   (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
 
 
+/* Free memory allocated by PCRE2 every so often, because a recent version
+is now using 20kB for every match call */
+
+#define RESET_STORE_FILECNT    1000
 
 /*************************************************
 *              Setup entry point                 *
@@ -501,7 +506,7 @@ Returns:     nothing
 */
 
 static void
-notify_comsat(uschar *user, off_t offset)
+notify_comsat(const uschar * user, off_t offset)
 {
 struct servent *sp;
 host_item host;
@@ -660,13 +665,14 @@ Returns:        the sum of the sizes of the stattable files
 off_t
 check_dir_size(const uschar * dirname, int * countptr, const pcre2_code * re)
 {
-DIR *dir;
+DIR * dir;
 off_t sum = 0;
-int count = *countptr;
+int count = *countptr, lcount = RESET_STORE_FILECNT;
+rmark reset_point = store_mark();
 
 if (!(dir = exim_opendir(dirname))) return 0;
 
-for (struct dirent *ent; ent = readdir(dir); )
+for (struct dirent * ent; ent = readdir(dir); )
   {
   uschar * path, * name = US ent->d_name;
   struct stat statbuf;
@@ -674,6 +680,11 @@ for (struct dirent *ent; ent = readdir(dir); )
   if (Ustrcmp(name, ".") == 0 || Ustrcmp(name, "..") == 0) continue;
 
   count++;
+  if (--lcount == 0)
+    {
+    store_reset(reset_point); reset_point = store_mark();
+    lcount = RESET_STORE_FILECNT;
+    }
 
   /* If there's a regex, try to find the size using it */
 
@@ -681,7 +692,7 @@ for (struct dirent *ent; ent = readdir(dir); )
     {
     pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
     int rc = pcre2_match(re, (PCRE2_SPTR)name, PCRE2_ZERO_TERMINATED,
-                         0, 0, md, pcre_mtc_ctx);
+                         0, 0, md, pcre_gen_mtc_ctx);
     PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
     if (  rc >= 0
        && (rc = pcre2_get_ovector_count(md)) >= 2)
@@ -694,9 +705,11 @@ for (struct dirent *ent; ent = readdir(dir); )
         DEBUG(D_transport)
           debug_printf("check_dir_size: size from %s is " OFF_T_FMT "\n", name,
             size);
+       /* pcre2_match_data_free(md);   gen ctx needs no free */
         continue;
         }
       }
+    /* pcre2_match_data_free(md);      gen ctx needs no free */
     DEBUG(D_transport)
       debug_printf("check_dir_size: regex did not match %s\n", name);
     }
@@ -723,6 +736,7 @@ DEBUG(D_transport)
   debug_printf("check_dir_size: dir=%s sum=" OFF_T_FMT " count=%d\n", dirname,
     sum, count);
 
+store_reset(reset_point);
 *countptr = count;
 return sum;
 }
@@ -1347,7 +1361,7 @@ if (!isdirectory)
     if (is_tainted(path))
       {
       DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
-      path = string_copy_taint(path, FALSE);
+      path = string_copy_taint(path, GET_UNTAINTED);
       }
 
   if (is_tainted(path)) goto tainted_ret_panic;
@@ -2186,7 +2200,7 @@ else
     if (ob->create_file == create_belowhome)
       {
       DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
-      path = string_copy_taint(path, FALSE);
+      path = string_copy_taint(path, GET_UNTAINTED);
       }
     else
       goto tainted_ret_panic;
@@ -2211,23 +2225,14 @@ else
 
   if (ob->quota_value > 0 || THRESHOLD_CHECK || ob->maildir_use_size_file)
     {
-    PCRE2_SIZE offset;
-    int err;
-
     /* Compile the regex if there is one. */
 
     if (ob->quota_size_regex)
       {
-      if (!(re = pcre2_compile((PCRE2_SPTR)ob->quota_size_regex,
-                 PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
-        {
-       uschar errbuf[128];
-       pcre2_get_error_message(err, errbuf, sizeof(errbuf));
-        addr->message = string_sprintf("appendfile: regular expression "
-          "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
-          ob->quota_size_regex);
+      if (!(re = regex_compile(ob->quota_size_regex,
+                 MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx)))
         return FALSE;
-        }
+
       DEBUG(D_transport) debug_printf("using regex for file sizes: %s\n",
         ob->quota_size_regex);
       }
@@ -2300,23 +2305,14 @@ else
   if (ob->maildir_use_size_file)
     {
     const pcre2_code * dir_regex = NULL;
-    PCRE2_SIZE offset;
-    int err;
 
     if (ob->maildir_dir_regex)
       {
       int check_path_len = Ustrlen(check_path);
 
-      if (!(dir_regex = pcre2_compile((PCRE2_SPTR)ob->maildir_dir_regex,
-           PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
-        {
-       uschar errbuf[128];
-       pcre2_get_error_message(err, errbuf, sizeof(errbuf));
-        addr->message = string_sprintf("appendfile: regular expression "
-          "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
-          ob->maildir_dir_regex);
+      if (!(dir_regex = regex_compile(ob->maildir_dir_regex,
+           MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx)))
         return FALSE;
-        }
 
       DEBUG(D_transport)
         debug_printf("using regex for maildir directory selection: %s\n",
@@ -2527,9 +2523,9 @@ else
 
   else
     {
-    FILE *env_file;
+    FILE * env_file;
     mailstore_basename = string_sprintf("%s/%s-%s", path, message_id,
-      string_base62((long int)getpid()));
+      string_base62_64((long int)getpid()));
 
     DEBUG(D_transport)
       debug_printf("delivering in mailstore format in %s\n", path);