Exemple #1
0
static int myopen(const char *fname, int flags, struct dbengine **ret, struct txn **mytid)
{
    struct dbengine *db;
    struct stat sbuf;

    assert(fname && ret);

    db = find_db(fname);
    if (db)
        goto out;   /* new reference to existing db */

    db = (struct dbengine *) xzmalloc(sizeof(struct dbengine));

    db->fd = open(fname, O_RDWR, 0644);
    if (db->fd == -1 && errno == ENOENT) {
        if (!(flags & CYRUSDB_CREATE)) {
            free_db(db);
            return CYRUSDB_NOTFOUND;
        }
        if (cyrus_mkdir(fname, 0755) == -1) {
            free_db(db);
            return CYRUSDB_IOERROR;
        }
        db->fd = open(fname, O_RDWR | O_CREAT, 0644);
    }

    if (db->fd == -1) {
        syslog(LOG_ERR, "IOERROR: opening %s: %m", fname);
        free_db(db);
        return CYRUSDB_IOERROR;
    }

    if (fstat(db->fd, &sbuf) == -1) {
        syslog(LOG_ERR, "IOERROR: fstat on %s: %m", fname);
        close(db->fd);
        free_db(db);
        return CYRUSDB_IOERROR;
    }
    db->ino = sbuf.st_ino;

    map_refresh(db->fd, 0, &db->base, &db->len, sbuf.st_size,
                fname, 0);
    db->size = sbuf.st_size;

    db->fname = xstrdup(fname);
    db->refcount = 1;

    /* prepend to the list */
    db->next = alldbs;
    alldbs = db;

    if (mytid) {
        int r = starttxn_or_refetch(db, mytid);
        if (r) return r;
    }

out:
    *ret = db;
    return 0;
}
Exemple #2
0
/**
 * map_scroll -- move the map around
 * @map: pointer to the map you want to move
 * @dir: 'lrud' directional motion char
 */
void map_scroll(struct map_t *map, int dir)
{
        switch (dir) {
        case 'w': 
                pos_u(map->pos);
                break;
        case 'a': 
                pos_l(map->pos);
                break;
        case 's': 
                pos_d(map->pos);
                break;
        case 'd': 
                pos_r(map->pos);
                break;
        case 'W': 
                pos_ustep(map->pos, 4);
                break;
        case 'A': 
                pos_lstep(map->pos, 5);
                break;
        case 'S': 
                pos_dstep(map->pos, 4);
                break;
        case 'D': 
                pos_rstep(map->pos, 5);
                break;
        }
        map_refresh(map);
}
Exemple #3
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);
}
Exemple #4
0
HIDDEN const char *sha1_file(int fd, const char *fname, size_t limit,
                             char buf[2 * SHA1_DIGEST_LENGTH + 1])
{
    const char *map = NULL;
    size_t len = 0, calc_len;
    unsigned char sha1_raw[SHA1_DIGEST_LENGTH];
    int r;

    map_refresh(fd, /*onceonly*/ 1, &map, &len, MAP_UNKNOWN_LEN, fname, NULL);
    calc_len = limit == SHA1_LIMIT_WHOLE_FILE ? len : MIN(limit, len);
    xsha1((const unsigned char *) map, calc_len, sha1_raw);
    map_free(&map, &len);
    r = bin_to_hex(sha1_raw, SHA1_DIGEST_LENGTH, buf, BH_LOWER);
    assert(r == 2 * SHA1_DIGEST_LENGTH);

    return buf;
}
Exemple #5
0
static int load(int fd, bytecode_input_t ** d)
{  
    const char * data=NULL;
    struct stat sbuf;
    unsigned long len=0;
    
    if (fstat(fd, &sbuf) == -1) {
	fprintf(stderr, "IOERROR: fstating sieve script: %m");
	return SIEVE_FAIL;
    }
    
    /*this reads in data and length from file*/
    map_refresh(fd, 1, &(data), &len, sbuf.st_size,
		"sievescript", "");
    *d=(bytecode_input_t *)data;
    
    printf("\n");
    
    return (len/sizeof(int));
}
Exemple #6
0
/* other routines call this one when they fail */
static int abort_txn(struct dbengine *db, struct txn *tid)
{
    int r = CYRUSDB_OK;
    int rw = 0;
    struct stat sbuf;

    assert(db && tid);

    /* cleanup done while lock is held */
    if (tid->fnamenew) {
        unlink(tid->fnamenew);
        free(tid->fnamenew);
        rw = 1;
    }

    /* release lock */
    r = lock_unlock(db->fd, db->fname);
    if (r == -1) {
        syslog(LOG_ERR, "IOERROR: unlocking db %s: %m", db->fname);
        r = CYRUSDB_IOERROR;
    }

    if (rw) {
        /* return to our normally scheduled fd */
        if (!r && fstat(db->fd, &sbuf) == -1) {
            syslog(LOG_ERR, "IOERROR: fstat on %s: %m", db->fname);
            r = CYRUSDB_IOERROR;
        }
        if (!r) {
            map_free(&db->base, &db->len);
            map_refresh(db->fd, 0, &db->base, &db->len, sbuf.st_size,
                        db->fname, 0);
            db->size = sbuf.st_size;
        }
    }

    free(tid);

    return 0;
}
Exemple #7
0
/*
 * render_cb 
 *
 * Called by the rendering loop, which is the tightest of the event loops. 
 * It writes any modified state to the screen, and tries not to calculate much
 * itself, since it has to return quickly.
 * Repeat: .02 seconds
 */
