]> git.pond.sub.org Git - empserver/blob - src/lib/common/file.c
Check argument of ef_cadef(), ef_nelem(), ef_flags(), ef_mtime()
[empserver] / src / lib / common / file.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program 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 2 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, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  file.c: Operations on Empire tables (`files' for historical reasons)
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1989
32  *     Steve McClure, 2000
33  *     Markus Armbruster, 2005-2008
34  */
35
36 #include <config.h>
37
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 #include "file.h"
44 #include "match.h"
45 #include "misc.h"
46 #include "nsc.h"
47 #include "prototypes.h"
48
49 static int ef_realloc_cache(struct empfile *, int);
50 static int fillcache(struct empfile *, int);
51 static int do_read(struct empfile *, void *, int, int);
52 static int do_write(struct empfile *, void *, int, int);
53 static unsigned get_seqno(struct empfile *, int);
54 static void new_seqno(struct empfile *, void *);
55 static void do_blank(struct empfile *, void *, int, int);
56 static int ef_check(int);
57
58 /*
59  * Open the file-backed table TYPE (EF_SECTOR, ...).
60  * HOW are flags to control operation.  Naturally, immutable flags are
61  * not permitted.
62  * If NELT is non-negative, the table must have that many elements.
63  * Return non-zero on success, zero on failure.
64  * You must call ef_close() before the next ef_open().
65  */
66 int
67 ef_open(int type, int how, int nelt)
68 {
69     struct empfile *ep;
70     struct flock lock;
71     int oflags, fd, fsiz, nslots;
72
73     if (ef_check(type) < 0)
74         return 0;
75     if (CANT_HAPPEN(how & EFF_IMMUTABLE))
76         how &= ~EFF_IMMUTABLE;
77
78     /* open file */
79     ep = &empfile[type];
80     if (CANT_HAPPEN(ep->fd >= 0))
81         return 0;
82     oflags = O_RDWR;
83     if (how & EFF_PRIVATE)
84         oflags = O_RDONLY;
85     if (how & EFF_CREATE)
86         oflags |= O_CREAT | O_TRUNC;
87 #if defined(_WIN32)
88     oflags |= O_BINARY;
89 #endif
90     if ((fd = open(ep->file, oflags, S_IRWUG)) < 0) {
91         logerror("Can't open %s (%s)", ep->file, strerror(errno));
92         return 0;
93     }
94
95     lock.l_type = how & EFF_PRIVATE ? F_RDLCK : F_WRLCK;
96     lock.l_whence = SEEK_SET;
97     lock.l_start = lock.l_len = 0;
98     if (fcntl(fd, F_SETLK, &lock) == -1) {
99         logerror("Can't lock %s (%s)", ep->file, strerror(errno));
100         close(fd);
101         return 0;
102     }
103
104     /* get file size */
105     fsiz = fsize(fd);
106     if (fsiz % ep->size) {
107         logerror("Can't open %s (file size not a multiple of record size %d)",
108                  ep->file, ep->size);
109         close(fd);
110         return 0;
111     }
112     ep->fids = fsiz / ep->size;
113     if (nelt >= 0 && nelt != ep->fids) {
114         logerror("Can't open %s (got %d records instead of %d)",
115                  ep->file, ep->fids, nelt);
116         close(fd);
117         return 0;
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 (ep->fids > ep->csize) {
125                 logerror("Can't open %s: file larger than %d bytes",
126                          ep->file, ep->fids * ep->size);
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 = ep->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     /* map file into cache */
150     if ((how & EFF_MEM) && ep->fids) {
151         if (fillcache(ep, 0) != ep->fids) {
152             ep->cids = 0;       /* prevent cache flush */
153             ep->flags &= EFF_IMMUTABLE; /* maintain invariant */
154             ef_close(type);
155             return 0;
156         }
157     }
158
159     return 1;
160 }
161
162 /*
163  * Reallocate cache for table EP to hold COUNT slots.
164  * The table must not be allocated statically.
165  * The cache may still be unmapped.
166  * If reallocation succeeds, any pointers obtained from ef_ptr()
167  * become invalid.
168  * If it fails, the cache is unchanged, and errno is set.
169  * Return non-zero on success, zero on failure.
170  */
171 static int
172 ef_realloc_cache(struct empfile *ep, int count)
173 {
174     void *cache;
175
176     if (CANT_HAPPEN(ep->flags & EFF_STATIC))
177         return 0;
178     if (CANT_HAPPEN(count < 0))
179         count = 0;
180
181     /*
182      * Avoid zero slots, because that can lead to null cache, which
183      * would be interpreted as unmapped cache.
184      */
185     if (count == 0)
186         count++;
187     cache = realloc(ep->cache, count * ep->size);
188     if (!cache)
189         return 0;
190
191     ep->cache = cache;
192     ep->csize = count;
193     return 1;
194 }
195
196 /*
197  * Close the file-backed table TYPE (EF_SECTOR, ...).
198  * Return non-zero on success, zero on failure.
199  */
200 int
201 ef_close(int type)
202 {
203     struct empfile *ep;
204     int retval;
205
206     retval = ef_flush(type);
207     ep = &empfile[type];
208     ep->flags &= EFF_IMMUTABLE;
209     if (!(ep->flags & EFF_STATIC)) {
210         free(ep->cache);
211         ep->cache = NULL;
212     }
213     if (close(ep->fd) < 0) {
214         logerror("Error closing %s (%s)", ep->file, strerror(errno));
215         retval = 0;
216     }
217     ep->fd = -1;
218     return retval;
219 }
220
221 /*
222  * Flush table TYPE (EF_SECTOR, ...) to disk.
223  * Do nothing if the table is privately mapped.
224  * Update timestamps of written elements if table is EFF_TYPED.
225  * Return non-zero on success, zero on failure.
226  */
227 int
228 ef_flush(int type)
229 {
230     struct empfile *ep;
231
232     if (ef_check(type) < 0)
233         return 0;
234     ep = &empfile[type];
235     if (ep->flags & EFF_PRIVATE)
236         return 1;               /* nothing to do */
237     if (CANT_HAPPEN(ep->fd < 0))
238         return 0;
239     /*
240      * We don't know which cache entries are dirty.  ef_write() writes
241      * through, but direct updates through ef_ptr() don't.  They are
242      * allowed only with EFF_MEM.  Assume the whole cash is dirty
243      * then.
244      */
245     if (ep->flags & EFF_MEM) {
246         if (do_write(ep, ep->cache, ep->baseid, ep->cids) < 0)
247             return 0;
248     }
249
250     return 1;
251 }
252
253 /*
254  * Return pointer to element ID in table TYPE if it exists, else NULL.
255  * The table must be fully cached, i.e. flags & EFF_MEM.
256  * The caller is responsible for flushing changes he makes.
257  */
258 void *
259 ef_ptr(int type, int id)
260 {
261     struct empfile *ep;
262
263     if (ef_check(type) < 0)
264         return NULL;
265     ep = &empfile[type];
266     if (CANT_HAPPEN(!(ep->flags & EFF_MEM) || !ep->cache))
267         return NULL;
268     if (id < 0 || id >= ep->fids)
269         return NULL;
270     return ep->cache + ep->size * id;
271 }
272
273 /*
274  * Read element ID from table TYPE into buffer INTO.
275  * FIXME pass buffer size!
276  * Return non-zero on success, zero on failure.
277  */
278 int
279 ef_read(int type, int id, void *into)
280 {
281     struct empfile *ep;
282     void *from;
283
284     if (ef_check(type) < 0)
285         return 0;
286     ep = &empfile[type];
287     if (CANT_HAPPEN(!ep->cache))
288         return 0;
289     if (id < 0 || id >= ep->fids)
290         return 0;
291
292     if (ep->flags & EFF_MEM) {
293         from = ep->cache + id * ep->size;
294     } else {
295         if (ep->baseid + ep->cids <= id || ep->baseid > id) {
296             if (fillcache(ep, id) < 1)
297                 return 0;
298         }
299         from = ep->cache + (id - ep->baseid) * ep->size;
300     }
301     memcpy(into, from, ep->size);
302
303     if (ep->postread)
304         ep->postread(id, into);
305     return 1;
306 }
307
308 /*
309  * Fill cache of file-backed EP with elements starting at ID.
310  * If any were read, return their number.
311  * Else return -1 and leave the cache unchanged.
312  */
313 static int
314 fillcache(struct empfile *ep, int id)
315 {
316     int ret;
317
318     if (CANT_HAPPEN(!ep->cache))
319         return -1;
320
321     ret = do_read(ep, ep->cache, id, MIN(ep->csize, ep->fids - id));
322     if (ret >= 0) {
323         /* cache changed */
324         ep->baseid = id;
325         ep->cids = ret;
326     }
327     return ret;
328 }
329
330 static int
331 do_read(struct empfile *ep, void *buf, int id, int count)
332 {
333     int n, ret;
334     char *p;
335
336     if (CANT_HAPPEN(ep->fd < 0 || id < 0 || count < 0))
337         return -1;
338
339     if (lseek(ep->fd, id * ep->size, SEEK_SET) == (off_t)-1) {
340         logerror("Error seeking %s to elt %d (%s)",
341                  ep->file, id, strerror(errno));
342         return -1;
343     }
344
345     p = buf;
346     n = count * ep->size;
347     while (n > 0) {
348         ret = read(ep->fd, p, n);
349         if (ret < 0) {
350             if (errno != EINTR) {
351                 logerror("Error reading %s elt %d (%s)",
352                          ep->file,
353                          id + (int)((p - (char *)buf) / ep->size),
354                          strerror(errno));
355                 break;
356             }
357         } else if (ret == 0) {
358             logerror("Unexpected EOF reading %s elt %d",
359                      ep->file, id + (int)((p - (char *)buf) / ep->size));
360             break;
361         } else {
362             p += ret;
363             n -= ret;
364         }
365     }
366
367     return (p - (char *)buf) / ep->size;
368 }
369
370 /*
371  * Write COUNT elements starting at ID from BUF to file-backed EP.
372  * Update the timestamp if the table is EFF_TYPED.
373  * Don't actually write if table is privately mapped.
374  * Return 0 on success, -1 on error (file may be corrupt then).
375  */
376 static int
377 do_write(struct empfile *ep, void *buf, int id, int count)
378 {
379     int i, n, ret;
380     char *p;
381     struct emptypedstr *elt;
382     time_t now;
383
384     if (CANT_HAPPEN(ep->fd < 0 || id < 0 || count < 0))
385         return -1;
386
387     if (ep->flags & EFF_TYPED) {
388         now = ep->flags & EFF_NOTIME ? (time_t)-1 : time(NULL);
389         for (i = 0; i < count; i++) {
390             /*
391              * TODO Oopses here could be due to bad data corruption.
392              * Fail instead of attempting to recover?
393              */
394             elt = (struct emptypedstr *)((char *)buf + i * ep->size);
395             if (CANT_HAPPEN(elt->ef_type != ep->uid))
396                 elt->ef_type = ep->uid;
397             if (CANT_HAPPEN(elt->uid != id + i))
398                 elt->uid = id + i;
399             if (now != (time_t)-1)
400                 elt->timestamp = now;
401         }
402     }
403
404     if (ep->flags & EFF_PRIVATE)
405         return 0;
406
407     if (lseek(ep->fd, id * ep->size, SEEK_SET) == (off_t)-1) {
408         logerror("Error seeking %s to elt %d (%s)",
409                  ep->file, id, strerror(errno));
410         return -1;
411     }
412
413     p = buf;
414     n = count * ep->size;
415     while (n > 0) {
416         ret = write(ep->fd, p, n);
417         if (ret < 0) {
418             if (errno != EINTR) {
419                 logerror("Error writing %s elt %d (%s)",
420                          ep->file,
421                          id + (int)((p - (char *)buf) / ep->size),
422                          strerror(errno));
423                 return -1;
424             }
425         } else {
426             p += ret;
427             n -= ret;
428         }
429     }
430
431     return 0;
432 }
433
434 /*
435  * Write element ID into table TYPE from buffer FROM.
436  * FIXME pass buffer size!
437  * Update timestamp in FROM if table is EFF_TYPED.
438  * If table is file-backed and not privately mapped, write through
439  * cache straight to disk.
440  * Cannot write beyond the end of fully cached table (flags & EFF_MEM).
441  * Can write at the end of partially cached table.
442  * Return non-zero on success, zero on failure.
443  */
444 int
445 ef_write(int type, int id, void *from)
446 {
447     struct empfile *ep;
448     char *to;
449
450     if (ef_check(type) < 0)
451         return 0;
452     ep = &empfile[type];
453     if (CANT_HAPPEN((ep->flags & (EFF_MEM | EFF_PRIVATE)) == EFF_PRIVATE))
454         return 0;
455     if (ep->prewrite)
456         ep->prewrite(id, from);
457     if (CANT_HAPPEN((ep->flags & EFF_MEM) ? id >= ep->fids : id > ep->fids))
458         return 0;               /* not implemented */
459     new_seqno(ep, from);
460     if (ep->fd >= 0) {
461         if (do_write(ep, from, id, 1) < 0)
462             return 0;
463     }
464     if (id >= ep->baseid && id < ep->baseid + ep->cids) {
465         /* update the cache if necessary */
466         to = ep->cache + (id - ep->baseid) * ep->size;
467         if (to != from)
468             memcpy(to, from, ep->size);
469     }
470     if (id >= ep->fids) {
471         /* write beyond end of file extends it, take note */
472         ep->fids = id + 1;
473     }
474     return 1;
475 }
476
477 /*
478  * Change element id.
479  * BUF is an element of table TYPE.
480  * ID is its new element ID.
481  * If table is EFF_TYPED, change id and sequence number stored in BUF.
482  * Else do nothing.
483  */
484 void
485 ef_set_uid(int type, void *buf, int uid)
486 {
487     struct emptypedstr *elt;
488     struct empfile *ep;
489
490     if (ef_check(type) < 0)
491         return;
492     ep = &empfile[type];
493     if (!(ep->flags & EFF_TYPED))
494         return;
495     elt = buf;
496     if (elt->uid == uid)
497         return;
498     elt->uid = uid;
499     elt->seqno = get_seqno(ep, uid);
500 }
501
502 /*
503  * Return sequence number of element ID in table EP.
504  * Return zero if table is not EFF_TYPED (it has no sequence number
505  * then).
506  */
507 static unsigned
508 get_seqno(struct empfile *ep, int id)
509 {
510     struct emptypedstr *elt;
511
512     if (!(ep->flags & EFF_TYPED))
513         return 0;
514     if (id < 0 || id >= ep->fids)
515         return 0;
516     if (id >= ep->baseid && id < ep->baseid + ep->cids)
517         elt = (void *)(ep->cache + (id - ep->baseid) * ep->size);
518     else {
519         /* need a buffer, steal last cache slot */
520         if (ep->cids == ep->csize)
521             ep->cids--;
522         elt = (void *)(ep->cache + ep->cids * ep->size);
523         if (do_read(ep, elt, id, 1) < 0)
524             return 0;           /* deep trouble */
525     }
526     return elt->seqno;
527 }
528
529 /*
530  * Increment sequence number in BUF, which is about to be written to EP.
531  * Do nothing if table is not EFF_TYPED (it has no sequence number
532  * then).
533  */
534 static void
535 new_seqno(struct empfile *ep, void *buf)
536 {
537     struct emptypedstr *elt = buf;
538     unsigned old_seqno;
539
540     if (!(ep->flags & EFF_TYPED))
541         return;
542     old_seqno = get_seqno(ep, elt->uid);
543     if (CANT_HAPPEN(old_seqno != elt->seqno))
544         old_seqno = MAX(old_seqno, elt->seqno);
545     elt->seqno = old_seqno + 1;
546 }
547
548 /*
549  * Extend table TYPE by COUNT elements.
550  * Any pointers obtained from ef_ptr() become invalid.
551  * Return non-zero on success, zero on failure.
552  */
553 int
554 ef_extend(int type, int count)
555 {
556     struct empfile *ep;
557     char *p;
558     int need_sentinel, i, id;
559
560     if (ef_check(type) < 0)
561         return 0;
562     ep = &empfile[type];
563     if (CANT_HAPPEN(count < 0))
564         return 0;
565
566     id = ep->fids;
567     if (ep->flags & EFF_MEM) {
568         need_sentinel = (ep->flags & EFF_SENTINEL) != 0;
569         if (id + count + need_sentinel > ep->csize) {
570             if (ep->flags & EFF_STATIC) {
571                 logerror("Can't extend %s beyond %d elements",
572                          ep->name, ep->csize - need_sentinel);
573                 return 0;
574             }
575             if (!ef_realloc_cache(ep, id + count + need_sentinel)) {
576                 logerror("Can't extend %s to %d elements (%s)",
577                          ep->name, id + count, strerror(errno));
578                 return 0;
579             }
580         }
581         p = ep->cache + id * ep->size;
582         do_blank(ep, p, id, count);
583         if (ep->fd >= 0) {
584             if (do_write(ep, p, id, count) < 0)
585                 return 0;
586         }
587         if (need_sentinel)
588             memset(ep->cache + (id + count) * ep->size, 0, ep->size);
589         ep->cids = id + count;
590     } else {
591         /* need a buffer, steal last cache slot */
592         if (ep->cids == ep->csize)
593             ep->cids--;
594         p = ep->cache + ep->cids * ep->size;
595         for (i = 0; i < count; i++) {
596             do_blank(ep, p, id + i, 1);
597             if (do_write(ep, p, id + i, 1) < 0)
598                 return 0;
599         }
600     }
601     ep->fids = id + count;
602     return 1;
603 }
604
605 /*
606  * Initialize element ID for EP in BUF.
607  * FIXME pass buffer size!
608  */
609 void
610 ef_blank(int type, int id, void *buf)
611 {
612     struct empfile *ep;
613     struct emptypedstr *elt;
614
615     if (ef_check(type) < 0)
616         return;
617     ep = &empfile[type];
618     do_blank(ep, buf, id, 1);
619     if (ep->flags & EFF_TYPED) {
620         elt = buf;
621         elt->seqno = get_seqno(ep, elt->uid);
622     }
623 }
624
625 /*
626  * Initialize COUNT elements of EP in BUF, starting with element ID.
627  */
628 static void
629 do_blank(struct empfile *ep, void *buf, int id, int count)
630 {
631     int i;
632     struct emptypedstr *elt;
633
634     memset(buf, 0, count * ep->size);
635     if (ep->flags & EFF_TYPED) {
636         for (i = 0; i < count; i++) {
637             elt = (struct emptypedstr *)((char *)buf + i * ep->size);
638             elt->ef_type = ep->uid;
639             elt->uid = id + i;
640         }
641     }
642 }
643
644 /*
645  * Truncate table TYPE to COUNT elements.
646  * Any pointers obtained from ef_ptr() become invalid.
647  * Return non-zero on success, zero on failure.
648  */
649 int
650 ef_truncate(int type, int count)
651 {
652     struct empfile *ep;
653     int need_sentinel;
654
655     if (ef_check(type) < 0)
656         return 0;
657     ep = &empfile[type];
658     if (CANT_HAPPEN(count < 0 || count > ep->fids))
659         return 0;
660
661     if (ep->fd >= 0 && !(ep->flags & EFF_PRIVATE)) {
662         if (ftruncate(ep->fd, count * ep->size) < 0) {
663             logerror("Can't truncate %s to %d elements (%s)",
664                      ep->file, count, strerror(errno));
665             return 0;
666         }
667     }
668     ep->fids = count;
669
670     if (ep->flags & EFF_MEM) {
671         need_sentinel = (ep->flags & EFF_SENTINEL) != 0;
672         if (!(ep->flags & EFF_STATIC)) {
673             if (!ef_realloc_cache(ep, count + need_sentinel)) {
674                 logerror("Can't shrink %s cache after truncate (%s)",
675                          ep->name, strerror(errno));
676                 /* continue with unshrunk cache */
677             }
678         }
679         if (need_sentinel)
680             memset(ep->cache + count * ep->size, 0, ep->size);
681         ep->cids = count;
682     } else {
683         if (ep->baseid >= count)
684             ep->cids = 0;
685         else if (ep->cids > count - ep->baseid)
686             ep->cids = count - ep->baseid;
687     }
688
689     return 1;
690 }
691
692 struct castr *
693 ef_cadef(int type)
694 {
695     if (ef_check(type) < 0)
696         return NULL;
697     return empfile[type].cadef;
698 }
699
700 int
701 ef_nelem(int type)
702 {
703     if (ef_check(type) < 0)
704         return 0;
705     return empfile[type].fids;
706 }
707
708 int
709 ef_flags(int type)
710 {
711     if (ef_check(type) < 0)
712         return 0;
713     return empfile[type].flags;
714 }
715
716 time_t
717 ef_mtime(int type)
718 {
719     if (ef_check(type) < 0)
720         return 0;
721     if (empfile[type].fd <= 0)
722         return 0;
723     return fdate(empfile[type].fd);
724 }
725
726 /*
727  * Search for a table matching NAME, return its table type.
728  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
729  * several.
730  */
731 int
732 ef_byname(char *name)
733 {
734     return stmtch(name, empfile, offsetof(struct empfile, name),
735                   sizeof(empfile[0]));
736 }
737
738 /*
739  * Search CHOICES[] for a table type matching NAME, return it.
740  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
741  * several.
742  * CHOICES[] must be terminated with a negative value.
743  */
744 int
745 ef_byname_from(char *name, int choices[])
746 {
747     int res;
748     int *p;
749
750     res = M_NOTFOUND;
751     for (p = choices; *p >= 0; p++) {
752         if (ef_check(*p) < 0)
753             continue;
754         switch (mineq(name, empfile[*p].name)) {
755         case ME_MISMATCH:
756             break;
757         case ME_PARTIAL:
758             if (res >= 0)
759                 return M_NOTUNIQUE;
760             res = *p;
761             break;
762         case ME_EXACT:
763             return *p;
764         }
765     }
766     return res;
767 }
768
769 char *
770 ef_nameof(int type)
771 {
772     if (ef_check(type) < 0)
773         return "bad ef_type";
774     return empfile[type].name;
775 }
776
777 static int
778 ef_check(int type)
779 {
780     if (CANT_HAPPEN((unsigned)type >= EF_MAX))
781         return -1;
782     return 0;
783 }
784
785 /*
786  * Ensure table contains element ID.
787  * If necessary, extend it in steps of COUNT elements.
788  * Return non-zero on success, zero on failure.
789  */
790 int
791 ef_ensure_space(int type, int id, int count)
792 {
793     if (ef_check(type) < 0)
794         return 0;
795     CANT_HAPPEN(id < 0);
796
797     while (id >= empfile[type].fids) {
798         if (!ef_extend(type, count))
799             return 0;
800     }
801     return 1;
802 }