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