static int want_append_message(struct dlist *dlist, struct sync_msgid_list *keep_message_guids) { struct dlist *di, *next; for (di = dlist->head; di; di = next) { struct message_guid *guid = NULL; /* save next pointer now in case we need to unstitch */ next = di->next; if (!dlist_tofile(di, NULL, &guid, NULL, NULL)) continue; if (!sync_msgid_lookup(keep_message_guids, guid)) { syslog(LOG_DEBUG, "%s: MESSAGE no longer needed: %s", __func__, message_guid_encode(guid)); dlist_unstitch(dlist, di); dlist_unlink_files(di); dlist_free(&di); } } if (dlist->head) { syslog(LOG_DEBUG, "%s: keeping MESSAGE line", __func__); return 1; } syslog(LOG_DEBUG, "%s: MESSAGE line has no more messages", __func__); return 0; }
/* XXX - these two functions should be out in append.c or reserve.c * or something more general */ EXPORTED const char *dlist_reserve_path(const char *part, int isarchive, const struct message_guid *guid) { static char buf[MAX_MAILBOX_PATH]; const char *base; /* part can be either a configured partition name, or a path */ if (strchr(part, '/')) { base = part; } else { base = isarchive ? config_archivepartitiondir(part) : config_partitiondir(part); } /* we expect to have a base at this point, so let's assert that */ assert(base != NULL); snprintf(buf, MAX_MAILBOX_PATH, "%s/sync./%lu/%s", base, (unsigned long)getpid(), message_guid_encode(guid)); /* gotta make sure we can create files */ if (cyrus_mkdir(buf, 0755)) { /* it's going to fail later, but at least this will help */ syslog(LOG_ERR, "IOERROR: failed to create %s/sync./%lu/ for reserve: %m", base, (unsigned long)getpid()); } return buf; }
static int cmd_show_mailboxes(struct backup *backup, const struct cyrbu_cmd_options *options) { struct backup_mailbox *mailbox = NULL; struct backup_mailbox_message *record = NULL; int i; for (i = 0; i < strarray_size(options->argv); i++) { char ts_deleted[32] = ""; const char *arg = strarray_nth(options->argv, i); /* argument could be a uniqueid */ mailbox = backup_get_mailbox_by_uniqueid(backup, arg, 1); /* or it could be an mboxname */ if (!mailbox) { mbname_t *mbname = mbname_from_intname(arg); if (!mbname) continue; mailbox = backup_get_mailbox_by_name(backup, mbname, 1); mbname_free(&mbname); } /* or it could be junk */ if (!mailbox) continue; fprintf(stdout, "mboxname: %s\n", mailbox->mboxname); fprintf(stdout, "uniqueid: %s\n", mailbox->uniqueid); if (mailbox->deleted) { strftime(ts_deleted, sizeof(ts_deleted), "%F %T", localtime(&mailbox->deleted)); fprintf(stdout, "deleted: %s\n", ts_deleted); } fprintf(stdout, "messages:\n"); fprintf(stdout, " uid expunged time guid\n"); for (record = mailbox->records->head; record; record = record->next) { char ts_expunged[32] = " "; if (record->expunged) strftime(ts_expunged, sizeof(ts_expunged), "%F %T", localtime(&record->expunged)); fprintf(stdout, "%10d %s %s\n", record->uid, ts_expunged, message_guid_encode(&record->guid)); } fprintf(stdout, "\n"); backup_mailbox_free(&mailbox); } return 0; }
static void printfile(struct protstream *out, const struct dlist *dl) { struct stat sbuf; FILE *f; unsigned long size; struct message_guid guid2; const char *msg_base = NULL; size_t msg_len = 0; assert(dlist_isfile(dl)); f = fopen(dl->sval, "r"); if (!f) { syslog(LOG_ERR, "IOERROR: Failed to read file %s", dl->sval); prot_printf(out, "NIL"); return; } if (fstat(fileno(f), &sbuf) == -1) { syslog(LOG_ERR, "IOERROR: Failed to stat file %s", dl->sval); prot_printf(out, "NIL"); fclose(f); return; } size = sbuf.st_size; if (size != dl->nval) { syslog(LOG_ERR, "IOERROR: Size mismatch %s (%lu != " MODSEQ_FMT ")", dl->sval, size, dl->nval); prot_printf(out, "NIL"); fclose(f); return; } map_refresh(fileno(f), 1, &msg_base, &msg_len, sbuf.st_size, "new message", 0); message_guid_generate(&guid2, msg_base, msg_len); if (!message_guid_equal(&guid2, dl->gval)) { syslog(LOG_ERR, "IOERROR: GUID mismatch %s", dl->sval); prot_printf(out, "NIL"); fclose(f); map_free(&msg_base, &msg_len); return; } prot_printf(out, "%%{"); prot_printastring(out, dl->part); prot_printf(out, " "); prot_printastring(out, message_guid_encode(dl->gval)); prot_printf(out, " %lu}\r\n", size); prot_write(out, msg_base, msg_len); fclose(f); map_free(&msg_base, &msg_len); }
static int list_message_cb(const struct backup_message *message, void *rock) { const struct cyrbu_cmd_options *options = (const struct cyrbu_cmd_options *) rock; (void) options; fprintf(stdout, "%s\n", message_guid_encode(message->guid)); return 0; }
static int cmd_show_messages(struct backup *backup, const struct cyrbu_cmd_options *options) { struct backup_message *message = NULL; struct backup_mailbox_list *mailboxes = NULL; struct backup_mailbox *mailbox; struct message_guid want_guid; int i; for (i = 0; i < strarray_size(options->argv); i++) { if (!message_guid_decode(&want_guid, strarray_nth(options->argv, i))) continue; message = backup_get_message(backup, &want_guid); if (!message) continue; fprintf(stdout, "guid:\t%s\n", message_guid_encode(message->guid)); mailboxes = backup_get_mailboxes_by_message(backup, message, 0); if (mailboxes) { fprintf(stdout, "mailboxes:\n"); for (mailbox = mailboxes->head; mailbox; mailbox = mailbox->next) { fprintf(stdout, "\t%s\t%s\n", mailbox->uniqueid, mailbox->mboxname); } backup_mailbox_list_empty(mailboxes); free(mailboxes); } fprintf(stdout, "headers:\n"); backup_read_message_data(backup, message, show_message_headers, stdout); fprintf(stdout, "\n"); backup_message_free(&message); } return 0; }
HIDDEN int dlist_tomap(struct dlist *dl, const char **valp, size_t *lenp) { char tmp[30]; if (!dl) return 0; switch (dl->type) { case DL_NUM: case DL_DATE: snprintf(tmp, 30, "%llu", dl->nval); dlist_makeatom(dl, tmp); break; case DL_HEX: snprintf(tmp, 30, "%016llx", dl->nval); dlist_makeatom(dl, tmp); break; case DL_GUID: dlist_makeatom(dl, message_guid_encode(dl->gval)); break; case DL_ATOM: case DL_FLAG: case DL_BUF: break; default: return 0; } if (valp) *valp = dl->sval; if (lenp) *lenp = dl->nval; return 1; }
EXPORTED void dlist_print(const struct dlist *dl, int printkeys, struct protstream *out) { struct dlist *di; if (printkeys) { prot_printastring(out, dl->name); prot_putc(' ', out); } switch (dl->type) { case DL_NIL: prot_printf(out, "NIL"); break; case DL_ATOM: prot_printastring(out, dl->sval); break; case DL_FLAG: prot_printf(out, "%s", dl->sval); break; case DL_NUM: case DL_DATE: /* for now, we will format it later */ prot_printf(out, "%llu", dl->nval); break; case DL_FILE: printfile(out, dl); break; case DL_BUF: if (strlen(dl->sval) == dl->nval) prot_printastring(out, dl->sval); else prot_printliteral(out, dl->sval, dl->nval); break; case DL_GUID: prot_printf(out, "%s", message_guid_encode(dl->gval)); break; case DL_HEX: { char buf[17]; snprintf(buf, 17, "%016llx", dl->nval); prot_printf(out, "%s", buf); } break; case DL_KVLIST: prot_printf(out, "%%("); for (di = dl->head; di; di = di->next) { dlist_print(di, 1, out); if (di->next) { prot_printf(out, " "); } } prot_printf(out, ")"); break; case DL_ATOMLIST: prot_printf(out, "("); for (di = dl->head; di; di = di->next) { dlist_print(di, dl->nval, out); if (di->next) prot_printf(out, " "); } prot_printf(out, ")"); break; } }
static int reservefile(struct protstream *in, const char *part, struct message_guid *guid, unsigned long size, const char **fname) { FILE *file; char buf[8192+1]; int r = 0; /* XXX - write to a temporary file then move in to place! */ *fname = dlist_reserve_path(part, /*isarchive*/0, guid); /* remove any duplicates if they're still here */ unlink(*fname); file = fopen(*fname, "w+"); if (!file) { syslog(LOG_ERR, "IOERROR: failed to upload file %s", message_guid_encode(guid)); r = IMAP_IOERROR; /* Note: we still read the file's data from the wire, * to avoid losing protocol sync */ } /* XXX - calculate sha1 on the fly? */ while (size) { size_t n = prot_read(in, buf, size > 8192 ? 8192 : size); if (!n) { syslog(LOG_ERR, "IOERROR: reading message: unexpected end of file"); r = IMAP_IOERROR; break; } size -= n; if (fwrite(buf, 1, n, file) != n) { syslog(LOG_ERR, "IOERROR: writing to file '%s': %m", *fname); r = IMAP_IOERROR; break; } } if (r) goto error; /* Make sure that message flushed to disk just incase mmap has problems */ fflush(file); if (ferror(file)) { r = IMAP_IOERROR; goto error; } if (fsync(fileno(file)) < 0) { syslog(LOG_ERR, "IOERROR: fsyncing file '%s': %m", *fname); r = IMAP_IOERROR; goto error; } fclose(file); return 0; error: if (file) { fclose(file); unlink(*fname); *fname = NULL; } return r; }
static void apply_mailbox_options(struct backup_mailbox *mailbox, const struct restore_options *options) { if (options->override_mboxname) { if (options->verbose) { fprintf(stderr, "%s: overriding mboxname with %s\n", mailbox->mboxname, options->override_mboxname); } if (mailbox->mboxname) free(mailbox->mboxname); mailbox->mboxname = xstrdup(options->override_mboxname); } if (options->override_partition) { if (options->verbose) { fprintf(stderr, "%s: overriding partition with %s (was %s)\n", mailbox->mboxname, options->override_partition, mailbox->partition); } if (mailbox->partition) free(mailbox->partition); mailbox->partition = xstrdup(options->override_partition); } if (options->override_acl) { if (options->verbose) { fprintf(stderr, "%s: overriding acl with '%s' (was '%s')\n", mailbox->mboxname, options->override_acl, mailbox->acl); } if (mailbox->acl) free(mailbox->acl); /* treat empty override string as no ACL, resulting in the mailbox * being restored with the default ACL for its owner. */ if (*options->override_acl) { mailbox->acl = xstrdup(options->override_acl); } else { mailbox->acl = NULL; } } if (!options->keep_uidvalidity) { if (options->verbose) { fprintf(stderr, "%s: not trying to keep uidvalidity\n", mailbox->mboxname); } if (mailbox->uniqueid) free(mailbox->uniqueid); mailbox->uniqueid = NULL; mailbox->highestmodseq = 0; mailbox->uidvalidity = 0; } else if (options->verbose) { fprintf(stderr, "%s: trying to keep uidvalidity(%u), " "uniqueid(%s), highestmodseq(" MODSEQ_FMT ")\n", mailbox->mboxname, mailbox->uidvalidity, mailbox->uniqueid, mailbox->highestmodseq); } if (mailbox->mboxname && options->trim_deletedprefix) { mbname_t *mbname = mbname_from_intname(mailbox->mboxname); if (mbname_isdeleted(mbname)) { char *freeme = mailbox->mboxname; mbname_set_isdeleted(mbname, 0); mailbox->mboxname = xstrdup(mbname_intname(mbname)); if (options->verbose) { fprintf(stderr, "%s: removing deletedprefix (was %s)\n", mailbox->mboxname, freeme); } free(freeme); } mbname_free(&mbname); } if (options->expunged_mode != RESTORE_EXPUNGED_OKAY) { struct backup_mailbox_message *iter, *tmp, *next; next = mailbox->records->head; while ((iter = next)) { next = iter->next; tmp = NULL; switch (options->expunged_mode) { case RESTORE_EXPUNGED_EXCLUDE: if (iter->expunged) { tmp = backup_mailbox_message_list_remove(mailbox->records, iter); if (options->verbose) { fprintf(stderr, "%s: excluding expunged message: %s\n", mailbox->mboxname, message_guid_encode(&iter->guid)); } } break; case RESTORE_EXPUNGED_ONLY: if (!iter->expunged) { tmp = backup_mailbox_message_list_remove(mailbox->records, iter); if (options->verbose) { fprintf(stderr, "%s: excluding unexpunged message: %s\n", mailbox->mboxname, message_guid_encode(&iter->guid)); } } break; default: break; } if (tmp) backup_mailbox_message_free(&tmp); } } }