void render_cb(EV_P_ ev_timer *w, int revents)
{
        spin_render_loop();

        if (game_is_paused)
                pause_loop();

        tick();

        free_nouns();
        update_nouns();

        dock_update();

        print_dock();
        update_map_control();
        update_panels();  /* Were slowing down performance, unnecessary */
        doupdate();
        MAPBOOK->restack(ACTIVE);
        map_refresh(ACTIVE);

        ev_timer_again(EV_DEFAULT, w);
}
Exemple #8
0
/* Add all ZONEs and LINKs in the given directory to the hash table */
void do_zonedir(const char *dir, struct hash_table *tzentries,
		struct zoneinfo *info)
{
    DIR *dirp;
    struct dirent *dirent;

    signals_poll();

    if (verbose) printf("Rebuilding %s\n", dir);

    dirp = opendir(dir);
    if (!dirp) {
	fprintf(stderr, "can't open zoneinfo directory %s\n", dir);
    }

    while ((dirent = readdir(dirp))) {
	char path[2048], *tzid;
	int plen;
	struct stat sbuf;
	struct zoneinfo *zi;

	if (*dirent->d_name == '.') continue;	    

	plen = snprintf(path, sizeof(path), "%s/%s", dir, dirent->d_name);
	lstat(path, &sbuf);

	if (S_ISDIR(sbuf.st_mode)) {
	    /* Path is a directory (region) */
	  do_zonedir(path, tzentries, info);
	}
	else if (S_ISLNK(sbuf.st_mode)) {
	    /* Path is a symlink (alias) */
	    char link[1024], *alias;
	    ssize_t llen;

	    /* Isolate tzid in path */
	    if ((llen = readlink(path, link, sizeof(link))) < 0) continue;
	    link[llen-4] = '\0';  /* Trim ".ics" */
	    for (tzid = link; !strncmp(tzid, "../", 3); tzid += 3);

	    /* Isolate alias in path */
	    path[plen-4] = '\0';  /* Trim ".ics" */
	    alias = path + strlen(config_dir) + strlen("zoneinfo") + 2;

	    if (verbose) printf("\tLINK: %s -> %s\n", alias, tzid);

	    /* Create hash entry for alias */
	    if (!(zi = hash_lookup(alias, tzentries))) {
		zi = xzmalloc(sizeof(struct zoneinfo));
		hash_insert(alias, zi, tzentries);
	    }
	    zi->type = ZI_LINK;
	    appendstrlist(&zi->data, tzid);

	    /* Create/update hash entry for tzid */
	    if (!(zi = hash_lookup(tzid, tzentries))) {
		zi = xzmalloc(sizeof(struct zoneinfo));
		hash_insert(tzid, zi, tzentries);
	    }
	    zi->type = ZI_ZONE;
	    appendstrlist(&zi->data, alias);
	}
	else if (S_ISREG(sbuf.st_mode)) {
	    /* Path is a regular file (zone) */
	    int fd;
	    const char *base = NULL;
	    size_t len = 0;
	    icalcomponent *ical, *comp;
	    icalproperty *prop;

	    /* Parse the iCalendar file for important properties */
	    if ((fd = open(path, O_RDONLY)) == -1) continue;
	    map_refresh(fd, 1, &base, &len, MAP_UNKNOWN_LEN, path, NULL);
	    close(fd);

	    ical = icalparser_parse_string(base);
	    map_free(&base, &len);

	    if (!ical) continue;  /* skip non-iCalendar files */

	    comp = icalcomponent_get_first_component(ical,
						     ICAL_VTIMEZONE_COMPONENT);
	    prop = icalcomponent_get_first_property(comp, ICAL_TZID_PROPERTY);
	    tzid = (char *) icalproperty_get_value_as_string(prop);

	    if (verbose) printf("\tZONE: %s\n", tzid);

	    /* Create/update hash entry for tzid */
	    if (!(zi = hash_lookup(tzid, tzentries))) {
		zi = xzmalloc(sizeof(struct zoneinfo));
		hash_insert(tzid, zi, tzentries);
	    }
	    zi->type = ZI_ZONE;
	    prop = icalcomponent_get_first_property(comp,
						    ICAL_LASTMODIFIED_PROPERTY);
	    zi->dtstamp = icaltime_as_timet(icalproperty_get_lastmodified(prop));

	    icalcomponent_free(ical);

	    /* Check overall lastmod */
	    if (zi->dtstamp > info->dtstamp) info->dtstamp = zi->dtstamp;
	}
	else {
	    fprintf(stderr, "unknown path type %s\n", path);
	}
    }

