]> git.pond.sub.org Git - empserver/blob - src/lib/common/file.c
Update copyright notice.
[empserver] / src / lib / common / file.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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 <string.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #if !defined(_WIN32)
40 #include <unistd.h>
41 #endif
42 #include "misc.h"
43 #include "xy.h"
44 #include "nsc.h"
45 #include "file.h"
46 #include "match.h"
47 #include "struct.h"
48 #include "common.h"
49 #include "gen.h"
50
51
52 static void fillcache(struct empfile *ep, int start);
53
54 int
55 ef_open(int type, int mode, int how)
56 {
57     register struct empfile *ep;
58     static int block;
59     int size;
60
61 #if defined(_WIN32)
62     mode |= _O_BINARY;
63 #endif
64     if (ef_check(type) < 0)
65         return 0;
66     ep = &empfile[type];
67     if ((ep->fd = open(ep->file, mode, 0660)) < 0) {
68         logerror("%s: open failed", ep->file);
69         return 0;
70     }
71     if (block == 0)
72         block = blksize(ep->fd);
73     ep->baseid = 0;
74     ep->cids = 0;
75     ep->mode = mode;
76     ep->flags |= how;
77     ep->fids = fsize(ep->fd) / ep->size;
78     if (ep->flags & EFF_MEM)
79         ep->csize = ep->fids;
80     else
81         ep->csize = block / ep->size;
82     size = ep->csize * ep->size;
83     ep->cache = (s_char *)malloc(size);
84     if ((ep->cache == 0) && (size != 0)) {
85         logerror("ef_open: %s malloc(%d) failed\n", ep->file, size);
86         return 0;
87     }
88     if (ep->flags & EFF_MEM) {
89         if (read(ep->fd, ep->cache, size) != size) {
90             logerror("ef_open: read(%s) failed\n", ep->file);
91             return 0;
92         }
93         ep->cids = size / ep->size;
94     }
95     return 1;
96 }
97
98 int
99 ef_close(int type)
100 {
101     register struct empfile *ep;
102     int r;
103
104     if (ef_check(type) < 0)
105         return 0;
106     ep = &empfile[type];
107     if (ep->cache == 0) {
108         /* no cache implies never opened */
109         return 0;
110     }
111     ef_flush(type);
112     ep->flags &= ~EFF_MEM;
113     free(ep->cache);
114     ep->cache = 0;
115     if ((r = close(ep->fd)) < 0) {
116         logerror("ef_close: %s close(%d) -> %d", ep->name, ep->fd, r);
117     }
118     return 1;
119 }
120
121 int
122 ef_flush(int type)
123 {
124     register struct empfile *ep;
125     int size;
126     int r;
127
128     if (ef_check(type) < 0)
129         return 0;
130     ep = &empfile[type];
131     if (ep->cache == 0) {
132         /* no cache implies never opened */
133         return 0;
134     }
135     size = ep->csize * ep->size;
136     if (ep->mode > 0 && (ep->flags & EFF_MEM)) {
137         if ((r = lseek(ep->fd, 0L, 0)) < 0) {
138             logerror("ef_flush: %s cache lseek(%d, 0L, 0) -> %d",
139                      ep->name, ep->fd, r);
140             return 0;
141         }
142         if (write(ep->fd, ep->cache, size) != size) {
143             logerror("ef_flush: %s cache write(%d, %p, %d) -> %d",
144                      ep->name, ep->fd, (void *)ep->cache, ep->size, r);
145             return 0;
146         }
147     }
148     /*ef_zapcache(type); */
149     return 1;
150 }
151
152 s_char *
153 ef_ptr(int type, int id)
154 {
155     register struct empfile *ep;
156
157     if (ef_check(type) < 0)
158         return 0;
159     ep = &empfile[type];
160     if (id < 0 || id >= ep->fids)
161         return 0;
162     if ((ep->flags & EFF_MEM) == 0) {
163         logerror("ef_ptr: (%s) only valid for EFF_MEM entries", ep->file);
164         return 0;
165     }
166     return (s_char *)(ep->cache + ep->size * id);
167 }
168
169 /*
170  * buffered read.  Tries to read a large number of items.
171  * This system won't work if item size is > sizeof buffer area.
172  */
173 int
174 ef_read(int type, int id, void *ptr)
175 {
176     register struct empfile *ep;
177     void *from;
178
179     if (ef_check(type) < 0)
180         return 0;
181     ep = &empfile[type];
182     if (id < 0)
183         return 0;
184     if (ep->flags & EFF_MEM) {
185         if (id >= ep->fids)
186             return 0;
187         from = ep->cache + (id * ep->size);
188     } else {
189         if (id >= ep->fids) {
190             ep->fids = fsize(ep->fd) / ep->size;
191             if (id >= ep->fids)
192                 return 0;
193         }
194         if (ep->baseid + ep->cids <= id || ep->baseid > id)
195             fillcache(ep, id);
196         from = ep->cache + (id - ep->baseid) * ep->size;
197     }
198     memcpy(ptr, from, ep->size);
199
200     if (ep->postread)
201         ep->postread(id, ptr);
202     return 1;
203 }
204
205 static void
206 fillcache(struct empfile *ep, int start)
207 {
208     int n;
209
210     ep->baseid = start;
211     lseek(ep->fd, start * ep->size, 0);
212     n = read(ep->fd, ep->cache, ep->csize * ep->size);
213     ep->cids = n / ep->size;
214 }
215
216 #ifdef notdef
217 /*
218  * no-buffered read
219  * zaps read cache
220  */
221 int
222 ef_nbread(int type, int id, void *ptr)
223 {
224     register struct empfile *ep;
225     int r;
226
227     if (ef_check(type) < 0)
228         return 0;
229     ep = &empfile[type];
230     if (id < 0)
231         return 0;
232     if (id >= ep->fids) {
233         ep->fids = fsize(ep->fd) / ep->size;
234         if (id >= ep->fids)
235             return 0;
236     }
237     if ((r = lseek(ep->fd, id * ep->size, 0)) < 0) {
238         logerror("ef_nbread: %s #%d lseek(%d, %d, 0) -> %d",
239                  ep->name, id, ep->fd, id * ep->size, r);
240         return 0;
241     }
242     if ((r = read(ep->fd, ptr, ep->size)) != ep->size) {
243         logerror("ef_nbread: %s #%d read(%d, %x, %d) -> %d",
244                  ep->name, id, ep->fd, ptr, ep->size, r);
245         return 0;
246     }
247     ef_zapcache(type);
248     if (ep->postread)
249         ep->postread(id, ptr);
250     return 1;
251 }
252 #endif
253
254 /*
255  * buffered write.  Modifies read cache (if applicable)
256  * and writes through to disk.
257  */
258 int
259 ef_write(int type, int id, void *ptr)
260 {
261     register int r;
262     register struct empfile *ep;
263     s_char *to;
264
265     if (ef_check(type) < 0)
266         return 0;
267     ep = &empfile[type];
268     if (id > 65536) {
269         /* largest unit id; this may bite us in large games */
270         logerror("ef_write: type %d id %d is too large!\n", type, id);
271         return 0;
272     }
273     if ((r = lseek(ep->fd, id * ep->size, 0)) < 0) {
274         logerror("ef_write: %s #%d lseek(%d, %d, 0) -> %d",
275                  ep->name, id, ep->fd, id * ep->size, r);
276         return 0;
277     }
278     if (ep->prewrite)
279         ep->prewrite(id, ptr);
280     if ((r = write(ep->fd, ptr, ep->size)) != ep->size) {
281         logerror("ef_write: %s #%d write(%d, %p, %d) -> %d",
282                  ep->name, id, ep->fd, (void *)ptr, ep->size, r);
283         return 0;
284     }
285     if (id >= ep->baseid && id < ep->baseid + ep->cids) {
286         /* update the cache if necessary */
287         to = ep->cache + (id - ep->baseid) * ep->size;
288         memcpy(to, ptr, ep->size);
289     }
290     if (id > ep->fids) {
291         logerror("WARNING ef_write: expanded %s by more than one id",
292                  ep->name);
293         log_last_commands();
294     }
295     if (id >= ep->fids) {
296         if (ep->flags & EFF_MEM) {
297             logerror("file %s went beyond %d items; won't be able toread item w/o restart",
298                      ep->name, ep->fids);
299         } else {
300             /* write expanded file; ep->fids = last id + 1 */
301             ep->fids = id + 1;
302         }
303     }
304     return 1;
305 }
306
307 #ifdef notdef
308 /*
309  * no-buffered write
310  * zaps read cache
311  */
312 int
313 ef_nbwrite(int type, int id, void *ptr)
314 {
315     register struct empfile *ep;
316     register int r;
317
318     if (ef_check(type) < 0)
319         return 0;
320     ep = &empfile[type];
321     if (id > 65536) {
322         /* largest unit id; this may bite us in large games */
323         logerror("ef_nbwrite: %s id %d is too large!\n", ep->name, id);
324         return 0;
325     }
326     if ((r = lseek(ep->fd, id * ep->size, 0)) < 0) {
327         logerror("ef_nbwrite: %s #%d lseek(%d, %d, 0) -> %d",
328                  ep->name, id, ep->fd, id * ep->size, r);
329         return 0;
330     }
331     if (ep->prewrite)
332         ep->prewrite(id, ptr);
333     if ((r = write(ep->fd, ptr, ep->size)) != ep->size) {
334         logerror("ef_nbwrite: %s #%d write(%d, %x, %d) -> %d",
335                  ep->name, id, ep->fd, ptr, ep->size, r);
336         return 0;
337     }
338     ef_zapcache(type);
339     if (id >= ep->fids) {
340         /* write expanded file; ep->fids = last id + 1 */
341         ep->fids = id + 1;
342     }
343     return 1;
344 }
345 #endif
346
347 int
348 ef_extend(int type, int count)
349 {
350     register struct empfile *ep;
351     char *ptr;
352     int cur, max;
353     int mode, how;
354     int r;
355
356     if (ef_check(type) < 0)
357         return 0;
358     ep = &empfile[type];
359     max = ep->fids + count;
360     cur = ep->fids;
361     ptr = (s_char *)calloc(1, ep->size);
362     if ((r = lseek(ep->fd, ep->fids * ep->size, 0)) < 0) {
363         logerror("ef_extend: %s +#%d lseek(%d, %d, 0) -> %d",
364                  ep->name, count, ep->fd, ep->fids * ep->size, r);
365         return 0;
366     }
367     for (cur = ep->fids; cur < max; cur++) {
368         if (ep->init)
369             ep->init(cur, ptr);
370         if ((r = write(ep->fd, ptr, ep->size)) != ep->size) {
371             logerror("ef_extend: %s +#%d write(%d, %p, %d) -> %d",
372                      ep->name, count, ep->fd, (void *)ptr, ep->size, r);
373             return 0;
374         }
375     }
376     free(ptr);
377     if (ep->flags & EFF_MEM) {
378         /* XXX this will cause problems if there are ef_ptrs (to the
379          * old allocated structure) active when we do the re-open */
380         mode = ep->mode;
381         how = ep->flags;
382         ef_close(type);
383         ef_open(type, mode, how);
384     } else {
385         ep->fids += count;
386     }
387     return 1;
388 }
389
390 void
391 ef_zapcache(int type)
392 {
393     register struct empfile *ep = &empfile[type];
394     if ((ep->flags & EFF_MEM) == 0) {
395         ep->cids = 0;
396         ep->baseid = -1;
397     }
398 }
399
400 struct castr *
401 ef_cadef(int type)
402 {
403     return empfile[type].cadef;
404 }
405
406 int
407 ef_nelem(int type)
408 {
409     return empfile[type].fids;
410 }
411
412 int
413 ef_flags(int type)
414 {
415     return empfile[type].flags;
416 }
417
418 time_t
419 ef_mtime(int type)
420 {
421     if (empfile[type].fd <= 0)
422         return 0;
423     return fdate(empfile[type].fd);
424 }
425
426 u_short *
427 ef_items(int type, void *sp)
428 {
429     register struct empfile *ef;
430
431     if (ef_check(type) < 0)
432         return 0;
433     ef = &empfile[type];
434     if ((ef->flags & EFF_COM) == 0)
435         return 0;
436     return (u_short *)((char *)sp + ef->itemoffs);
437 }
438
439 int
440 ef_byname(s_char *name)
441 {
442     register struct empfile *ef;
443     register int i;
444     int len;
445
446     len = strlen(name);
447     for (i = 0; i < EF_MAX; i++) {
448         ef = &empfile[i];
449         if (strncmp(ef->name, name, min(len, strlen(ef->name))) == 0)
450             return i;
451     }
452     return -1;
453 }
454
455 s_char *
456 ef_nameof(int type)
457 {
458     if (type < 0 || type >= EF_MAX)
459         return "bad item type";
460     return empfile[type].name;
461 }
462
463 int
464 ef_check(int type)
465 {
466     if (type < 0 || type >= EF_MAX) {
467         logerror("ef_ptr: bad EF_type %d\n", type);
468         return -1;
469     }
470     return 0;
471 }
472
473 int
474 ef_ensure_space(int type, int id, int count)
475 {
476     while (id >= empfile[type].fids) {
477         if (!ef_extend(type, count))
478             return 0;
479     }
480     return 1;
481 }