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
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.
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.
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
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.
28 * file.c: Misc. operations on files
30 * Known contributors to this file:
52 static void fillcache(struct empfile *ep, int start);
55 ef_open(int type, int mode, int how)
57 register struct empfile *ep;
64 if (ef_check(type) < 0)
67 if ((ep->fd = open(ep->file, mode, 0660)) < 0) {
68 logerror("%s: open failed", ep->file);
72 block = blksize(ep->fd);
77 ep->fids = fsize(ep->fd) / ep->size;
78 if (ep->flags & EFF_MEM)
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);
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);
93 ep->cids = size / ep->size;
101 register struct empfile *ep;
104 if (ef_check(type) < 0)
107 if (ep->cache == 0) {
108 /* no cache implies never opened */
112 ep->flags &= ~EFF_MEM;
115 if ((r = close(ep->fd)) < 0) {
116 logerror("ef_close: %s close(%d) -> %d", ep->name, ep->fd, r);
124 register struct empfile *ep;
128 if (ef_check(type) < 0)
131 if (ep->cache == 0) {
132 /* no cache implies never opened */
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);
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);
148 /*ef_zapcache(type); */
153 ef_ptr(int type, int id)
155 register struct empfile *ep;
157 if (ef_check(type) < 0)
160 if (id < 0 || id >= ep->fids)
162 if ((ep->flags & EFF_MEM) == 0) {
163 logerror("ef_ptr: (%s) only valid for EFF_MEM entries", ep->file);
166 return (s_char *)(ep->cache + ep->size * id);
170 * buffered read. Tries to read a large number of items.
171 * This system won't work if item size is > sizeof buffer area.
174 ef_read(int type, int id, void *ptr)
176 register struct empfile *ep;
179 if (ef_check(type) < 0)
184 if (ep->flags & EFF_MEM) {
187 from = ep->cache + (id * ep->size);
189 if (id >= ep->fids) {
190 ep->fids = fsize(ep->fd) / ep->size;
194 if (ep->baseid + ep->cids <= id || ep->baseid > id)
196 from = ep->cache + (id - ep->baseid) * ep->size;
198 memcpy(ptr, from, ep->size);
201 ep->postread(id, ptr);
206 fillcache(struct empfile *ep, int 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;
222 ef_nbread(int type, int id, void *ptr)
224 register struct empfile *ep;
227 if (ef_check(type) < 0)
232 if (id >= ep->fids) {
233 ep->fids = fsize(ep->fd) / ep->size;
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);
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);
249 ep->postread(id, ptr);
255 * buffered write. Modifies read cache (if applicable)
256 * and writes through to disk.
259 ef_write(int type, int id, void *ptr)
262 register struct empfile *ep;
265 if (ef_check(type) < 0)
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);
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);
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);
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);
291 logerror("WARNING ef_write: expanded %s by more than one id",
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",
300 /* write expanded file; ep->fids = last id + 1 */
313 ef_nbwrite(int type, int id, void *ptr)
315 register struct empfile *ep;
318 if (ef_check(type) < 0)
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);
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);
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);
339 if (id >= ep->fids) {
340 /* write expanded file; ep->fids = last id + 1 */
348 ef_extend(int type, int count)
350 register struct empfile *ep;
356 if (ef_check(type) < 0)
359 max = ep->fids + count;
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);
367 for (cur = ep->fids; cur < max; cur++) {
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);
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 */
383 ef_open(type, mode, how);
391 ef_zapcache(int type)
393 register struct empfile *ep = &empfile[type];
394 if ((ep->flags & EFF_MEM) == 0) {
403 return empfile[type].cadef;
409 return empfile[type].fids;
415 return empfile[type].flags;
421 if (empfile[type].fd <= 0)
423 return fdate(empfile[type].fd);
427 ef_items(int type, void *sp)
429 register struct empfile *ef;
431 if (ef_check(type) < 0)
434 if ((ef->flags & EFF_COM) == 0)
436 return (u_short *)((char *)sp + ef->itemoffs);
440 ef_byname(s_char *name)
442 register struct empfile *ef;
447 for (i = 0; i < EF_MAX; i++) {
449 if (strncmp(ef->name, name, min(len, strlen(ef->name))) == 0)
458 if (type < 0 || type >= EF_MAX)
459 return "bad item type";
460 return empfile[type].name;
466 if (type < 0 || type >= EF_MAX) {
467 logerror("ef_ptr: bad EF_type %d\n", type);
474 ef_ensure_space(int type, int id, int count)
476 while (id >= empfile[type].fids) {
477 if (!ef_extend(type, count))