    closedir(dirp);
}
Exemple #9
0
/* Load a compiled script */
EXPORTED int sieve_script_load(const char *fname, sieve_execute_t **ret)
{
    struct stat sbuf;
    sieve_execute_t *ex;
    sieve_bytecode_t *bc;
    int dofree = 0;

    if (!fname || !ret) return SIEVE_FAIL;

    if (stat(fname, &sbuf) == -1) {
        if (errno == ENOENT) {
                syslog(LOG_DEBUG, "WARNING: sieve script %s doesn't exist: %m", fname);
        } else {
                syslog(LOG_DEBUG, "IOERROR: fstating sieve script %s: %m", fname);
        }
        return SIEVE_FAIL;
    }

    if (!*ret) {
        /* new sieve_bytecode_t */
        ex = (sieve_execute_t *) xzmalloc(sizeof(sieve_execute_t));
        dofree = 1;
    } else {
        /* existing sieve_execute_t (INCLUDE) */
        ex = *ret;
    }

    /* see if we already have this script loaded */
    bc = ex->bc_list;
    while (bc) {
        if (sbuf.st_ino == bc->inode) break;
        bc = bc->next;
    }

    if (!bc) {
        int fd;

        /* new script -- load it */
        fd = open(fname, O_RDONLY);
        if (fd == -1) {
            syslog(LOG_ERR, "IOERROR: can not open sieve script %s: %m", fname);
            if (dofree) free(ex);
            return SIEVE_FAIL;
        }
        if (fstat(fd, &sbuf) == -1) {
            syslog(LOG_ERR, "IOERROR: fstating sieve script %s: %m", fname);
            close(fd);
            if (dofree) free(ex);
            return SIEVE_FAIL;
        }

        bc = (sieve_bytecode_t *) xzmalloc(sizeof(sieve_bytecode_t));

        bc->fd = fd;
        bc->inode = sbuf.st_ino;

        map_refresh(fd, 1, &bc->data, &bc->len, sbuf.st_size,
                    fname, "sievescript");

        /* add buffer to list */
        bc->next = ex->bc_list;
        ex->bc_list = bc;

        ex->bc_cur = bc;
        *ret = ex;
        return SIEVE_OK;
    } else {
        // script was loaded in the past
        ex->bc_cur = bc;
        *ret = ex;
        return SIEVE_SCRIPT_RELOADED;
    }
}
Exemple #10
0
static int mystore(struct dbengine *db,
                   const char *key, size_t keylen,
                   const char *data, size_t datalen,
                   struct txn **mytid, int overwrite)
{
    int r = 0;
    char fnamebuf[1024];
    int offset;
    unsigned long len;
    const char *lockfailaction;
    int writefd;
    struct iovec iov[10];
    int niov;
    struct stat sbuf;
    struct buf keybuf = BUF_INITIALIZER;
    struct buf databuf = BUF_INITIALIZER;

