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; }
/** * 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); }
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); }
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; }
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)); }
/* 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; }
/* * 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); }
/* 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); }
/* 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; } }
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; }
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; }
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; }
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; }