Hi list

Our admin set up a new mailserver which should provide IMAP to our
coworkers - problem: their current (local) mailboxes are already
scratching the 2GB limit of their mailclients, therefore we needed
higher quotas on the new server to suit the coworkers needs. When
testing his qmail+vpopmail+courier setup there were crazy results when
quota was set to >2GB and even more problems appeared when the maildir
was filled with mails in total of >2GB.

Being a programmer the admin contacted me if i could look at the code.
What i first figured out was that you seem to use 32bit off_t typedefs
for vpopmail. Information about that can be found here:

http://ac-archive.sourceforge.net/largefile/makedefault.html

Next i started to fix the maildirquota.[ch] files which used a mix of
off_t and long for filesize- and quota-calculations to use off_t in
every case. This seems to fix the problems we had with false reports of
"user over quota" and similar stuff. We tested behaviour for a
quota-size of 3GB and mails ranging from 1.5GB to 2.8GB in total, and we
went over quota too of course. Everything went fine.

The patch is attached to this mail, to actually take advantage of the
new code you need to do the following:

$ patch -p1 < vpopmail-maildirquota.patch
$ export CFLAGS=-D_FILE_OFFSET_BITS=64
$ ./configure --your-flags
$ make
...

w/o the CFLAGS off_t will be 32bit and the problems will persist.
Developers of vpopmail may want to include that #define into their
configure.ac file, because then it will appear in config.h and there's
no need for external CFLAGS.

I hope you find this patch useful, it was made against vpopmail-5.3.8

I also patched courier-imap to fix the issues for such high quotas, this
patch went to the courier-imap ML of course. There's discussion about whether to use off_t or not, and string to number conversion issues - please share your thoughts with me about these changes in the vpopmail source (changes are similar for both projects).


Yours
  Mike

p.s.: sscanf is used to read some maildirsize entries - afaik the %lld i
used to read "long long" values is GNU only, this may be a problem for
keeping the code crossplattform. same goes for sprintf statements.

p.p.s.: It would be nice if you mention somewhere on the homepage that the ML is for subscribers only.

--- vpopmail-5.3.8/maildirquota.c       2002-05-18 06:16:29.000000000 +0200
+++ vpopmail-5.3.8_2gbfix/maildirquota.c        2004-05-16 15:49:50.000000000 +0200
@@ -39,11 +39,11 @@
                time_t *, off_t *, unsigned *);
 static int statcurnew(const char *, time_t *);
 static int statsubdir(const char *, const char *, time_t *);
-static int     doaddquota(const char *, int, const char *, long, int, int);
+static int doaddquota(const char *, int, const char *, off_t, int, int);
 static int docheckquota(const char *dir,
        int *maildirsize_fdptr,
        const char *quota_type,
-       long xtra_size,
+       off_t xtra_size,
        int xtra_cnt, int *percentage);
 static int docount(const char *, time_t *, off_t *, unsigned *);
 int deliver_quota_warning(const char *dir);
@@ -103,35 +103,34 @@
 
 char *format_maildirquota(const char *q) {
 int     i;
-int     per_user_limit;
+off_t   per_user_limit;
 static char    tempquota[500];
 
     /* translate the quota to a number, or leave it */
     i = strlen(q) - 1;
     tempquota[0] = '\0'; /* make sure tempquota is 0 length */
     if(strstr(q, ",") == NULL && q[i] != 'S') {
-        per_user_limit = atol(q);
+        per_user_limit = atoll(q);
         for(i=0;q[i]!=0;++i) {
             if ( q[i] == 'k' || q[i] == 'K' ) {
                 per_user_limit = per_user_limit * 1000;
-                snprintf(tempquota, 500, "%dS", per_user_limit);
+                snprintf(tempquota, 500, "%lldS", per_user_limit);
                 break;
             }
             if ( q[i] == 'm' || q[i] == 'M' ) {
                 per_user_limit = per_user_limit * 1000000;
-                sprintf(tempquota, "%dS", per_user_limit);
+                snprintf(tempquota, 500, "%lldS", per_user_limit);
                 break;
             }
         }
 
 
         if(strlen(tempquota) == 0) {
-            sprintf(tempquota, "%sS", q);
+            snprintf(tempquota, 500, "%sS", q);
         }
     } else {
-          sprintf(tempquota, "%s", q);
+          snprintf(tempquota, 500, "%s", q);
     }
-
     return(tempquota);
 }
 