    /* lock file, if needed */
    if (!mytid || !*mytid) {
        r = lock_reopen(db->fd, db->fname, &sbuf, &lockfailaction);
        if (r < 0) {
            syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, db->fname);
            return CYRUSDB_IOERROR;
        }

        if (sbuf.st_ino != db->ino) {
            db->ino = sbuf.st_ino;
            map_free(&db->base, &db->len);
            map_refresh(db->fd, 0, &db->base, &db->len,
                        sbuf.st_size, db->fname, 0);
            db->size = sbuf.st_size;
        }

        if (mytid) {
            *mytid = new_txn();
        }
    }

    encode(key, keylen, &keybuf);

    /* find entry, if it exists */
    offset = bsearch_mem_mbox(keybuf.s, db->base, db->size, 0, &len);

    /* overwrite? */
    if (len && !overwrite) {
        if (mytid) abort_txn(db, *mytid);
        buf_free(&keybuf);
        buf_free(&databuf);
        return CYRUSDB_EXISTS;
    }

    /* write new file */
    if (mytid && (*mytid)->fnamenew) {
        strlcpy(fnamebuf, (*mytid)->fnamenew, sizeof(fnamebuf));
    } else {
        strlcpy(fnamebuf, db->fname, sizeof(fnamebuf));
        strlcat(fnamebuf, ".NEW", sizeof(fnamebuf));
    }

    unlink(fnamebuf);
    r = writefd = open(fnamebuf, O_RDWR | O_CREAT, 0666);
    if (r < 0) {
        syslog(LOG_ERR, "opening %s for writing failed: %m", fnamebuf);
        if (mytid) abort_txn(db, *mytid);
        buf_free(&keybuf);
        buf_free(&databuf);
        return CYRUSDB_IOERROR;
    }

    niov = 0;
    if (offset) {
        WRITEV_ADD_TO_IOVEC(iov, niov, (char *) db->base, offset);
    }

    if (data) {
        /* new entry */
        encode(data, datalen, &databuf);
        WRITEV_ADD_TO_IOVEC(iov, niov, keybuf.s, keybuf.len);
        WRITEV_ADD_TO_IOVEC(iov, niov, "\t", 1);
        WRITEV_ADD_TO_IOVEC(iov, niov, databuf.s, databuf.len);
        WRITEV_ADD_TO_IOVEC(iov, niov, "\n", 1);
    }

    if (db->size - (offset + len) > 0) {
        WRITEV_ADD_TO_IOVEC(iov, niov, (char *) db->base + offset + len,
                            db->size - (offset + len));
    }

    /* do the write */
    r = retry_writev(writefd, iov, niov);
    if (r == -1) {
        syslog(LOG_ERR, "IOERROR: writing %s: %m", fnamebuf);
        close(writefd);
        if (mytid) abort_txn(db, *mytid);
        buf_free(&keybuf);
        buf_free(&databuf);
        return CYRUSDB_IOERROR;
    }
    r = 0;

    if (mytid) {
        /* setup so further accesses will be against fname.NEW */
        if (fstat(writefd, &sbuf) == -1) {
            /* xxx ? */
        }

        if (!(*mytid)->fnamenew) (*mytid)->fnamenew = xstrdup(fnamebuf);
        if ((*mytid)->fd) close((*mytid)->fd);
        (*mytid)->fd = writefd;
        map_free(&db->base, &db->len);
        map_refresh(writefd, 0, &db->base, &db->len, sbuf.st_size,
                    fnamebuf, 0);
        db->size = sbuf.st_size;
    } else {
        /* commit immediately */
        if (fsync(writefd) ||
            fstat(writefd, &sbuf) == -1 ||
            rename(fnamebuf, db->fname) == -1) {
            syslog(LOG_ERR, "IOERROR: writing %s: %m", fnamebuf);
            close(writefd);
            buf_free(&keybuf);
            buf_free(&databuf);
            return CYRUSDB_IOERROR;
        }

        close(db->fd);
        db->fd = writefd;

        /* release lock */
        r = lock_unlock(db->fd, db->fname);
        if (r == -1) {
            syslog(LOG_ERR, "IOERROR: unlocking db %s: %m", db->fname);
            r = CYRUSDB_IOERROR;
        }

        db->ino = sbuf.st_ino;
        map_free(&db->base, &db->len);
        map_refresh(writefd, 0, &db->base, &db->len, sbuf.st_size,
            db->fname, 0);
        db->size = sbuf.st_size;
    }

    buf_free(&keybuf);
    buf_free(&databuf);

    return r;
}
Exemple #11
0
static int foreach(struct dbengine *db,
                   const char *prefix, size_t prefixlen,
                   foreach_p *goodp,
                   foreach_cb *cb, void *rock,
                   struct txn **mytid)
{
    int r = CYRUSDB_OK;
    int offset;
    unsigned long len;
    const char *p, *pend;
    const char *dataend;

