maildirquota.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:12k
- /*
- ** Copyright 1998 - 2000 Double Precision, Inc.
- ** See COPYING for distribution information.
- */
- #if HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include <sys/types.h>
- #if HAVE_DIRENT_H
- #include <dirent.h>
- #define NAMLEN(dirent) strlen((dirent)->d_name)
- #else
- #define dirent direct
- #define NAMLEN(dirent) (dirent)->d_namlen
- #if HAVE_SYS_NDIR_H
- #include <sys/ndir.h>
- #endif
- #if HAVE_SYS_DIR_H
- #include <sys/dir.h>
- #endif
- #if HAVE_NDIR_H
- #include <ndir.h>
- #endif
- #endif
- #include <sys/types.h>
- #if HAVE_SYS_STAT_H
- #include <sys/stat.h>
- #endif
- #include <sys/uio.h>
- #include "maildirquota.h"
- #include "maildirmisc.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #if HAVE_FCNTL_H
- #include <fcntl.h>
- #endif
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <time.h>
- #include <numlib/numlib.h>
- static const char rcsid[]="$Id: maildirquota.c,v 1.3 2000/05/24 03:42:00 mrsam Exp $";
- /* Read the maildirsize file */
- static int maildirsize_read(const char *filename, /* The filename */
- int *fdptr, /* Keep the file descriptor open */
- off_t *sizeptr, /* Grand total of maildir size */
- unsigned *cntptr, /* Grand total of message count */
- unsigned *nlines, /* # of lines in maildirsize */
- struct stat *statptr) /* The stats on maildirsize */
- {
- char buf[5120];
- int f;
- char *p;
- unsigned l;
- int n;
- int first;
- if ((f=maildir_safeopen(filename, O_RDWR|O_APPEND, 0)) < 0)
- return (-1);
- p=buf;
- l=sizeof(buf);
- while (l)
- {
- n=read(f, p, l);
- if (n < 0)
- {
- close(f);
- return (-1);
- }
- if (n == 0) break;
- p += n;
- l -= n;
- }
- if (l == 0 || fstat(f, statptr)) /* maildir too big */
- {
- close(f);
- return (-1);
- }
- *sizeptr=0;
- *cntptr=0;
- *nlines=0;
- *p=0;
- p=buf;
- first=1;
- while (*p)
- {
- long n=0;
- int c=0;
- char *q=p;
- while (*p)
- if (*p++ == 'n')
- {
- p[-1]=0;
- break;
- }
- if (first)
- {
- first=0;
- continue;
- }
- sscanf(q, "%ld %d", &n, &c);
- *sizeptr += n;
- *cntptr += c;
- ++ *nlines;
- }
- *fdptr=f;
- return (0);
- }
- static char *makenewmaildirsizename(const char *, int *);
- static int countcurnew(const char *, time_t *, off_t *, unsigned *);
- static int countsubdir(const char *, const char *,
- time_t *, off_t *, unsigned *);
- static int statcurnew(const char *, time_t *);
- static int statsubdir(const char *, const char *, time_t *);
- #define MDQUOTA_SIZE 'S' /* Total size of all messages in maildir */
- #define MDQUOTA_BLOCKS 'B' /* Total # of blocks for all messages in
- maildir -- NOT IMPLEMENTED */
- #define MDQUOTA_COUNT 'C' /* Total number of messages in maildir */
- static int qcalc(off_t s, unsigned n, const char *quota)
- {
- unsigned long i;
- errno=ENOSPC;
- while (quota && *quota)
- {
- if (*quota < '0' || *quota > '9')
- {
- ++quota;
- continue;
- }
- i=0;
- while (*quota >= '0' && *quota <= '9')
- i=i*10 + (*quota++ - '0');
- switch (*quota) {
- default:
- if (i < s) return (-1);
- break;
- case 'C':
- if (i < n) return (-1);
- break;
- }
- }
- return (0);
- }
- static int doaddquota(const char *, int, const char *, long, int, int);
- int maildir_checkquota(const char *dir,
- int *maildirsize_fdptr,
- const char *quota_type,
- long xtra_size,
- int xtra_cnt)
- {
- char *checkfolder=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));
- char *newmaildirsizename;
- struct stat stat_buf;
- int maildirsize_fd;
- off_t maildirsize_size;
- unsigned maildirsize_cnt;
- unsigned maildirsize_nlines;
- int n;
- time_t tm;
- time_t maxtime;
- DIR *dirp;
- struct dirent *de;
- if (checkfolder == 0) return (-1);
- *maildirsize_fdptr= -1;
- strcat(strcpy(checkfolder, dir), "/maildirfolder");
- if (stat(checkfolder, &stat_buf) == 0) /* Go to parent */
- {
- strcat(strcpy(checkfolder, dir), "/..");
- n=maildir_checkquota(checkfolder, maildirsize_fdptr,
- quota_type, xtra_size, xtra_cnt);
- free(checkfolder);
- return (n);
- }
- if (!quota_type || !*quota_type) return (0);
- strcat(strcpy(checkfolder, dir), "/maildirsize");
- time(&tm);
- if (maildirsize_read(checkfolder, &maildirsize_fd,
- &maildirsize_size, &maildirsize_cnt,
- &maildirsize_nlines, &stat_buf) == 0)
- {
- n=qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt,
- quota_type);
- if (n == 0)
- {
- free(checkfolder);
- *maildirsize_fdptr=maildirsize_fd;
- return (0);
- }
- close(maildirsize_fd);
- if (maildirsize_nlines == 1 && tm < stat_buf.st_mtime + 15*60)
- return (n);
- }
- maxtime=0;
- maildirsize_size=0;
- maildirsize_cnt=0;
- if (countcurnew(dir, &maxtime, &maildirsize_size, &maildirsize_cnt))
- {
- free(checkfolder);
- return (-1);
- }
- dirp=opendir(dir);
- while (dirp && (de=readdir(dirp)) != 0)
- {
- if (countsubdir(dir, de->d_name, &maxtime, &maildirsize_size,
- &maildirsize_cnt))
- {
- free(checkfolder);
- closedir(dirp);
- return (-1);
- }
- }
- if (dirp)
- {
- #if CLOSEDIR_VOID
- closedir(dirp);
- #else
- if (closedir(dirp))
- {
- free(checkfolder);
- return (-1);
- }
- #endif
- }
- newmaildirsizename=makenewmaildirsizename(dir, &maildirsize_fd);
- if (!newmaildirsizename)
- {
- free(checkfolder);
- return (-1);
- }
- *maildirsize_fdptr=maildirsize_fd;
- if (doaddquota(dir, maildirsize_fd, quota_type, maildirsize_size,
- maildirsize_cnt, 1))
- {
- free(newmaildirsizename);
- unlink(newmaildirsizename);
- close(maildirsize_fd);
- *maildirsize_fdptr= -1;
- free(checkfolder);
- return (-1);
- }
- strcat(strcpy(checkfolder, dir), "/maildirsize");
- if (rename(newmaildirsizename, checkfolder))
- {
- free(checkfolder);
- unlink(newmaildirsizename);
- close(maildirsize_fd);
- *maildirsize_fdptr= -1;
- }
- free(checkfolder);
- free(newmaildirsizename);
- tm=0;
- if (statcurnew(dir, &tm))
- {
- close(maildirsize_fd);
- *maildirsize_fdptr= -1;
- return (-1);
- }
- dirp=opendir(dir);
- while (dirp && (de=readdir(dirp)) != 0)
- {
- if (statsubdir(dir, de->d_name, &tm))
- {
- close(maildirsize_fd);
- *maildirsize_fdptr= -1;
- closedir(dirp);
- return (-1);
- }
- }
- if (dirp)
- {
- #if CLOSEDIR_VOID
- closedir(dirp);
- #else
- if (closedir(dirp))
- {
- close(maildirsize_fd);
- *maildirsize_fdptr= -1;
- return (-1);
- }
- #endif
- }
- if (tm != maxtime) /* Race condition, someone changed something */
- {
- errno=EAGAIN;
- return (-1);
- }
- return (qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt,
- quota_type));
- }
- int maildir_addquota(const char *dir, int maildirsize_fd,
- const char *quota_type, long maildirsize_size, int maildirsize_cnt)
- {
- if (!quota_type || !*quota_type) return (0);
- return (doaddquota(dir, maildirsize_fd, quota_type, maildirsize_size,
- maildirsize_cnt, 0));
- }
- static int doaddquota(const char *dir, int maildirsize_fd,
- const char *quota_type, long maildirsize_size, int maildirsize_cnt,
- int isnew)
- {
- union {
- char buf[100];
- struct stat stat_buf;
- } u; /* Scrooge */
- char *newname2=0;
- char *newmaildirsizename=0;
- struct iovec iov[3];
- int niov;
- struct iovec *p;
- int n;
- niov=0;
- if ( maildirsize_fd < 0)
- {
- newname2=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));
- if (!newname2) return (-1);
- strcat(strcpy(newname2, dir), "/maildirfolder");
- if (stat(newname2, &u.stat_buf) == 0)
- {
- strcat(strcpy(newname2, dir), "/..");
- n=doaddquota(newname2, maildirsize_fd, quota_type,
- maildirsize_size, maildirsize_cnt,
- isnew);
- free(newname2);
- return (n);
- }
- strcat(strcpy(newname2, dir), "/maildirsize");
- if ((maildirsize_fd=maildir_safeopen(newname2,
- O_RDWR|O_APPEND, 0644)) < 0)
- {
- newmaildirsizename=makenewmaildirsizename(dir, &maildirsize_fd);
- if (!newmaildirsizename)
- {
- free(newname2);
- return (-1);
- }
- maildirsize_fd=maildir_safeopen(newmaildirsizename,
- O_CREAT|O_RDWR|O_APPEND, 0644);
- if (maildirsize_fd < 0)
- {
- free(newname2);
- return (-1);
- }
- isnew=1;
- }
- }
- if (isnew)
- {
- iov[0].iov_base=(caddr_t)quota_type;
- iov[0].iov_len=strlen(quota_type);
- iov[1].iov_base=(caddr_t)"n";
- iov[1].iov_len=1;
- niov=2;
- }
- sprintf(u.buf, "%ld %dn", maildirsize_size, maildirsize_cnt);
- iov[niov].iov_base=(caddr_t)u.buf;
- iov[niov].iov_len=strlen(u.buf);
- p=iov;
- ++niov;
- n=0;
- while (niov)
- {
- if (n)
- {
- if (n < p->iov_len)
- {
- p->iov_base=
- (caddr_t)((char *)p->iov_base + n);
- p->iov_len -= n;
- }
- else
- {
- n -= p->iov_len;
- ++p;
- --niov;
- continue;
- }
- }
- n=writev( maildirsize_fd, p, niov);
- if (n <= 0)
- {
- if (newname2)
- {
- close(maildirsize_fd);
- free(newname2);
- }
- return (-1);
- }
- }
- if (newname2)
- {
- close(maildirsize_fd);
- if (newmaildirsizename)
- {
- rename(newmaildirsizename, newname2);
- free(newmaildirsizename);
- }
- free(newname2);
- }
- return (0);
- }
- /* New maildirsize is built in the tmp subdirectory */
- static char *makenewmaildirsizename(const char *dir, int *fd)
- {
- char hostname[256];
- struct stat stat_buf;
- time_t t;
- char *p;
- hostname[0]=0;
- hostname[sizeof(hostname)-1]=0;
- gethostname(hostname, sizeof(hostname)-1);
- p=(char *)malloc(strlen(dir)+strlen(hostname)+130);
- if (!p) return (0);
- for (;;)
- {
- char tbuf[NUMBUFSIZE];
- char pbuf[NUMBUFSIZE];
- time(&t);
- strcat(strcpy(p, dir), "/tmp/");
- sprintf(p+strlen(p), "%s.%s_NeWmAiLdIrSiZe.%s",
- str_time_t(t, tbuf),
- str_pid_t(getpid(), pbuf), hostname);
- if (stat( (const char *)p, &stat_buf) < 0 &&
- (*fd=maildir_safeopen(p,
- O_CREAT|O_RDWR|O_APPEND, 0644)) >= 0)
- break;
- sleep(3);
- }
- return (p);
- }
- static int statcurnew(const char *dir, time_t *maxtimestamp)
- {
- char *p=(char *)malloc(strlen(dir)+5);
- struct stat stat_buf;
- if (!p) return (-1);
- strcat(strcpy(p, dir), "/cur");
- if ( stat(p, &stat_buf) == 0 && stat_buf.st_mtime > *maxtimestamp)
- *maxtimestamp=stat_buf.st_mtime;
- strcat(strcpy(p, dir), "/new");
- if ( stat(p, &stat_buf) == 0 && stat_buf.st_mtime > *maxtimestamp)
- *maxtimestamp=stat_buf.st_mtime;
- free(p);
- return (0);
- }
- static int statsubdir(const char *dir, const char *subdir, time_t *maxtime)
- {
- char *p;
- int n;
- if ( *subdir != '.' || strcmp(subdir, ".") == 0 ||
- strcmp(subdir, "..") == 0 || strcmp(subdir, ".Trash") == 0)
- return (0);
- p=(char *)malloc(strlen(dir)+strlen(subdir)+2);
- if (!p) return (-1);
- strcat(strcat(strcpy(p, dir), "/"), subdir);
- n=statcurnew(p, maxtime);
- free(p);
- return (n);
- }
- static int docount(const char *, time_t *, off_t *, unsigned *);
- static int countcurnew(const char *dir, time_t *maxtime,
- off_t *sizep, unsigned *cntp)
- {
- char *p=(char *)malloc(strlen(dir)+5);
- int n;
- if (!p) return (-1);
- strcat(strcpy(p, dir), "/new");
- n=docount(p, maxtime, sizep, cntp);
- if (n == 0)
- {
- strcat(strcpy(p, dir), "/cur");
- n=docount(p, maxtime, sizep, cntp);
- }
- free(p);
- return (n);
- }
- static int countsubdir(const char *dir, const char *subdir, time_t *maxtime,
- off_t *sizep, unsigned *cntp)
- {
- char *p;
- int n;
- if ( *subdir != '.' || strcmp(subdir, ".") == 0 ||
- strcmp(subdir, "..") == 0 || strcmp(subdir, ".Trash") == 0)
- return (0);
- p=(char *)malloc(strlen(dir)+strlen(subdir)+2);
- if (!p) return (2);
- strcat(strcat(strcpy(p, dir), "/"), subdir);
- n=countcurnew(p, maxtime, sizep, cntp);
- free(p);
- return (n);
- }
- static int docount(const char *dir, time_t *dirstamp,
- off_t *sizep, unsigned *cntp)
- {
- struct stat stat_buf;
- char *p;
- DIR *dirp;
- struct dirent *de;
- unsigned long s;
- if (stat(dir, &stat_buf)) return (0); /* Ignore */
- if (stat_buf.st_mtime > *dirstamp) *dirstamp=stat_buf.st_mtime;
- if ((dirp=opendir(dir)) == 0) return (0);
- while ((de=readdir(dirp)) != 0)
- {
- const char *n=de->d_name;
- if (*n == '.') continue;
- /* PATCH - do not count msgs marked as deleted */
- for ( ; *n; n++)
- {
- if (n[0] != ':' || n[1] != '2' ||
- n[2] != ',') continue;
- n += 3;
- while (*n >= 'A' && *n <= 'Z')
- {
- if (*n == 'T') break;
- ++n;
- }
- break;
- }
- if (*n == 'T') continue;
- n=de->d_name;
- if (maildir_parsequota(n, &s) == 0)
- stat_buf.st_size=s;
- else
- {
- p=(char *)malloc(strlen(dir)+strlen(n)+2);
- if (!p)
- {
- closedir(dirp);
- return (-1);
- }
- strcat(strcat(strcpy(p, dir), "/"), n);
- if (stat(p, &stat_buf))
- {
- free(p);
- continue;
- }
- free(p);
- }
- *sizep += stat_buf.st_size;
- ++*cntp;
- }
- #if CLOSEDIR_VOID
- closedir(dirp);
- #else
- if (closedir(dirp))
- return (-1);
- #endif
- return (0);
- }