@@ -149,7 +148,7 @@
  int f;
  char *p;
  unsigned l;
- int n;
+ off_t n;
  int first;
 
        if ((f=maildir_safeopen(filename, O_RDWR|O_APPEND, 0)) < 0)
@@ -181,9 +180,10 @@
        *p=0;
        p=buf;
        first=1;
+
        while (*p)
        {
-       long n=0;
+       off_t n=0;
        int c=0;
        char    *q=p;
 
@@ -199,9 +199,11 @@
                        first=0;
                        continue;
                }
-               sscanf(q, "%ld %d", &n, &c);
+               if (sscanf(q, "%lld %d", &n, &c) == 2)
+               {
                *sizeptr += n;
                *cntptr += c;
+               }
                ++ *nlines;
        }
        *fdptr=f;
@@ -271,7 +273,7 @@
 int maildir_checkquota(const char *dir,
        int *maildirsize_fdptr,
        const char *quota_type,
-       long xtra_size,
+       off_t xtra_size,
        int xtra_cnt)
 {
 int    dummy;
@@ -294,7 +296,7 @@
 static int docheckquota(const char *dir,
        int *maildirsize_fdptr,
        const char *quota_type,
-       long xtra_size,
+       off_t xtra_size,
        int xtra_cnt,
        int *percentage)
 {
@@ -456,7 +458,7 @@
 }
 
 int    maildir_addquota(const char *dir, int maildirsize_fd,
-       const char *quota_type, long maildirsize_size, int maildirsize_cnt)
+       const char *quota_type, off_t maildirsize_size, int maildirsize_cnt)
 {
        if (!quota_type || !*quota_type)        return (0);
        return (doaddquota(dir, maildirsize_fd, quota_type, maildirsize_size,
@@ -464,7 +466,7 @@
 }
 
 static int doaddquota(const char *dir, int maildirsize_fd,
-       const char *quota_type, long maildirsize_size, int maildirsize_cnt,
+       const char *quota_type, off_t maildirsize_size, int maildirsize_cnt,
        int isnew)
 {
 union  {
@@ -527,8 +529,7 @@
                niov=2;
        }
 
-
-       sprintf(u.buf, "%ld %d\n", maildirsize_size, maildirsize_cnt);
+       snprintf(u.buf, 100, "%lld %d\n", maildirsize_size, maildirsize_cnt);
        (char *)iov[niov].iov_base=u.buf;
        iov[niov].iov_len=strlen(u.buf);
 
@@ -693,7 +694,7 @@
 char   *p;
 DIR    *dirp;
 struct dirent *de;
-unsigned long  s;
+off_t *s;
 
        if (stat(dir, &stat_buf))       return (0);     /* Ignore */
        if (stat_buf.st_mtime > *dirstamp)      *dirstamp=stat_buf.st_mtime;
@@ -811,7 +812,7 @@
         return (strcpy(arg, p));
 }
 
-int maildir_parsequota(const char *n, unsigned long *s)
+int maildir_parsequota(const char *n, off_t *s)
 {
 const char *o;
 int     yes;
--- vpopmail-5.3.8/maildirquota.h       2002-04-06 16:30:35.000000000 +0200
+++ vpopmail-5.3.8_2gbfix/maildirquota.h        2004-05-15 19:44:19.000000000 +0200
@@ -30,19 +30,19 @@
 int maildir_checkquota(const char *,   /* Pointer to directory */
        int *,  /* Initialized to -1, or opened descriptor for maildirsize */
        const char *,   /* The quota */
-       long,           /* Extra bytes planning to add/remove from maildir */
+       off_t,          /* Extra bytes planning to add/remove from maildir */
        int);           /* Extra messages planning to add/remove from maildir */
 
 int maildir_addquota(const char *,     /* Pointer to the maildir */
        int,    /* Must be the int pointed to by 2nd arg to checkquota */
        const char *,   /* The quota */
-       long,   /* +/- bytes */
+       off_t,  /* +/- bytes */
        int);   /* +/- files */
 
 int maildir_readquota(const char *,    /* Directory */
        const char *);                  /* Quota, from getquota */
 
-int maildir_parsequota(const char *, unsigned long *);
+int maildir_parsequota(const char *, off_t *);
        /* Attempt to parse file size encoded in filename.  Returns 0 if
        ** parsed, non-zero if we didn't parse. */
 

Reply via email to