We'd like to make some changes to reconstruct, but would like to get
some feedback on them. Attached is a diff of the changes.
First we'd like to make -k the default behavior if delayed expunge is
enabled. Second, add a -w flag to warn about changes that would be
made to a mailbox, similar to ctl_mboxlist -w. Third, add -e to
enable indexing un-indexed messages to a new cyrus.expunge rather
than putting them into the cyrus.index file. -e can be useful when a
expunge file isn't verifiable or corrupted and you don't want a large
number of deleted messages to reappear in a users mailbox.
---
Brian Awood
University of Michigan
--- cyrus-imapd-2.3.14/imap/reconstruct.c~ 2009-02-11 13:53:04.000000000 -0500
+++ cyrus-imapd-2.3.14/imap/reconstruct.c 2009-04-10 16:11:19.000000000 -0400
@@ -134,10 +134,13 @@
extern cyrus_acl_canonproc_t mboxlist_ensureOwnerRights;
int code = 0;
+int status = 0;
int keepflag = 0;
int syncflag = 0;
int guid_clear = 0;
int guid_set = 0;
+int warn_only = 0;
+int add_expunge = 0;
int main(int argc, char **argv)
{
@@ -163,7 +166,7 @@
assert(INDEX_HEADER_SIZE == (OFFSET_SPARE4+4));
assert(INDEX_RECORD_SIZE == (OFFSET_MODSEQ+4));
- while ((opt = getopt(argc, argv, "C:kp:rmfsxgG")) != EOF) {
+ while ((opt = getopt(argc, argv, "C:kp:rmfsxgGwe")) != EOF) {
switch (opt) {
case 'C': /* alt config file */
alt_config = optarg;
@@ -205,6 +208,14 @@
guid_set = 1;
break;
+ case 'w':
+ warn_only = 1;
+ break;
+
+ case 'e':
+ add_expunge = 1;
+ break;
+
default:
usage();
}
@@ -213,6 +224,11 @@
cyrus_init(alt_config, "reconstruct", 0);
global_sasl_init(1,0,NULL);
+ if( config_getenum(IMAPOPT_EXPUNGE_MODE) ==
+ IMAP_ENUM_EXPUNGE_MODE_DELAYED ) {
+ keepflag = 1;
+ }
+
/* Set namespace -- force standard (internal) */
if ((r = mboxname_init_namespace(&recon_namespace, 1)) != 0) {
syslog(LOG_ERR, error_message(r));
@@ -302,10 +318,14 @@
(*recon_namespace.mboxname_tointernal)(&recon_namespace, argv[i],
NULL, buf);
- r = mboxlist_createmailbox(buf, 0, start_part, 1,
+ if( warn_only ) {
+ printf( "Add to mailbox list: %s\n", buf );
+ } else {
+ r = mboxlist_createmailbox(buf, 0, start_part, 1,
"cyrus", NULL, 0, 0, !xflag);
- if(r) {
- fprintf(stderr, "could not create %s\n", argv[i]);
+ if(r) {
+ fprintf(stderr, "could not create %s\n", argv[i]);
+ }
}
}
}
@@ -363,10 +383,14 @@
p = head.next;
head.next = p->next;
- /* create p (database only) and reconstruct it */
- /* partition is defined by the parent mailbox */
- r = mboxlist_createmailbox(p->name, 0, NULL, 1,
+ if( warn_only ) {
+ printf( "Discovered mailbox %s\n", p->name );
+ } else {
+ /* create p (database only) and reconstruct it */
+ /* partition is defined by the parent mailbox */
+ r = mboxlist_createmailbox(p->name, 0, NULL, 1,
"cyrus", NULL, 0, 0, !xflag);
+ }
if (!r) {
do_reconstruct(p->name, strlen(p->name), 0, &head);
} else {
@@ -387,7 +411,8 @@
cyrus_done();
- return code;
+ if(code) return code;
+ return ( status ? 1: 0);
}
void usage(void)
@@ -833,11 +858,16 @@
snprintf(mbpath, sizeof(mbpath), "%s%s", path, FNAME_HEADER);
if(stat(mbpath, &sbuf) == -1) {
/* Header doesn't exist, create it! */
- r = mailbox_create(name, mypart, myacl, NULL,
+ if( warn_only ) {
+ printf( "stat() error of header file, does it exist?\n" );
+ return IMAP_IOERROR;
+ } else {
+ r = mailbox_create(name, mypart, myacl, NULL,
((mytype & MBTYPE_NETNEWS) ?
MAILBOX_FORMAT_NETNEWS :
MAILBOX_FORMAT_NORMAL), NULL);
- if(r) return r;
+ if(r) return r;
+ }
}
/* Now open just the header (it will hopefully be valid) */
@@ -859,8 +889,7 @@
if (mailbox.quota.root) free(mailbox.quota.root);
if (hasquota) {
mailbox.quota.root = xstrdup(quota_root);
- }
- else {
+ } else {
mailbox.quota.root = 0;
}
@@ -893,7 +922,11 @@
}
if(strcmp(list_acl, mailbox.acl)) {
- r = mboxlist_update(name, list_type, list_part, mailbox.acl, 0);
+ if( warn_only ) {
+ printf( "Update mailbox list acl: %s, %s\n", name, mailbox.acl );
+ } else {
+ r = mboxlist_update(name, list_type, list_part, mailbox.acl, 0);
+ }
}
if (r) {
mailbox_close(&mailbox);
@@ -931,12 +964,16 @@
map_free(&expunge_base, &expunge_len);
close(expunge_fd);
expunge_fd = -1;
- syslog(LOG_ERR, "Unable to verify expunge header - deleting: %s",
+ if( warn_only ) {
+ printf( "Bad expunge header: %s\n", name );
+ } else {
+ syslog(LOG_ERR, "Unable to verify expunge header - deleting: %s",
mailbox.name);
- reconstruct_delete_single(&mailbox,
+ reconstruct_delete_single(&mailbox,
IMAP_ENUM_METAPARTITION_FILES_EXPUNGE,
FNAME_EXPUNGE_INDEX, NULL);
- }
+ }
+ }
}
if (expunge_base && (expunge_len >= INDEX_HEADER_SIZE))
expunge_exists = ntohl(*((bit32 *)(expunge_base+OFFSET_EXISTS)));
@@ -964,9 +1001,15 @@
}
if (!keepflag && (expunge_exists > 0))
+ if( warn_only ) {
+ printf( "Remove from %s, %i expunged messages!\n", name,
+ expunge_exists );
+ } else {
reconstruct_clear_expunged(&mailbox, expunge_uidmap, expunge_exists);
+ }
/* Create new index/cache/expunge files */
+ if( !warn_only ) {
reconstruct_make_path(fnamebuf, sizeof(fnamebuf), &mailbox,
IMAP_ENUM_METAPARTITION_FILES_INDEX,
FNAME_INDEX, ".NEW");
@@ -995,6 +1038,7 @@
fwrite(buf, 1, INDEX_HEADER_SIZE, newindex);
fwrite(buf, 1, INDEX_HEADER_SIZE, newexpunge);
retry_write(newcache_fd, buf, sizeof(bit32));
+ }
/* Find all message files in directory */
uid = (unsigned long *) xmalloc(UIDGROW * sizeof(unsigned long));
@@ -1063,7 +1107,11 @@
if (sbuf.st_size == 0) {
/* Zero-length message file--blow it away */
fclose(msgfile);
+ if( warn_only ) {
+ printf( "Delete Zero-length message file: %s\n", msgfname );
+ } else {
unlink(msgfname);
+ }
continue;
}
@@ -1139,8 +1187,9 @@
/* NB: message_create_record() will reconstruct GUID if NULL */
if (((r = message_parse_file(msgfile, NULL, NULL, &body)) != 0) ||
- ((r = message_create_record(mailbox.name, newcache_fd,
- &message_index, body)) != 0)) {
+ ( !warn_only &&
+ ( r = message_create_record(mailbox.name, newcache_fd,
+ &message_index, body) != 0 ))) {
r = IMAP_IOERROR;
goto bail;
}
@@ -1150,19 +1199,23 @@
/* Clear out existing or regenerated GUID */
if (guid_clear) message_guid_set_null(&message_index.guid);
- if (expunge_found && keepflag) {
+ if ((expunge_found && keepflag) || ( !index_found && add_expunge)) {
/* Write out new entry in expunge file */
reconstruct_counts_update(&expunge_counts, &message_index);
- mailbox_index_record_to_buf(&message_index, buf);
- n = fwrite(buf, 1, INDEX_RECORD_SIZE, newexpunge);
+ if( !warn_only ) {
+ mailbox_index_record_to_buf(&message_index, buf);
+ n = fwrite(buf, 1, INDEX_RECORD_SIZE, newexpunge);
+ }
} else {
/* Write out new entry in index file */
reconstruct_counts_update(&index_counts, &message_index);
- mailbox_index_record_to_buf(&message_index, buf);
- n = fwrite(buf, 1, INDEX_RECORD_SIZE, newindex);
+ if( !warn_only ) {
+ mailbox_index_record_to_buf(&message_index, buf);
+ n = fwrite(buf, 1, INDEX_RECORD_SIZE, newindex);
+ }
}
- if (n != INDEX_RECORD_SIZE) {
+ if (!warn_only && n != INDEX_RECORD_SIZE) {
r = IMAP_IOERROR;
goto bail;
}
@@ -1201,33 +1254,46 @@
/* updated by the counts_tobuf below, different in each file */
}
- rewind(newindex);
- reconstruct_counts_tobuf(buf, &mailbox, &index_counts);
- n = fwrite(buf, 1, INDEX_HEADER_SIZE, newindex);
- if (n != INDEX_HEADER_SIZE) {
- r = IMAP_IOERROR;
- goto bail;
- }
- rewind(newexpunge);
- reconstruct_counts_tobuf(buf, &mailbox, &expunge_counts);
- n = fwrite(buf, 1, INDEX_HEADER_SIZE, newexpunge);
- if (n != INDEX_HEADER_SIZE) {
- r = IMAP_IOERROR;
- goto bail;
- }
+ if( warn_only ) {
+ if( mailbox.exists != index_counts.newexists ) {
+ printf( "Update index message count, old: %i new: %i\n",
+ mailbox.exists, index_counts.newexists );
+ status++;
+ }
+ if( expunge_exists != expunge_counts.newexists ) {
+ printf( "Update expunge message count, old: %i new: %i\n",
+ expunge_exists, expunge_counts.newexists );
+ status++;
+ }
+ } else {
+ rewind(newindex);
+ reconstruct_counts_tobuf(buf, &mailbox, &index_counts);
+ n = fwrite(buf, 1, INDEX_HEADER_SIZE, newindex);
+ if (n != INDEX_HEADER_SIZE) {
+ r = IMAP_IOERROR;
+ goto bail;
+ }
+ rewind(newexpunge);
+ reconstruct_counts_tobuf(buf, &mailbox, &expunge_counts);
+ n = fwrite(buf, 1, INDEX_HEADER_SIZE, newexpunge);
+ if (n != INDEX_HEADER_SIZE) {
+ r = IMAP_IOERROR;
+ goto bail;
+ }
- fflush(newindex);
- fflush(newexpunge);
- if (ferror(newindex) || ferror(newexpunge) || fsync(newcache_fd) ||
- fsync(fileno(newindex)) || fsync(fileno(newexpunge))) {
- r = IMAP_IOERROR;
- goto bail;
- }
+ fflush(newindex);
+ fflush(newexpunge);
+ if (ferror(newindex) || ferror(newexpunge) || fsync(newcache_fd) ||
+ fsync(fileno(newindex)) || fsync(fileno(newexpunge))) {
+ r = IMAP_IOERROR;
+ goto bail;
+ }
- /* Free temporary resources now that the index/expunge update is done */
- close(newcache_fd);
- fclose(newexpunge);
- fclose(newindex);
+ /* Free temporary resources now that the index/expunge update is done */
+ close(newcache_fd);
+ fclose(newexpunge);
+ fclose(newindex);
+ }
if (expunge_base) map_free(&expunge_base, &expunge_len);
if (expunge_fd >= 0) close(expunge_fd);
@@ -1249,16 +1315,24 @@
/* this may change uniqueid, but if it does, nothing we can do
about it */
- mailbox_make_uniqueid(mailbox.name, mailbox.uidvalidity, unique_buf,
+ if( warn_only ) {
+ printf( "No uid for mailbox: %s\n", mailbox.name );
+ } else {
+ mailbox_make_uniqueid(mailbox.name, mailbox.uidvalidity, unique_buf,
sizeof(unique_buf));
- mailbox.uniqueid = xstrdup(unique_buf);
+ mailbox.uniqueid = xstrdup(unique_buf);
+ }
} else {
if (find_uniqid (mailbox.name, mailbox.uniqueid) != NULL ) {
-
- mailbox_make_uniqueid(mailbox.name, mailbox.uidvalidity,
+ if( warn_only ) {
+ printf( "Mailbox uid not unique: %s\n", mailbox.name );
+ status++;
+ } else {
+ mailbox_make_uniqueid(mailbox.name, mailbox.uidvalidity,
unique_buf, sizeof(unique_buf));
- free (mailbox.uniqueid);
- mailbox.uniqueid = xstrdup(unique_buf);
+ free (mailbox.uniqueid);
+ mailbox.uniqueid = xstrdup(unique_buf);
+ }
}
}
if (add_uniqid (mailbox.name, mailbox.uniqueid) == NULL) {
@@ -1272,33 +1346,35 @@
* mailbox_write_header() locks the new header file before it commits.
* That lock is only released on mailbox_close().
*/
- r = mailbox_write_header(&mailbox);
- if (!r)
- r = reconstruct_rename_single(&mailbox,
+ if( !warn_only ) {
+ r = mailbox_write_header(&mailbox);
+ if (!r)
+ r = reconstruct_rename_single(&mailbox,
IMAP_ENUM_METAPARTITION_FILES_CACHE,
FNAME_CACHE);
- if (!r)
+ if (!r)
r = reconstruct_rename_single(&mailbox,
IMAP_ENUM_METAPARTITION_FILES_EXPUNGE,
FNAME_EXPUNGE_INDEX);
- if (expunge_counts.newexists == 0) {
- reconstruct_delete_single(&mailbox,
+ if (expunge_counts.newexists == 0) {
+ reconstruct_delete_single(&mailbox,
IMAP_ENUM_METAPARTITION_FILES_EXPUNGE,
FNAME_EXPUNGE_INDEX, NULL);
- }
- if (!r)
- r = reconstruct_rename_single(&mailbox,
+ }
+ if (!r)
+ r = reconstruct_rename_single(&mailbox,
IMAP_ENUM_METAPARTITION_FILES_INDEX,
FNAME_INDEX);
- if (r) {
- mailbox_close(&mailbox);
- return (r);
- }
+ if (r) {
+ mailbox_close(&mailbox);
+ return (r);
+ }
- r = seen_reconstruct(&mailbox,
+ r = seen_reconstruct(&mailbox,
(time_t)0, (time_t)0, (int (*)())0, (void *)0);
- if (syncflag) {
- sync_log_mailbox(mailbox.name);
+ if (syncflag) {
+ sync_log_mailbox(mailbox.name);
+ }
}
mailbox_close(&mailbox);
--- cyrus-imapd-2.3.14/man/reconstruct.8~ 2008-04-04 08:47:01.000000000 -0400
+++ cyrus-imapd-2.3.14/man/reconstruct.8 2009-05-01 13:04:56.000000000 -0400
@@ -64,6 +64,12 @@
]
.br
[
+.B \-w
+]
+[
+.B \-e
+]
+[
.B \-k
]
[
@@ -145,9 +151,23 @@
a cyrus.header found there as new mailboxes. Useful for
restoring mailboxes from backups.
.TP
+.B \-w
+Warn about potentially user visible changes to meta data without modifying
+any files, e.g., If the message count listed in the index or expunge meta
+data will change, it displays a summary of what the results will be and
+exits with status 1. Other potentially major changes are warned about.
+Since the cache file isn't user visible, the warn option doesn't generate
+any output regarding it, but is not rebuilt when \-w is used.
+.TP
+.B \-e
+If there are messages on the filesystem that are not listed in the index,
+add them to the expunge data. Useful if the expunge file is corrupted
+and you don't want all the users expunge messages to re-appear in their
+mailbox.
+.TP
.B \-k
Preserve the cyrus.expunge file and the corresponding message files
-instead of deleting them.
+instead of deleting them. (Default if delayed_expunge mode is configured.)
.TP
.B \-s
Adds synchronization records to the log, so the synchronization
@@ -185,6 +205,12 @@
reconstruct -r user/ben.lacy
.fi
+If you want to reconstruct a mailbox and generate GUID data only if the visible
+messages won't change, you could run:
+
+.nf
+reconstruct -w user/foo && reconstruct -g user/foo
+
.SH FILES
.TP
.B /etc/imapd.conf