[Exim] Better maildir++ support

Top Page
Delete this message
Reply to this message
Author: michael
Date:  
To: exim-users
Subject: [Exim] Better maildir++ support
A while ago, I mailed some patches that speed up maildir quota calculation
by encoding the (approximate) message size in the file name like maildir++
does. Now I added support for maildir++ folders. Such a folder is a
maildir with the empty file maildirfolder additionally to cur/new/tmp
in it, which tells the MTA to calculate quotas for the parent directory.

Things look like this:

Maildir
Maildir/.folder
Maildir/.folder/maildirfolder
Maildir/.folder/cur
Maildir/.folder/new
Maildir/.folder/tmp
Maildir/cur
Maildir/new
Maildir/tmp

Obviously, when mails are delivered to Maildir/.folder, quota must
be checked for Maildir including all subdirectories. If anybody is
interested, here are the diffs against Exim 3.12.

There has been a discussion if the quota patch should be applied, because
someone with a shell account could lie to Exim by changing file names.
But then again, if you use shell accounts, you probably need file system
quota anyway. If someone thinks different, an option to enable this
speedup might be useful.

Any opinions against the maildirfolder patch?

Michael
----------------------------------------------------------------------
--- src/transports/appendfile.c.orig    Mon Dec 13 15:51:39 1999
+++ src/transports/appendfile.c    Mon Jan  3 15:55:53 2000
@@ -614,7 +614,7 @@
 */


static int
-check_dir_size(char *dirname, int *countptr)
+check_folder_size(char *dirname, int *countptr)
{
DIR *dir;
int sum = 0;
@@ -629,21 +629,32 @@
{
char *name = ent->d_name;
char buffer[1024];
+ char *sizeptr;

if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;

count++;

+  if ((sizeptr=strstr(name,",S="))!=(char*)0 && *(sizeptr+3)>='0' && *(sizeptr+3)<='9')
+    {
+      int size=0;
+
+      sizeptr+=3;
+      while (*sizeptr>='0' && *sizeptr<='9') size=size*10+(*sizeptr++-'0');
+      sum += size;
+    }
+  else
+    {
   if (!string_format(buffer, sizeof(buffer), "%s/%s", dirname, name))
     {
-    log_write(0, LOG_PANIC|LOG_MAIN, "name too long in check_dir_size: "
+    log_write(0, LOG_PANIC|LOG_MAIN, "name too long in check_folder_size: "
       "dir=%s name=%s", dirname, name);
     continue;
     }


   if (stat(buffer, &statbuf) < 0)
     {
-    DEBUG(9) debug_printf("check_dir_size: stat error %d for %s: %s\n",
+    DEBUG(9) debug_printf("check_folder_size: stat error %d for %s: %s\n",
       errno, buffer, strerror(errno));
     continue;
     }
@@ -651,18 +662,47 @@
   if ((statbuf.st_mode & S_IFREG) != 0)
     sum += statbuf.st_size;
   else if ((statbuf.st_mode & S_IFDIR) != 0)
-    sum += check_dir_size(buffer, &count);
+    sum += check_folder_size(buffer, &count);
+    }
   }


closedir(dir);
-DEBUG(9) debug_printf("check_dir_size: dir=%s sum=%d count=%d\n", dirname, sum,
+DEBUG(9) debug_printf("check_folder_size: dir=%s sum=%d count=%d\n", dirname, sum,
count);
*countptr = count;
return sum;
}


+static int
+check_dir_size(char *dirname, int *countptr)
+{
+char buf[1024];
+struct stat statbuf;
+
+if (!string_format(buf, sizeof(buf), "%s/maildirfolder", dirname))
+  {
+  log_write(0, LOG_PANIC|LOG_MAIN, "name too long in check_dir_size: "
+    "dir=%s", dirname);
+  return 0;
+  }
+
+if (stat(buf, &statbuf) < 0)
+  return check_folder_size(dirname, countptr);
+else
+  {
+  char *slash;


+  if (!string_format(buf, sizeof(buf), "%s", dirname))
+    {
+    log_write(0, LOG_PANIC|LOG_MAIN, "name too long in check_dir_size: "
+      "dir=%s", dirname);
+    return 0;
+    }
+  if ((slash=strrchr(buf,'/'))!=(char*)0) *slash='\0';
+  return check_folder_size(buf, countptr);
+  }
+}



#ifdef SUPPORT_MBX
@@ -1992,8 +2032,8 @@

   for (i = 1;; i++)
     {
-    char *basename = string_sprintf("%lu.%lu.%s%s", time(NULL), getpid(),
-      primary_hostname, tag);
+    char *basename = string_sprintf("%lu.%lu.%s,S=%d%s", time(NULL), getpid(),
+      primary_hostname, message_size, tag);


     filename = dataname = string_sprintf("tmp/%s", basename);
     newname = string_sprintf("new/%s", basename);