/* create a downgraded index file in cyrus.index. We don't copy back * expunged messages, sorry */ static int dump_index(struct mailbox *mailbox, int oldversion, struct seqset *expunged_seq, int first, int sync, struct protstream *pin, struct protstream *pout) { char oldname[MAX_MAILBOX_PATH]; const char *fname; int oldindex_fd = -1; indexbuffer_t headerbuf; indexbuffer_t recordbuf; char *hbuf = (char *)headerbuf.buf; char *rbuf = (char *)recordbuf.buf; int header_size; int record_size; int n, r; if (oldversion == 6) { header_size = 76; record_size = 60; } else if (oldversion == 7) { header_size = 76; record_size = 72; } else if (oldversion == 8) { header_size = 92; record_size = 80; } else if (oldversion == 9) { header_size = 96; record_size = 80; } else if (oldversion == 10) { header_size = 96; record_size = 88; } else { return IMAP_MAILBOX_BADFORMAT; } fname = mailbox_meta_fname(mailbox, META_INDEX); snprintf(oldname, MAX_MAILBOX_PATH, "%s.OLD", fname); oldindex_fd = open(oldname, O_RDWR|O_TRUNC|O_CREAT, 0666); if (oldindex_fd == -1) goto fail; downgrade_header(&mailbox->i, hbuf, oldversion, header_size, record_size); /* Write header - everything we'll say */ n = retry_write(oldindex_fd, hbuf, header_size); if (n == -1) goto fail; struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, ITER_SKIP_UNLINKED); const message_t *msg; while ((msg = mailbox_iter_step(iter))) { const struct index_record *record = msg_record(msg); /* we have to make sure expunged records don't get the * file copied, or a reconstruct could bring them back * to life! It we're not creating an expunged file... */ if (record->system_flags & FLAG_EXPUNGED) { if (oldversion < 9) seqset_add(expunged_seq, record->uid, 1); continue; } /* not making sure exists matches, we do trust a bit */ downgrade_record(record, rbuf, oldversion); n = retry_write(oldindex_fd, rbuf, record_size); if (n == -1) goto fail; } mailbox_iter_done(&iter); close(oldindex_fd); r = dump_file(first, sync, pin, pout, oldname, "cyrus.index", NULL, 0); unlink(oldname); if (r) return r; /* create cyrus.expunge */ if (oldversion > 8 && mailbox->i.num_records > mailbox->i.exists) { int nexpunge = mailbox->i.num_records - mailbox->i.exists; fname = mailbox_meta_fname(mailbox, META_EXPUNGE); snprintf(oldname, MAX_MAILBOX_PATH, "%s.OLD", fname); oldindex_fd = open(oldname, O_RDWR|O_TRUNC|O_CREAT, 0666); if (oldindex_fd == -1) goto fail; header_set_num_records(hbuf, nexpunge); /* Write header - everything we'll say */ n = retry_write(oldindex_fd, hbuf, header_size); if (n == -1) goto fail; iter = mailbox_iter_init(mailbox, 0, ITER_SKIP_UNLINKED); while ((msg = mailbox_iter_step(iter))) { const struct index_record *record = msg_record(msg); /* ignore non-expunged records */ if (!(record->system_flags & FLAG_EXPUNGED)) continue; downgrade_record(record, rbuf, oldversion); n = retry_write(oldindex_fd, rbuf, record_size); if (n == -1) goto fail; } close(oldindex_fd); r = dump_file(first, sync, pin, pout, oldname, "cyrus.expunge", NULL, 0); unlink(oldname); if (r) return r; } return 0; fail: if (oldindex_fd != -1) close(oldindex_fd); unlink(oldname); return IMAP_IOERROR; }
/* create a downgraded index file in cyrus.index. We don't copy back * expunged messages, sorry */ static int dump_index(struct mailbox *mailbox, int oldversion, struct seqset *expunged_seq, int first, int sync, struct protstream *pin, struct protstream *pout) { char oldname[MAX_MAILBOX_PATH]; const char *fname; int oldindex_fd = -1; indexbuffer_t headerbuf; indexbuffer_t recordbuf; char *hbuf = (char *)headerbuf.buf; char *rbuf = (char *)recordbuf.buf; int header_size; int record_size; int n, r; struct index_record record; unsigned recno; if (oldversion == 6) { header_size = 76; record_size = 60; } else if (oldversion == 7) { header_size = 76; record_size = 72; } else if (oldversion == 8) { header_size = 92; record_size = 80; } else if (oldversion == 9) { header_size = 96; record_size = 80; } else if (oldversion == 10) { header_size = 96; record_size = 88; } else { return IMAP_MAILBOX_BADFORMAT; } fname = mailbox_meta_fname(mailbox, META_INDEX); snprintf(oldname, MAX_MAILBOX_PATH, "%s.OLD", fname); oldindex_fd = open(oldname, O_RDWR|O_TRUNC|O_CREAT, 0666); if (oldindex_fd == -1) goto fail; downgrade_header(&mailbox->i, hbuf, oldversion, header_size, record_size); /* Write header - everything we'll say */ n = retry_write(oldindex_fd, hbuf, header_size); if (n == -1) goto fail; for (recno = 1; recno <= mailbox->i.num_records; recno++) { if (mailbox_read_index_record(mailbox, recno, &record)) goto fail; /* we don't care about unlinked records at all */ if (record.system_flags & FLAG_UNLINKED) continue; /* we have to make sure expunged records don't get the * file copied, or a reconstruct could bring them back * to life! It we're not creating an expunged file... */ if (record.system_flags & FLAG_EXPUNGED) { if (oldversion < 9) seqset_add(expunged_seq, record.uid, 1); continue; } /* not making sure exists matches, we do trust a bit */ downgrade_record(&record, rbuf, oldversion); n = retry_write(oldindex_fd, rbuf, record_size); if (n == -1) goto fail; } close(oldindex_fd); r = dump_file(first, sync, pin, pout, oldname, "cyrus.index"); unlink(oldname); if (r) return r; /* create cyrus.expunge */ if (oldversion > 8 && mailbox->i.num_records > mailbox->i.exists) { int nexpunge = mailbox->i.num_records - mailbox->i.exists; fname = mailbox_meta_fname(mailbox, META_EXPUNGE); snprintf(oldname, MAX_MAILBOX_PATH, "%s.OLD", fname); oldindex_fd = open(oldname, O_RDWR|O_TRUNC|O_CREAT, 0666); if (oldindex_fd == -1) goto fail; *((bit32 *)(hbuf+OFFSET_NUM_RECORDS)) = htonl(nexpunge); /* Write header - everything we'll say */ n = retry_write(oldindex_fd, hbuf, header_size); if (n == -1) goto fail; for (recno = 1; recno <= mailbox->i.num_records; recno++) { if (mailbox_read_index_record(mailbox, recno, &record)) goto fail; /* ignore non-expunged records */ if (!(record.system_flags & FLAG_EXPUNGED)) continue; downgrade_record(&record, rbuf, oldversion); n = retry_write(oldindex_fd, rbuf, record_size); if (n == -1) goto fail; } close(oldindex_fd); r = dump_file(first, sync, pin, pout, oldname, "cyrus.expunge"); unlink(oldname); if (r) return r; } return 0; fail: if (oldindex_fd != -1) close(oldindex_fd); unlink(oldname); return IMAP_IOERROR; }