Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
0
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;
}
Пример #4
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);
}
Пример #5
0
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;
}
Пример #6
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;
}
Пример #7
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;
}
Пример #8
0
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;
    }
}
Пример #9
0
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;
}
Пример #10
0
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);
        }
    }
}