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