    /* for use inside the loop, but we need the values to be retained
     * from loop to loop */
    struct buf keybuf = BUF_INITIALIZER;
    int dontmove = 0;

    /* For when we have a transaction running */
    struct buf savebuf = BUF_INITIALIZER;

    /* for the local iteration so that the db can change out from under us */
    const char *dbbase = NULL;
    size_t dblen = 0;
    int dbfd = -1;

    struct buf prefixbuf = BUF_INITIALIZER;

    r = starttxn_or_refetch(db, mytid);
    if (r) return r;

    if (!mytid) {
        /* No transaction, use the fast method to avoid stomping on our
         * memory map if changes happen */
        dbfd = dup(db->fd);
        if(dbfd == -1) return CYRUSDB_IOERROR;

        map_refresh(dbfd, 1, &dbbase, &dblen, db->size, db->fname, 0);

        /* drop our read lock on the file, since we don't really care
         * if it gets replaced out from under us, our mmap stays on the
         * old version */
        lock_unlock(db->fd, db->fname);
    }
    else {
        /* use the same variables as in the no transaction case, just to
         * get things set up */
        dbbase = db->base;
        dblen = db->len;
    }

    if (prefix) {
        encode(prefix, prefixlen, &prefixbuf);
        offset = bsearch_mem_mbox(prefixbuf.s, dbbase, db->size, 0, &len);
    }
    else {
        offset = 0;
    }

    p = dbbase + offset;
    pend = dbbase + db->size;

    while (p < pend) {
        if (!dontmove) {
            GETENTRY(p)
        }
        else dontmove = 0;

        /* does it still match prefix? */
        if (keybuf.len < (size_t) prefixbuf.len) break;
        if (prefixbuf.len && memcmp(keybuf.s, prefixbuf.s, prefixbuf.len)) break;

        if (!goodp || goodp(rock, keybuf.s, keybuf.len, DATA(db), DATALEN(db))) {
            unsigned long ino = db->ino;
            unsigned long sz = db->size;

            if(mytid) {
                /* transaction present, this means we do the slow way */
                buf_copy(&savebuf, &keybuf);
            }

            /* make callback */
            r = cb(rock, keybuf.s, keybuf.len, DATA(db), DATALEN(db));
            if (r) break;

            if (mytid) {
                /* reposition? (we made a change) */
                if (!(ino == db->ino && sz == db->size)) {
                    /* something changed in the file; reseek */
                    buf_cstring(&savebuf);
                    offset = bsearch_mem_mbox(savebuf.s, db->base, db->size,
                                              0, &len);
                    p = db->base + offset;

                    GETENTRY(p);

                    /* 'key' might not equal 'savebuf'.  if it's different,
                       we want to stay where we are.  if it's the same, we
                       should move on to the next one */
                    if (!buf_cmp(&savebuf, &keybuf)) {
                        p = dataend + 1;
                    }
                    else {
                        /* 'savebuf' got deleted, so we're now pointing at the
                           right thing */
                        dontmove = 1;
                    }
                }
            }
        }

        p = dataend + 1;
    }

    if (!mytid) {
        /* cleanup the fast method */
        map_free(&dbbase, &dblen);
        close(dbfd);
    }

