]> git.pond.sub.org Git - empserver/blob - src/lib/common/file.c
Clean up superfluous includes
[empserver] / src / lib / common / file.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  file.c: Operations on Empire tables (`files' for historical reasons)
28  *
29  *  Known contributors to this file:
30  *     Dave Pare, 1989
31  *     Steve McClure, 2000
32  *     Markus Armbruster, 2005-2011
33  */
34
35 #include <config.h>
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <limits.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 #ifdef _WIN32
44 #include <io.h>
45 #include <share.h>
46 #endif
47 #include "file.h"
48 #include "match.h"
49 #include "misc.h"
50 #include "prototypes.h"
51
52 static int open_locked(char *, int, mode_t);
53 static int ef_realloc_cache(struct empfile *, int);
54 static int fillcache(struct empfile *, int);
55 static int do_read(struct empfile *, void *, int, int);
56 static int do_write(struct empfile *, void *, int, int);
57 static unsigned get_seqno(struct empfile *, int);
58 static void new_seqno(struct empfile *, void *);
59 static void must_be_fresh(struct empfile *, void *);
60 static int do_extend(struct empfile *, int);
61 static void do_blank(struct empfile *, void *, int, int);
62 static int ef_check(int);
63
64 static unsigned ef_generation;
65
66 /*
67  * Open the file-backed table TYPE (EF_SECTOR, ...).
68  * HOW are flags to control operation.  Naturally, immutable flags are
69  * not permitted.
70  * The table must not be already open.
71  * Return non-zero on success, zero on failure.
72  */
73 int
74 ef_open(int type, int how)
75 {
76     struct empfile *ep;
77     int oflags, fd, fsiz, fids, nslots, fail;
78
79     if (ef_check(type) < 0)
80         return 0;
81     if (CANT_HAPPEN(how & EFF_IMMUTABLE))
82         how &= ~EFF_IMMUTABLE;
83
84     /* open file */
85     ep = &empfile[type];
86     if (CANT_HAPPEN(!ep->file || ep->base != EF_BAD || ep->fd >= 0))
87         return 0;
88     oflags = O_RDWR;
89     if (how & EFF_PRIVATE)
90         oflags = O_RDONLY;
91     if (how & EFF_CREATE)
92         oflags |= O_CREAT | O_TRUNC;
93     fd = open_locked(ep->file, oflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
94     if (fd < 0) {
95         logerror("Can't open %s (%s)", ep->file, strerror(errno));
96         return 0;
97     }
98
99     /* get file size */
100     if (how & EFF_CREATE) {
101         fids = ep->nent >= 0 ? ep->nent : 0;
102     } else {
103         fsiz = fsize(fd);
104         if (fsiz % ep->size) {
105             logerror("Can't open %s (file size not a multiple of record size %d)",
106                      ep->file, ep->size);
107             close(fd);
108             return 0;
109         }
110         fids = fsiz / ep->size;
111         if (ep->nent >= 0 && ep->nent != fids) {
112             logerror("Can't open %s (got %d records instead of %d)",
113                      ep->file, fids, ep->nent);
114             close(fd);
115             return 0;
116         }
117     }
118
119     /* allocate cache */
120     if (ep->flags & EFF_STATIC) {
121         /* ep->cache already points to space for ep->csize elements */
122         if (how & EFF_MEM) {
123             if (fids > ep->csize) {
124                 CANT_HAPPEN(ep->nent >= 0); /* insufficient static cache */
125                 logerror("Can't open %s (file larger than %d records)",
126                          ep->file, ep->csize);
127                 close(fd);
128                 return 0;
129             }
130         }
131     } else {
132         if (CANT_HAPPEN(ep->cache))
133             free(ep->cache);
134         if (how & EFF_MEM)
135             nslots = fids;
136         else
137             nslots = blksize(fd) / ep->size;
138         if (!ef_realloc_cache(ep, nslots)) {
139             logerror("Can't map %s (%s)", ep->file, strerror(errno));
140             close(fd);
141             return 0;
142         }
143     }
144     ep->baseid = 0;
145     ep->cids = 0;
146     ep->flags = (ep->flags & EFF_IMMUTABLE) | (how & ~EFF_CREATE);
147     ep->fd = fd;
148
149     if (how & EFF_CREATE) {
150         /* populate new file */
151         ep->fids = 0;
152         fail = !do_extend(ep, fids);
153     } else {
154         ep->fids = fids;
155         if ((how & EFF_MEM) && fids)
156             fail = fillcache(ep, 0) != fids;
157         else
158             fail = 0;
159     }
160     if (fail) {
161         ep->cids = 0;   /* prevent cache flush */
162         ef_close(type);
163         return 0;
164     }
165
166     if (ep->onresize)
167         ep->onresize(type);
168     return 1;
169 }
170
171 static int
172 open_locked(char *name, int oflags, mode_t mode)
173 {
174     int rdlonly = (oflags & O_ACCMODE) == O_RDONLY;
175     int fd;
176
177 #ifdef _WIN32
178     fd = _sopen(name, oflags | O_BINARY, rdlonly ? SH_DENYNO : SH_DENYWR,
179                 mode);
180     if (fd < 0)
181         return -1;
182 #else  /* !_WIN32 */
183     struct flock lock;
184
185     fd = open(name, oflags, mode);
186     if (fd < 0)
187         return -1;
188
189     lock.l_type = rdlonly ? F_RDLCK : F_WRLCK;
190     lock.l_whence = SEEK_SET;
191     lock.l_start = lock.l_len = 0;
192     if (fcntl(fd, F_SETLK, &lock) == -1) {
193         close(fd);
194         return -1;
195     }
196 #endif  /* !_WIN32 */
197     return fd;
198 }
199
200 /*
201  * Reallocate cache for table EP to hold COUNT slots.
202  * The table must not be allocated statically.
203  * The cache may still be unmapped.
204  * If reallocation succeeds, any pointers obtained from ef_ptr()
205  * become invalid.
206  * If it fails, the cache is unchanged, and errno is set.
207  * Return non-zero on success, zero on failure.
208  */
209 static int
210 ef_realloc_cache(struct empfile *ep, int count)
211 {
212     void *cache;
213
214     if (CANT_HAPPEN(ep->flags & EFF_STATIC))
215         return 0;
216     if (CANT_HAPPEN(count < 0))
217         count = 0;
218
219     /*
220      * Avoid zero slots, because that can lead to null cache, which
221      * would be interpreted as unmapped cache.
222      */
223     if (count == 0)
224         count++;
225     cache = realloc(ep->cache, count * ep->size);
226     if (!cache)
227         return 0;
228
229     ep->cache = cache;
230     ep->csize = count;
231     return 1;
232 }
233
234 /*
235  * Open the table TYPE, which is a view of a base table
236  * The table must not be already open.
237  * Return non-zero on success, zero on failure.
238  * Beware: views work only as long as the base table doesn't change size!
239  * You must close the view before closing its base table.
240  */
241 int
242 ef_open_view(int type)
243 {
244     struct empfile *ep;
245     int base;
246
247     if (ef_check(type) < 0)
248         return 0;
249     ep = &empfile[type];
250     base = ep->base;
251     if (ef_check(base) < 0)
252         return 0;
253     if (CANT_HAPPEN(!(ef_flags(base) & EFF_MEM)
254                     || ep->file
255                     || ep->size != empfile[base].size
256                     || ep->nent != empfile[base].nent
257                     || ep->cache || ep->oninit || ep->postread
258                     || ep->prewrite || ep->onresize))
259         return -1;
260
261     ep->cache = empfile[base].cache;
262     ep->csize = empfile[base].csize;
263     ep->flags |= EFF_MEM;
264     ep->baseid = empfile[base].baseid;
265     ep->cids = empfile[base].cids;
266     ep->fids = empfile[base].fids;
267     return 0;
268 }
269
270 /*
271  * Close the open table TYPE (EF_SECTOR, ...).
272  * Return non-zero on success, zero on failure.
273  */
274 int
275 ef_close(int type)
276 {
277     struct empfile *ep;
278     int retval = 1;
279
280     if (ef_check(type) < 0)
281         return 0;
282     ep = &empfile[type];
283
284     if (EF_IS_VIEW(type)) {
285         ep->cache = NULL;
286         ep->csize = 0;
287     } else {
288         if (!ef_flush(type))
289             retval = 0;
290         if (!(ep->flags & EFF_STATIC)) {
291             free(ep->cache);
292             ep->cache = NULL;
293             ep->csize = 0;
294         }
295         if (close(ep->fd) < 0) {
296             logerror("Error closing %s (%s)", ep->file, strerror(errno));
297             retval = 0;
298         }
299         ep->fd = -1;
300     }
301     ep->flags &= EFF_IMMUTABLE;
302     ep->baseid = ep->cids = ep->fids = 0;
303     if (ep->onresize)
304         ep->onresize(type);
305     return retval;
306 }
307
308 /*
309  * Flush file-backed table TYPE (EF_SECTOR, ...) to its backing file.
310  * Do nothing if the table is privately mapped.
311  * Update timestamps of written elements if table is EFF_TYPED.
312  * Return non-zero on success, zero on failure.
313  */
314 int
315 ef_flush(int type)
316 {
317     struct empfile *ep;
318
319     if (ef_check(type) < 0)
320         return 0;
321     ep = &empfile[type];
322     if (ep->flags & EFF_PRIVATE)
323         return 1;               /* nothing to do */
324     if (CANT_HAPPEN(ep->fd < 0))
325         return 0;
326     /*
327      * We don't know which cache entries are dirty.  ef_write() writes
328      * through, but direct updates through ef_ptr() don't.  They are
329      * allowed only with EFF_MEM.  Assume the whole cash is dirty
330      * then.
331      */
332     if (ep->flags & EFF_MEM) {
333         if (do_write(ep, ep->cache, ep->baseid, ep->cids) < 0)
334             return 0;
335     }
336
337     return 1;
338 }
339
340 /*
341  * Return pointer to element ID in table TYPE if it exists, else NULL.
342  * The table must be fully cached, i.e. flags & EFF_MEM.
343  * The caller is responsible for flushing changes he makes.
344  */
345 void *
346 ef_ptr(int type, int id)
347 {
348     struct empfile *ep;
349
350     if (ef_check(type) < 0)
351         return NULL;
352     ep = &empfile[type];
353     if (CANT_HAPPEN(!(ep->flags & EFF_MEM) || !ep->cache))
354         return NULL;
355     if (id < 0 || id >= ep->fids)
356         return NULL;
357     return ep->cache + ep->size * id;
358 }
359
360 /*
361  * Read element ID from table TYPE into buffer INTO.
362  * FIXME pass buffer size!
363  * INTO is marked fresh with ef_mark_fresh().
364  * Return non-zero on success, zero on failure.
365  */
366 int
367 ef_read(int type, int id, void *into)
368 {
369     struct empfile *ep;
370     void *cachep;
371
372     if (ef_check(type) < 0)
373         return 0;
374     ep = &empfile[type];
375     if (CANT_HAPPEN(!ep->cache))
376         return 0;
377     if (id < 0 || id >= ep->fids)
378         return 0;
379
380     if (ep->flags & EFF_MEM) {
381         cachep = ep->cache + id * ep->size;
382     } else {
383         if (ep->baseid + ep->cids <= id || ep->baseid > id) {
384             if (fillcache(ep, id) < 1)
385                 return 0;
386         }
387         cachep = ep->cache + (id - ep->baseid) * ep->size;
388     }
389     memcpy(into, cachep, ep->size);
390     ef_mark_fresh(type, into);
391
392     if (ep->postread)
393         ep->postread(id, into);
394     return 1;
395 }
396
397 /*
398  * Fill cache of file-backed EP with elements starting at ID.
399  * If any were read, return their number.
400  * Else return -1 and leave the cache unchanged.
401  */
402 static int
403 fillcache(struct empfile *ep, int id)
404 {
405     int ret;
406
407     if (CANT_HAPPEN(!ep->cache))
408         return -1;
409
410     ret = do_read(ep, ep->cache, id, MIN(ep->csize, ep->fids - id));
411     if (ret >= 0) {
412         /* cache changed */
413         ep->baseid = id;
414         ep->cids = ret;
415     }
416     return ret;
417 }
418
419 static int
420 do_read(struct empfile *ep, void *buf, int id, int count)
421 {
422     int n, ret;
423     char *p;
424
425     if (CANT_HAPPEN(ep->fd < 0 || id < 0 || count < 0))
426         return -1;
427
428     if (lseek(ep->fd, id * ep->size, SEEK_SET) == (off_t)-1) {
429         logerror("Error seeking %s to elt %d (%s)",
430                  ep->file, id, strerror(errno));
431         return -1;
432     }
433
434     p = buf;
435     n = count * ep->size;
436     while (n > 0) {
437         ret = read(ep->fd, p, n);
438         if (ret < 0) {
439             if (errno != EINTR) {
440                 logerror("Error reading %s elt %d (%s)",
441                          ep->file,
442                          id + (int)((p - (char *)buf) / ep->size),
443                          strerror(errno));
444                 break;
445             }
446         } else if (ret == 0) {
447             logerror("Unexpected EOF reading %s elt %d",
448                      ep->file, id + (int)((p - (char *)buf) / ep->size));
449             break;
450         } else {
451             p += ret;
452             n -= ret;
453         }
454     }
455
456     return (p - (char *)buf) / ep->size;
457 }
458
459 /*
460  * Write COUNT elements starting at ID from BUF to file-backed EP.
461  * Update the timestamp if the table is EFF_TYPED.
462  * Don't actually write if table is privately mapped.
463  * Return 0 on success, -1 on error (file may be corrupt then).
464  */
465 static int
466 do_write(struct empfile *ep, void *buf, int id, int count)
467 {
468     int i, n, ret;
469     char *p;
470     struct emptypedstr *elt;
471     time_t now;
472
473     if (CANT_HAPPEN(ep->fd < 0 || id < 0 || count < 0))
474         return -1;
475
476     if (ep->flags & EFF_TYPED) {
477         now = ep->flags & EFF_NOTIME ? (time_t)-1 : time(NULL);
478         for (i = 0; i < count; i++) {
479             /*
480              * TODO Oopses here could be due to bad data corruption.
481              * Fail instead of attempting to recover?
482              */
483             elt = (struct emptypedstr *)((char *)buf + i * ep->size);
484             if (CANT_HAPPEN(elt->ef_type != ep->uid))
485                 elt->ef_type = ep->uid;
486             if (CANT_HAPPEN(elt->uid != id + i))
487                 elt->uid = id + i;
488             if (now != (time_t)-1)
489                 elt->timestamp = now;
490         }
491     }
492
493     if (ep->flags & EFF_PRIVATE)
494         return 0;
495
496     if (lseek(ep->fd, id * ep->size, SEEK_SET) == (off_t)-1) {
497         logerror("Error seeking %s to elt %d (%s)",
498                  ep->file, id, strerror(errno));
499         return -1;
500     }
501
502     p = buf;
503     n = count * ep->size;
504     while (n > 0) {
505         ret = write(ep->fd, p, n);
506         if (ret < 0) {
507             if (errno != EINTR) {
508                 logerror("Error writing %s elt %d (%s)",
509                          ep->file,
510                          id + (int)((p - (char *)buf) / ep->size),
511                          strerror(errno));
512                 return -1;
513             }
514         } else {
515             p += ret;
516             n -= ret;
517         }
518     }
519
520     return 0;
521 }
522
523 /*
524  * Write element ID into table TYPE from buffer FROM.
525  * FIXME pass buffer size!
526  * Update timestamp in FROM if table is EFF_TYPED.
527  * If table is file-backed and not privately mapped, write through
528  * cache straight to disk.
529  * Cannot write beyond the end of fully cached table (flags & EFF_MEM).
530  * Can write at the end of partially cached table.
531  * FROM must be fresh; see ef_make_stale().
532  * Return non-zero on success, zero on failure.
533  */
534 int
535 ef_write(int type, int id, void *from)
536 {
537     struct empfile *ep;
538     char *cachep;
539
540     if (ef_check(type) < 0)
541         return 0;
542     ep = &empfile[type];
543     if (CANT_HAPPEN((ep->flags & (EFF_MEM | EFF_PRIVATE)) == EFF_PRIVATE))
544         return 0;
545     if (CANT_HAPPEN(ep->nent >= 0 && id >= ep->nent))
546         return 0;               /* beyond fixed size */
547     new_seqno(ep, from);
548     if (id >= ep->fids) {
549         /* beyond end of file */
550         if (CANT_HAPPEN((ep->flags & EFF_MEM) || id > ep->fids))
551             return 0;           /* not implemented */
552         /* write at end of file extends it */
553         ep->fids = id + 1;
554         if (ep->onresize)
555             ep->onresize(type);
556     }
557     if (id >= ep->baseid && id < ep->baseid + ep->cids) {
558         cachep = ep->cache + (id - ep->baseid) * ep->size;
559         if (cachep != from)
560             must_be_fresh(ep, from);
561     } else
562         cachep = NULL;
563     if (ep->prewrite)
564         ep->prewrite(id, cachep, from);
565     if (ep->fd >= 0) {
566         if (do_write(ep, from, id, 1) < 0)
567             return 0;
568     }
569     if (cachep && cachep != from)       /* update the cache if necessary */
570         memcpy(cachep, from, ep->size);
571     return 1;
572 }
573
574 /*
575  * Change element id.
576  * BUF is an element of table TYPE.
577  * ID is its new element ID.
578  * If table is EFF_TYPED, change id and sequence number stored in BUF.
579  * Else do nothing.
580  */
581 void
582 ef_set_uid(int type, void *buf, int uid)
583 {
584     struct emptypedstr *elt;
585     struct empfile *ep;
586
587     if (ef_check(type) < 0)
588         return;
589     ep = &empfile[type];
590     if (!(ep->flags & EFF_TYPED))
591         return;
592     elt = buf;
593     if (elt->uid == uid)
594         return;
595     elt->uid = uid;
596     elt->seqno = get_seqno(ep, uid);
597 }
598
599 /*
600  * Return sequence number of element ID in table EP.
601  * Return zero if table is not EFF_TYPED (it has no sequence number
602  * then).
603  */
604 static unsigned
605 get_seqno(struct empfile *ep, int id)
606 {
607     struct emptypedstr *elt;
608
609     if (!(ep->flags & EFF_TYPED))
610         return 0;
611     if (id < 0 || id >= ep->fids)
612         return 0;
613     if (id >= ep->baseid && id < ep->baseid + ep->cids)
614         elt = (void *)(ep->cache + (id - ep->baseid) * ep->size);
615     else {
616         /* need a buffer, steal last cache slot */
617         if (ep->cids == ep->csize)
618             ep->cids--;
619         elt = (void *)(ep->cache + ep->cids * ep->size);
620         if (do_read(ep, elt, id, 1) < 0)
621             return 0;           /* deep trouble */
622     }
623     return elt->seqno;
624 }
625
626 /*
627  * Increment sequence number in BUF, which is about to be written to EP.
628  * Do nothing if table is not EFF_TYPED (it has no sequence number
629  * then).
630  * Else, BUF's sequence number must match the one in EP's cache.  If
631  * it doesn't, we're about to clobber a previous write.
632  */
633 static void
634 new_seqno(struct empfile *ep, void *buf)
635 {
636     struct emptypedstr *elt = buf;
637     unsigned old_seqno;
638
639     if (!(ep->flags & EFF_TYPED))
640         return;
641     old_seqno = get_seqno(ep, elt->uid);
642     CANT_HAPPEN(old_seqno != elt->seqno);
643     elt->seqno = old_seqno + 1;
644 }
645
646 /*
647  * Make all copies stale.
648  * Only fresh copies may be written back to the cache.
649  * To be called by functions that may yield the processor.
650  * Writing an copy when there has been a yield since it was read is
651  * unsafe, because we could clobber another thread's write then.
652  * Robust code must assume the that any function that may yield does
653  * yield.  Marking copies stale there lets us catch unsafe writes.
654  */
655 void
656 ef_make_stale(void)
657 {
658     ef_generation++;
659 }
660
661 /* Mark copy of an element of table TYPE in BUF fresh.  */
662 void
663 ef_mark_fresh(int type, void *buf)
664 {
665     struct empfile *ep;
666
667     if (ef_check(type) < 0)
668         return;
669     ep = &empfile[type];
670     if (!(ep->flags & EFF_TYPED))
671         return;
672     ((struct emptypedstr *)buf)->generation = ef_generation;
673 }
674
675 static void
676 must_be_fresh(struct empfile *ep, void *buf)
677 {
678     struct emptypedstr *elt = buf;
679
680     if (!(ep->flags & EFF_TYPED))
681         return;
682     CANT_HAPPEN(elt->generation != (ef_generation & 0xfff));
683 }
684
685 /*
686  * Extend table TYPE by COUNT elements.
687  * Any pointers obtained from ef_ptr() become invalid.
688  * Return non-zero on success, zero on failure.
689  */
690 int
691 ef_extend(int type, int count)
692 {
693     struct empfile *ep;
694
695     if (ef_check(type) < 0)
696         return 0;
697     ep = &empfile[type];
698     if (ep->nent >= 0) {
699         logerror("Can't extend %s, its size is fixed", ep->name);
700         return 0;
701     }
702     if (!do_extend(ep, count))
703         return 0;
704     if (ep->onresize)
705         ep->onresize(type);
706     return 1;
707 }
708
709 static int
710 do_extend(struct empfile *ep, int count)
711 {
712     char *p;
713     int need_sentinel, i, id;
714
715     if (CANT_HAPPEN(EF_IS_VIEW(ep->uid)) || count < 0)
716         return 0;
717
718     id = ep->fids;
719     if (ep->flags & EFF_MEM) {
720         need_sentinel = (ep->flags & EFF_SENTINEL) != 0;
721         if (id + count + need_sentinel > ep->csize) {
722             if (ep->flags & EFF_STATIC) {
723                 logerror("Can't extend %s beyond %d elements",
724                          ep->name, ep->csize - need_sentinel);
725                 return 0;
726             }
727             if (!ef_realloc_cache(ep, id + count + need_sentinel)) {
728                 logerror("Can't extend %s to %d elements (%s)",
729                          ep->name, id + count, strerror(errno));
730                 return 0;
731             }
732         }
733         p = ep->cache + id * ep->size;
734         do_blank(ep, p, id, count);
735         if (ep->fd >= 0) {
736             if (do_write(ep, p, id, count) < 0)
737                 return 0;
738         }
739         if (need_sentinel)
740             memset(ep->cache + (id + count) * ep->size, 0, ep->size);
741         ep->cids = id + count;
742     } else {
743         /* need a buffer, steal last cache slot */
744         if (ep->cids == ep->csize)
745             ep->cids--;
746         p = ep->cache + ep->cids * ep->size;
747         for (i = 0; i < count; i++) {
748             do_blank(ep, p, id + i, 1);
749             if (do_write(ep, p, id + i, 1) < 0)
750                 return 0;
751         }
752     }
753     ep->fids = id + count;
754     return 1;
755 }
756
757 /*
758  * Initialize element ID for table TYPE in BUF.
759  * FIXME pass buffer size!
760  * BUF is marked fresh with ef_mark_fresh().
761  */
762 void
763 ef_blank(int type, int id, void *buf)
764 {
765     struct empfile *ep;
766     struct emptypedstr *elt;
767
768     if (ef_check(type) < 0)
769         return;
770     ep = &empfile[type];
771     do_blank(ep, buf, id, 1);
772     if (ep->flags & EFF_TYPED) {
773         elt = buf;
774         elt->seqno = get_seqno(ep, elt->uid);
775     }
776     ef_mark_fresh(type, buf);
777 }
778
779 /*
780  * Initialize COUNT elements of EP in BUF, starting with element ID.
781  */
782 static void
783 do_blank(struct empfile *ep, void *buf, int id, int count)
784 {
785     int i;
786     struct emptypedstr *elt;
787
788     memset(buf, 0, count * ep->size);
789     for (i = 0; i < count; i++) {
790         elt = (struct emptypedstr *)((char *)buf + i * ep->size);
791         if (ep->flags & EFF_TYPED) {
792             elt->ef_type = ep->uid;
793             elt->uid = id + i;
794         }
795         if (ep->oninit)
796             ep->oninit(elt);
797     }
798 }
799
800 /*
801  * Truncate table TYPE to COUNT elements.
802  * Any pointers obtained from ef_ptr() become invalid.
803  * Return non-zero on success, zero on failure.
804  */
805 int
806 ef_truncate(int type, int count)
807 {
808     struct empfile *ep;
809     int need_sentinel;
810
811     if (ef_check(type) < 0 || CANT_HAPPEN(EF_IS_VIEW(type)))
812         return 0;
813     ep = &empfile[type];
814     if (ep->nent >= 0) {
815         logerror("Can't truncate %s, its size is fixed", ep->name);
816         return 0;
817     }
818     if (CANT_HAPPEN(count < 0 || count > ep->fids))
819         return 0;
820
821     if (ep->fd >= 0 && !(ep->flags & EFF_PRIVATE)) {
822         if (ftruncate(ep->fd, count * ep->size) < 0) {
823             logerror("Can't truncate %s to %d elements (%s)",
824                      ep->file, count, strerror(errno));
825             return 0;
826         }
827     }
828     ep->fids = count;
829
830     if (ep->flags & EFF_MEM) {
831         need_sentinel = (ep->flags & EFF_SENTINEL) != 0;
832         if (!(ep->flags & EFF_STATIC)) {
833             if (!ef_realloc_cache(ep, count + need_sentinel)) {
834                 logerror("Can't shrink %s cache after truncate (%s)",
835                          ep->name, strerror(errno));
836                 /* continue with unshrunk cache */
837             }
838         }
839         if (need_sentinel)
840             memset(ep->cache + count * ep->size, 0, ep->size);
841         ep->cids = count;
842     } else {
843         if (ep->baseid >= count)
844             ep->cids = 0;
845         else if (ep->cids > count - ep->baseid)
846             ep->cids = count - ep->baseid;
847     }
848
849     if (ep->onresize)
850         ep->onresize(type);
851     return 1;
852 }
853
854 struct castr *
855 ef_cadef(int type)
856 {
857     if (ef_check(type) < 0)
858         return NULL;
859     return empfile[type].cadef;
860 }
861
862 int
863 ef_nelem(int type)
864 {
865     if (ef_check(type) < 0)
866         return 0;
867     return empfile[type].fids;
868 }
869
870 int
871 ef_flags(int type)
872 {
873     if (ef_check(type) < 0)
874         return 0;
875     return empfile[type].flags;
876 }
877
878 time_t
879 ef_mtime(int type)
880 {
881     if (ef_check(type) < 0)
882         return 0;
883     if (empfile[type].fd <= 0)
884         return 0;
885     return fdate(empfile[type].fd);
886 }
887
888 /*
889  * Search for a table matching NAME, return its table type.
890  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
891  * several.
892  */
893 int
894 ef_byname(char *name)
895 {
896     return stmtch(name, empfile, offsetof(struct empfile, name),
897                   sizeof(empfile[0]));
898 }
899
900 /*
901  * Search CHOICES[] for a table type matching NAME, return it.
902  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
903  * several.
904  * CHOICES[] must be terminated with a negative value.
905  */
906 int
907 ef_byname_from(char *name, int choices[])
908 {
909     int res;
910     int *p;
911
912     res = M_NOTFOUND;
913     for (p = choices; *p >= 0; p++) {
914         if (ef_check(*p) < 0)
915             continue;
916         switch (mineq(name, empfile[*p].name)) {
917         case ME_MISMATCH:
918             break;
919         case ME_PARTIAL:
920             if (res >= 0)
921                 return M_NOTUNIQUE;
922             res = *p;
923             break;
924         case ME_EXACT:
925             return *p;
926         }
927     }
928     return res;
929 }
930
931 char *
932 ef_nameof(int type)
933 {
934     if (ef_check(type) < 0)
935         return "bad ef_type";
936     return empfile[type].name;
937 }
938
939 static int
940 ef_check(int type)
941 {
942     if (CANT_HAPPEN((unsigned)type >= EF_MAX))
943         return -1;
944     return 0;
945 }
946
947 /*
948  * Ensure table contains element ID.
949  * If necessary, extend it in steps of COUNT elements.
950  * Return non-zero on success, zero on failure.
951  */
952 int
953 ef_ensure_space(int type, int id, int count)
954 {
955     if (ef_check(type) < 0)
956         return 0;
957     CANT_HAPPEN(id < 0);
958
959     while (id >= empfile[type].fids) {
960         if (!ef_extend(type, count))
961             return 0;
962     }
963     return 1;
964 }
965
966 /*
967  * Return maximum ID acceptable for table TYPE.
968  * Assuming infinite memory and disk space.
969  */
970 int
971 ef_id_limit(int type)
972 {
973     struct empfile *ep;
974
975     if (ef_check(type) < 0)
976         return -1;
977     ep = &empfile[type];
978     if (ep->nent >= 0)
979         return ep->nent - 1;
980     if (ep->flags & EFF_MEM) {
981         if (ep->flags & EFF_STATIC)
982             return ep->csize - 1 - ((ep->flags & EFF_SENTINEL) != 0);
983     }
984     return INT_MAX;
985 }