]> git.pond.sub.org Git - empserver/blob - src/lib/common/file.c
(ef_open): Failed to reset empfile member fd on failure, and leaked
[empserver] / src / lib / common / file.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2005, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  file.c: Misc. operations on files
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1989
32  *     Steve McClure, 2000
33  */
34
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #if !defined(_WIN32)
41 #include <unistd.h>
42 #endif
43 #include "misc.h"
44 #include "nsc.h"
45 #include "file.h"
46 #include "common.h"
47 #include "gen.h"
48
49
50 static int fillcache(struct empfile *, int);
51 static int do_write(struct empfile *, void *, int, int);
52
53
54 /*
55  * Open the binary file for table TYPE (EF_SECTOR, ...).
56  * HOW are EFF_OPEN flags to control operation.
57  * Return non-zero on success, zero on failure.
58  * You must call ef_close() before the next ef_open().
59  */
60 int
61 ef_open(int type, int how)
62 {
63     struct empfile *ep;
64     int oflags, fd, fsiz, size;
65
66     if (ef_check(type) < 0)
67         return 0;
68     if (CANT_HAPPEN(how & ~EFF_OPEN))
69         how &= EFF_OPEN;
70     ep = &empfile[type];
71     if (CANT_HAPPEN(ep->fd >= 0))
72         return 0;
73     oflags = O_RDWR;
74     if (how & EFF_RDONLY)
75         oflags = O_RDONLY;
76     if (how & EFF_CREATE)
77         oflags |= O_CREAT | O_TRUNC;
78 #if defined(_WIN32)
79     oflags |= O_BINARY;
80 #endif
81     if ((fd = open(ep->file, oflags, 0660)) < 0) {
82         logerror("Can't open %s (%s)", ep->file, strerror(errno));
83         return 0;
84     }
85     fsiz = fsize(fd);
86     if (fsiz % ep->size) {
87         logerror("Can't open %s (file size not a multiple of record size %d)",
88                  ep->file, ep->size);
89         close(fd);
90         return 0;
91     }
92     ep->fids = fsiz / ep->size;
93     if (how & EFF_MEM)
94         ep->csize = ep->fids;
95     else
96         ep->csize = max(1, blksize(fd) / ep->size);
97     size = ep->csize * ep->size;
98     ep->cache = malloc(size);
99     if (ep->cache == NULL) {
100         logerror("Can't open %s: out of memory", ep->file);
101         close(fd);
102         return 0;
103     }
104     ep->baseid = 0;
105     ep->cids = 0;
106     ep->flags = (ep->flags & ~EFF_OPEN) | (how ^ ~EFF_CREATE);
107     ep->fd = fd;
108     if (how & EFF_MEM) {
109         if (fillcache(ep, 0) != ep->fids) {
110             ep->cids = 0;       /* prevent cache flush */
111             ep->flags &= ~EFF_OPEN; /* maintain invariant */
112             ef_close(type);
113             return 0;
114         }
115     }
116     return 1;
117 }
118
119 /*
120  * Close the file containing objects of the type 'type', flushing the cache
121  * if applicable.
122  */
123 int
124 ef_close(int type)
125 {
126     struct empfile *ep;
127     int retval;
128
129     retval = ef_flush(type);
130     ep = &empfile[type];
131     ep->flags &= ~EFF_OPEN;
132     free(ep->cache);
133     ep->cache = NULL;
134     if (close(ep->fd) < 0) {
135         logerror("Error closing %s (%s)", ep->name, strerror(errno));
136         retval = 0;
137     }
138     ep->fd = -1;
139     return retval;
140 }
141
142 /*
143  * Flush the cache of the file containing objects of type 'type' to disk.
144  */
145 int
146 ef_flush(int type)
147 {
148     struct empfile *ep;
149
150     if (ef_check(type) < 0)
151         return 0;
152     ep = &empfile[type];
153     if (CANT_HAPPEN(ep->fd < 0))
154         return 0;
155     /*
156      * We don't know which cache entries are dirty.  ef_write() writes
157      * through, but direct updates through ef_ptr() don't.  They are
158      * allowed only with EFF_MEM.  Assume the whole cash is dirty
159      * then.
160      */
161     if (!(ep->flags & EFF_RDONLY) && (ep->flags & EFF_MEM))
162         return do_write(ep, ep->cache, ep->baseid, ep->cids) >= 0;
163
164     return 1;
165 }
166
167 /*
168  * Return a pointer the id 'id' of object of type 'type' in the cache.
169  */
170 char *
171 ef_ptr(int type, int id)
172 {
173     struct empfile *ep;
174
175     if (ef_check(type) < 0)
176         return NULL;
177     ep = &empfile[type];
178     if (id < 0 || id >= ep->fids)
179         return NULL;
180     if ((ep->flags & EFF_MEM) == 0) {
181         logerror("ef_ptr: (%s) only valid for EFF_MEM entries", ep->file);
182         return NULL;
183     }
184     return ep->cache + ep->size * id;
185 }
186
187 /*
188  * buffered read.  Tries to read a large number of items.
189  * This system won't work if item size is > sizeof buffer area.
190  */
191 int
192 ef_read(int type, int id, void *into)
193 {
194     struct empfile *ep;
195     void *from;
196
197     if (ef_check(type) < 0)
198         return 0;
199     ep = &empfile[type];
200     if (id < 0)
201         return 0;
202     if (ep->flags & EFF_MEM) {
203         if (id >= ep->fids)
204             return 0;
205         from = ep->cache + (id * ep->size);
206     } else {
207         if (id >= ep->fids) {
208             ep->fids = fsize(ep->fd) / ep->size;
209             if (id >= ep->fids)
210                 return 0;
211         }
212         if (ep->baseid + ep->cids <= id || ep->baseid > id)
213             if (fillcache(ep, id) < 1)
214                 return 0;
215         from = ep->cache + (id - ep->baseid) * ep->size;
216     }
217     memcpy(into, from, ep->size);
218
219     if (ep->postread)
220         ep->postread(id, into);
221     return 1;
222 }
223
224 /*
225  * Fill cache of EP with elements starting at ID.
226  * If any were read, return their number.
227  * Else return -1 and leave the cache unchanged.
228  */
229 static int
230 fillcache(struct empfile *ep, int start)
231 {
232     int n, ret;
233     char *p;
234
235     if (CANT_HAPPEN(ep->fd < 0 || !ep->cache))
236         return -1;
237
238     if (lseek(ep->fd, start * ep->size, SEEK_SET) == (off_t)-1) {
239         logerror("Error seeking %s (%s)", ep->file, strerror(errno));
240         return -1;
241     }
242
243     p = ep->cache;
244     n = ep->csize * ep->size;
245     while (n > 0) {
246         ret = read(ep->fd, p, n);
247         if (ret < 0) {
248             if (errno != EAGAIN) {
249                 logerror("Error reading %s (%s)", ep->file, strerror(errno));
250                 break;
251             }
252         } else if (ret == 0) {
253             break;
254         } else {
255             p += ret;
256             n -= ret;
257         }
258     }
259
260     if (p == ep->cache)
261         return -1;              /* nothing read, old cache still ok */
262
263     ep->baseid = start;
264     ep->cids = (p - ep->cache) / ep->size;
265     return ep->cids;
266 }
267
268 /*
269  * Write COUNT elements from BUF to EP, starting at ID.
270  * Return 0 on success, -1 on error.
271  */
272 static int
273 do_write(struct empfile *ep, void *buf, int id, int count)
274 {
275     int n, ret;
276     char *p;
277
278     if (CANT_HAPPEN(ep->fd < 0 || id < 0 || count < 0))
279         return -1;
280
281     if (lseek(ep->fd, id * ep->size, SEEK_SET) == (off_t)-1) {
282         logerror("Error seeking %s (%s)", ep->file, strerror(errno));
283         return -1;
284     }
285
286     p = buf;
287     n = count * ep->size;
288     while (n > 0) {
289         ret = write(ep->fd, p, n);
290         if (ret < 0) {
291             if (errno != EAGAIN) {
292                 logerror("Error writing %s (%s)", ep->file, strerror(errno));
293                 return -1;
294             }
295         } else {
296             p += ret;
297             n -= ret;
298         }
299     }
300
301     return 0;
302 }
303
304 /*
305  * buffered write.  Modifies read cache (if applicable)
306  * and writes through to disk.
307  */
308 int
309 ef_write(int type, int id, void *from)
310 {
311     struct empfile *ep;
312     char *to;
313
314     if (ef_check(type) < 0)
315         return 0;
316     ep = &empfile[type];
317     if (id > 65536) {
318         /* largest unit id; this may bite us in large games */
319         logerror("ef_write: type %d id %d is too large!\n", type, id);
320         return 0;
321     }
322     if (ep->prewrite)
323         ep->prewrite(id, from);
324     if (CANT_HAPPEN((ep->flags & EFF_MEM) ? id >= ep->fids : id > ep->fids))
325         return 0;               /* not implemented */
326     if (do_write(ep, from, id, 1) < 0)
327         return 0;
328     if (id >= ep->baseid && id < ep->baseid + ep->cids) {
329         /* update the cache if necessary */
330         to = ep->cache + (id - ep->baseid) * ep->size;
331         memcpy(to, from, ep->size);
332     }
333     CANT_HAPPEN(id > ep->fids);
334     if (id >= ep->fids) {
335         /* write beyond end of file extends it, take note */
336         ep->fids = id + 1;
337     }
338     return 1;
339 }
340
341 /*
342  * Grow the file containing objects of the type 'type' by 'count' objects.
343  */
344 int
345 ef_extend(int type, int count)
346 {
347     struct empfile *ep;
348     char *tmpobj;
349     int cur, max;
350     int how;
351     int r;
352
353     if (ef_check(type) < 0)
354         return 0;
355     ep = &empfile[type];
356     max = ep->fids + count;
357     cur = ep->fids;
358     tmpobj = calloc(1, ep->size);
359     if ((r = lseek(ep->fd, ep->fids * ep->size, SEEK_SET)) < 0) {
360         logerror("ef_extend: %s +#%d lseek(%d, %d, SEEK_SET) -> %d",
361                  ep->name, count, ep->fd, ep->fids * ep->size, r);
362         free(tmpobj);
363         return 0;
364     }
365     for (cur = ep->fids; cur < max; cur++) {
366         if (ep->init)
367             ep->init(cur, tmpobj);
368         if ((r = write(ep->fd, tmpobj, ep->size)) != ep->size) {
369             logerror("ef_extend: %s +#%d write(%d, %p, %d) -> %d",
370                      ep->name, count, ep->fd, tmpobj, ep->size, r);
371             free(tmpobj);
372             return 0;
373         }
374     }
375     free(tmpobj);
376     if (ep->flags & EFF_MEM) {
377         /* XXX this will cause problems if there are ef_ptrs (to the
378          * old allocated structure) active when we do the re-open */
379         how = ep->flags;
380         ef_close(type);
381         ef_open(type, how);
382     } else {
383         ep->fids += count;
384     }
385     return 1;
386 }
387
388 /*
389  * Mark the cache for the file containing objects of type 'type' as unused.
390  */
391 void
392 ef_zapcache(int type)
393 {
394     struct empfile *ep = &empfile[type];
395     if ((ep->flags & EFF_MEM) == 0) {
396         ep->cids = 0;
397         ep->baseid = -1;
398     }
399 }
400
401 struct castr *
402 ef_cadef(int type)
403 {
404     return empfile[type].cadef;
405 }
406
407 int
408 ef_nelem(int type)
409 {
410     return empfile[type].fids;
411 }
412
413 int
414 ef_flags(int type)
415 {
416     return empfile[type].flags;
417 }
418
419 time_t
420 ef_mtime(int type)
421 {
422     if (empfile[type].fd <= 0)
423         return 0;
424     return fdate(empfile[type].fd);
425 }
426
427 /*
428  * Search empfile[0..EF_MAX-1] for element named NAME.
429  * Return its index in empfile[] if found, else -1.
430  */
431 int
432 ef_byname(char *name)
433 {
434     struct empfile *ef;
435     int i;
436     int len;
437
438     len = strlen(name);
439     for (i = 0; i < EF_MAX; i++) {
440         ef = &empfile[i];
441         if (strncmp(ef->name, name, min(len, strlen(ef->name))) == 0)
442             return i;
443     }
444     return -1;
445 }
446
447 char *
448 ef_nameof(int type)
449 {
450     if (type < 0 || type >= EF_MAX)
451         return "bad item type";
452     return empfile[type].name;
453 }
454
455 int
456 ef_check(int type)
457 {
458     if (type < 0 || type >= EF_MAX) {
459         logerror("ef_ptr: bad EF_type %d\n", type);
460         return -1;
461     }
462     return 0;
463 }
464
465 int
466 ef_ensure_space(int type, int id, int count)
467 {
468     while (id >= empfile[type].fids) {
469         if (!ef_extend(type, count))
470             return 0;
471     }
472     return 1;
473 }