    buf_free(&savebuf);
    buf_free(&keybuf);
    buf_free(&prefixbuf);
    return r;
}
Exemple #12
0
static int starttxn_or_refetch(struct dbengine *db, struct txn **mytid)
{
    int r = 0;
    struct stat sbuf;

    assert(db);

    if (mytid && !*mytid) {
        const char *lockfailaction;

        /* start txn; grab lock */

        r = lock_reopen(db->fd, db->fname, &sbuf, &lockfailaction);
        if (r < 0) {
            syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, db->fname);
            return CYRUSDB_IOERROR;
        }
        *mytid = new_txn();

        if (db->ino != sbuf.st_ino) {
            map_free(&db->base, &db->len);
        }
        map_refresh(db->fd, 0, &db->base, &db->len, sbuf.st_size,
                    db->fname, 0);

        /* we now have the latest & greatest open */
        db->size = sbuf.st_size;
        db->ino = sbuf.st_ino;
    }

    if (!mytid) {
        /* no txn, but let's try to be reasonably up-to-date */

        if (stat(db->fname, &sbuf) == -1) {
            syslog(LOG_ERR, "IOERROR: stating flat %s: %m", db->fname);
            return CYRUSDB_IOERROR;
        }

        if (sbuf.st_ino != db->ino) {
            /* reopen */
            int newfd = open(db->fname, O_RDWR);

            if (newfd == -1) {
                /* fail! */
                syslog(LOG_ERR, "couldn't reopen %s: %m", db->fname);
                return CYRUSDB_IOERROR;
            }
            dup2(newfd, db->fd);
            close(newfd);
            if (stat(db->fname, &sbuf) == -1) {
                syslog(LOG_ERR, "IOERROR: stating flat %s: %m", db->fname);
                return CYRUSDB_IOERROR;
            }

            db->ino = sbuf.st_ino;
            map_free(&db->base, &db->len);
        }
        map_refresh(db->fd, 0, &db->base, &db->len,
                    sbuf.st_size, db->fname, 0);
        db->size = sbuf.st_size;
    }

    return 0;
}
Exemple #13
0
static int _verify_message_cb(const struct backup_message *message, void *rock)
{
    struct verify_message_rock *vmrock = (struct verify_message_rock *) rock;
    struct dlist *dl = NULL;
    struct dlist *di = NULL;
    FILE *out = vmrock->out;
    int r;

    /* cache the dlist so that multiple reads from the same offset don't
     * cause expensive reverse seeks in decompression stream
     */
    if (!vmrock->cached_dlist || vmrock->cached_offset != message->offset) {
        if (vmrock->cached_dlist) {
            dlist_unlink_files(vmrock->cached_dlist);
            dlist_free(&vmrock->cached_dlist);
        }

        r = gzuc_seekto(vmrock->gzuc, message->offset);
        if (r) return r;

        struct protstream *ps = prot_readcb(_prot_fill_cb, vmrock->gzuc);
        prot_setisclient(ps, 1); /* don't sync literals */
        r = parse_backup_line(ps, NULL, NULL, &dl);
        prot_free(ps);

        if (r == EOF) {
            const char *error = prot_error(ps);
            if (error && 0 != strcmp(error, PROT_EOF_STRING)) {
                syslog(LOG_ERR,
                       "%s: error reading message %i at offset %jd, byte %i: %s",
                       __func__, message->id, message->offset, prot_bytes_in(ps), error);
                if (out)
                    fprintf(out, "error reading message %i at offset %jd, byte %i: %s",
                            message->id, message->offset, prot_bytes_in(ps), error);
            }
            return r;
        }

        vmrock->cached_dlist = dl;
        vmrock->cached_offset = message->offset;
    }
    else {
        dl = vmrock->cached_dlist;
    }

    r = strcmp(dl->name, "MESSAGE");
    if (r) return r;

    r = -1;
    for (di = dl->head; di; di = di->next) {
        struct message_guid *guid = NULL;
        const char *fname = NULL;

        if (!dlist_tofile(di, NULL, &guid, NULL, &fname))
            continue;

        r = message_guid_cmp(guid, message->guid);
        if (!r) {
            if (vmrock->verify_guid) {
                const char *msg_base = NULL;
                size_t msg_len = 0;
                struct message_guid computed_guid;
                int fd;

                fd = open(fname, O_RDWR);
                if (fd != -1) {
                    map_refresh(fd, 1, &msg_base, &msg_len, MAP_UNKNOWN_LEN, fname, NULL);

                    message_guid_generate(&computed_guid, msg_base, msg_len);
                    r = message_guid_cmp(&computed_guid, message->guid);
                    if (r && out)
                        fprintf(out, "guid mismatch for message %i\n", message->id);

                    map_free(&msg_base, &msg_len);
                    close(fd);
                }
                else {
                    syslog(LOG_ERR, "IOERROR: %s open %s: %m", __func__, fname);
                    if (out)
                        fprintf(out, "error reading staging file for message %i\n", message->id);
                    r = -1;
                }
            }
            break;
        }
    }

    return r;
}