diff -Naur cyrus-imapd-2.2.12/imap/imapd.c cyrus-imapd-2.2.12.rmquota.uncompiled/imap/imapd.c --- cyrus-imapd-2.2.12/imap/imapd.c 2005-02-14 08:39:55.000000000 +0200 +++ cyrus-imapd-2.2.12.rmquota.uncompiled/imap/imapd.c 2005-03-03 16:08:19.000000000 +0200 @@ -4718,6 +4718,7 @@ { int newquota = -1; int badresource = 0; + int rmquota = 0; int c; int force = 0; static struct buf arg; @@ -4732,7 +4733,8 @@ if (c != ')' || arg.s[0] != '\0') { for (;;) { if (c != ' ') goto badlist; - if (strcasecmp(arg.s, "storage") != 0) badresource = 1; + if (strcasecmp(arg.s, "remove") == 0) rmquota = 1; + else if (strcasecmp(arg.s, "storage") != 0) badresource = 1; c = getword(imapd_in, &arg); if (c != ' ' && c != ')') goto badlist; if (arg.s[0] == '\0') goto badlist; @@ -4769,7 +4771,10 @@ imapd_userid, mailboxname); if (!r) { - r = mboxlist_setquota(mailboxname, newquota, force); + if(!rmquota) + r = mboxlist_setquota(mailboxname, newquota, force); + else + r = mboxlist_unsetquota(mailboxname); } } diff -Naur cyrus-imapd-2.2.12/imap/mailbox.c cyrus-imapd-2.2.12.rmquota.uncompiled/imap/mailbox.c --- cyrus-imapd-2.2.12/imap/mailbox.c 2005-02-14 08:39:57.000000000 +0200 +++ cyrus-imapd-2.2.12.rmquota.uncompiled/imap/mailbox.c 2005-03-03 16:08:19.000000000 +0200 @@ -2117,27 +2117,7 @@ seen_delete_mailbox(mailbox); - if (delete_quota_root && !rquota) { - quota_delete(&mailbox->quota, &tid); - free(mailbox->quota.root); - mailbox->quota.root = NULL; - } else if (!rquota) { - /* Free any quota being used by this mailbox */ - if (mailbox->quota.used >= mailbox->quota_mailbox_used) { - mailbox->quota.used -= mailbox->quota_mailbox_used; - } - else { - mailbox->quota.used = 0; - } - r = quota_write(&mailbox->quota, &tid); - if (r) { - syslog(LOG_ERR, - "LOSTQUOTA: unable to record free of %lu bytes in quota %s", - mailbox->quota_mailbox_used, mailbox->quota.root); - } - else - quota_commit(&tid); - } + mailbox_updatequota(mailbox,NULL); /* remove all files in directory */ strlcpy(buf, mailbox->path, sizeof(buf)); @@ -2751,3 +2731,49 @@ if (*p == '.') *p = '/'; } } + + +/* This function is used to update the quota. Can be used to replace + * identical parts of the code, and can be quite handy some times + * The tid is used in order to make possible to make the quota update + * being a part of a bigger transaction to the quota db */ +int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid) +{ + int r = 0, havetid = 0; + struct txn **ltid = NULL; + + if(tid) { + ltid = tid; + havetid = 1; + } + /* Ensure that we are locked */ + if(!mailbox->header_lock_count) return IMAP_INTERNAL; + + + if(mailbox->quota.root) { + r = quota_read(&mailbox->quota, ltid, 1); + if( r == 0 ) { + if (mailbox->quota.used >= mailbox->quota_mailbox_used) { + mailbox->quota.used -= mailbox->quota_mailbox_used; + } + else { + mailbox->quota.used = 0; + } + r = quota_write(&mailbox->quota, ltid); + if (r) { + syslog(LOG_ERR, + "LOSTQUOTA: unable to record free of %lu bytes in quota %s", + mailbox->quota_mailbox_used, mailbox->quota.root); + } + else if(!havetid) + quota_commit(&tid); + } + /* It is not a big mistake not to have quota .. just remove from the mailbox */ + else if ( r == IMAP_QUOTAROOT_NONEXISTENT) { + free(mailbox->quota.root); + r = 0; + } + } + return r; +} + diff -Naur cyrus-imapd-2.2.12/imap/mailbox.h cyrus-imapd-2.2.12.rmquota.uncompiled/imap/mailbox.h --- cyrus-imapd-2.2.12/imap/mailbox.h 2004-01-22 23:17:09.000000000 +0200 +++ cyrus-imapd-2.2.12.rmquota.uncompiled/imap/mailbox.h 2005-03-03 16:08:19.000000000 +0200 @@ -305,6 +305,8 @@ struct mailbox *mailboxp); extern int mailbox_delete(struct mailbox *mailbox, int delete_quota_root); +extern int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid); + extern int mailbox_rename_copy(struct mailbox *oldmailbox, const char *newname, char *newpath, bit32 *olduidvalidityp, bit32 *newuidvalidityp, diff -Naur cyrus-imapd-2.2.12/imap/mboxlist.c cyrus-imapd-2.2.12.rmquota.uncompiled/imap/mboxlist.c --- cyrus-imapd-2.2.12/imap/mboxlist.c 2004-07-26 21:08:03.000000000 +0300 +++ cyrus-imapd-2.2.12.rmquota.uncompiled/imap/mboxlist.c 2005-03-03 16:08:19.000000000 +0200 @@ -100,6 +100,7 @@ struct change_rock { struct quota *quota; + struct quota *oldquota; struct txn **tid; }; @@ -2357,6 +2358,7 @@ if (r) return r; crock.quota = "a; + crock.oldquota = NULL; crock.tid = &tid; /* top level mailbox */ if(have_mailbox) @@ -2375,17 +2377,21 @@ */ int mboxlist_unsetquota(const char *root) { + char newquota[MAX_MAILBOX_PATH+1]; char pattern[MAX_MAILBOX_PATH+1]; struct quota quota; - int r=0; + struct change_rock crock; + int r=0, k=0; if (!root[0] || root[0] == '.' || strchr(root, '/') || strchr(root, '*') || strchr(root, '%') || strchr(root, '?')) { return IMAP_MAILBOX_BADNAME; } + crock.tid = NULL; + quota.root = (char *) root; - r = quota_read("a, NULL, 0); + r = quota_read("a, crock.tid, 0); if (r == IMAP_QUOTAROOT_NONEXISTENT) { /* already unset */ return 0; @@ -2402,13 +2408,45 @@ } else strlcat(pattern, ".*", sizeof(pattern)); - - /* top level mailbox */ - mboxlist_rmquota(root, 0, 0, (void *)root); - /* submailboxes - we're using internal names here */ - mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root); - r = quota_delete("a, NULL); + r = quota_delete("a, crock.tid); + + /* If we cannot delete the quota then abort the operation */ + if(!r) { + /* quota_findroot performs several checks that we can + * assume that are already done, and don't have to perform + * them again. One of them is that it returns 1 only if + * quotaroot exists. + */ + if(quota_findroot(newquota, sizeof(newquota), root)) { + struct quota rootquota; + rootquota.root = newquota; + k = quota_read(&rootquota, crock.tid, 0); + if (!k) { + crock.quota = &rootquota; + crock.oldquota = "a; + /* top level mailbox */ + k = mboxlist_changequota(root, 0, 0, &crock); + } + /* submailboxes - we're using internal names here */ + if (!k) + k = mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_changequota, &crock); + if(!k) + k = quota_write(&rootquota, crock.tid); + + } + else { + /* top level mailbox */ + mboxlist_rmquota(root, 0, 0, (void *)root); + /* submailboxes - we're using internal names here */ + mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root); + } + } + + if(!r && !k) + quota_commit(crock.tid); + else + quota_abort(crock.tid); return r; } @@ -2506,6 +2544,7 @@ struct mailbox mailbox; struct change_rock *crock = (struct change_rock *) rock; struct quota *mboxlist_newquota = crock->quota; + struct quota *mboxlist_oldquota = crock->oldquota; struct txn **tid = crock->tid; assert(rock != NULL); @@ -2523,27 +2562,24 @@ if (r) goto error; if (mailbox.quota.root) { - if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) { - /* Part of a child quota root */ - mailbox_close(&mailbox); - return 0; - } - - r = quota_read(&mailbox.quota, tid, 1); - if (r) goto error; - if (mailbox.quota.used >= mailbox.quota_mailbox_used) { - mailbox.quota.used -= mailbox.quota_mailbox_used; - } - else { - mailbox.quota.used = 0; - } - r = quota_write(&mailbox.quota, tid); - if (r) { - syslog(LOG_ERR, - "LOSTQUOTA: unable to record free of %lu bytes in quota %s", - mailbox.quota_mailbox_used, mailbox.quota.root); - } - free(mailbox.quota.root); + if(mboxlist_oldquota) { + if (strlen(mailbox.quota.root) > strlen(mboxlist_oldquota->root)) { + /* Part of a child quota root */ + mailbox_close(&mailbox); + return 0; + } + } + else { + if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) { + /* Part of a child quota root */ + mailbox_close(&mailbox); + return 0; + } + } + + r = mailbox_updatequota(&mailbox,tid); + if (r) + goto error; } mailbox.quota.root = xstrdup(mboxlist_newquota->root); @@ -2553,18 +2589,24 @@ mboxlist_newquota->used += mailbox.quota_mailbox_used; mailbox_close(&mailbox); return 0; - + error: mailbox_close(&mailbox); + syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s. \ + Command aborted. Run reconstruct to make sure mailboxes \ + are in consistent state", + name, mboxlist_newquota->root, error_message(r)); + return 1; error_noclose: syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s", - name, mboxlist_newquota->root, error_message(r)); + name, mboxlist_newquota->root, error_message(r)); /* Note, we're a callback, and it's not a huge tragedy if we * fail, so we don't ever return a failure */ return 0; } + /* must be called after cyrus_init */ void mboxlist_init(int myflags) {