(fillcache): Rewrite. Old version failed to check success of lseek(),

couldn't cope with interrupted or short reads (mostly harmless, as
disk reads commonly complete), and left an empty cache after a failed
read.
(ef_open): Use fillcache() instead of read().
(ef_read): Fail if fillcache() fails to read at least one element.
Old version copied garbage to its caller and claimed success.
This commit is contained in:
Markus Armbruster 2005-10-24 19:02:39 +00:00
parent 3ea02e2519
commit ab03d83ce1

View file

@ -32,10 +32,11 @@
* Steve McClure, 2000 * Steve McClure, 2000
*/ */
#include <string.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#if !defined(_WIN32) #if !defined(_WIN32)
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -46,7 +47,7 @@
#include "gen.h" #include "gen.h"
static void fillcache(struct empfile *ep, int start); static int fillcache(struct empfile *ep, int start);
/* /*
* Open the binary file for table TYPE (EF_SECTOR, ...). * Open the binary file for table TYPE (EF_SECTOR, ...).
@ -101,11 +102,9 @@ ef_open(int type, int how)
return 0; return 0;
} }
if (ep->flags & EFF_MEM) { if (ep->flags & EFF_MEM) {
if (read(ep->fd, ep->cache, size) != size) { if (fillcache(ep, 0) != ep->fids) {
logerror("ef_open: read(%s) failed\n", ep->file);
return 0; return 0;
} }
ep->cids = size / ep->size;
} }
return 1; return 1;
} }
@ -223,7 +222,8 @@ ef_read(int type, int id, void *into)
return 0; return 0;
} }
if (ep->baseid + ep->cids <= id || ep->baseid > id) if (ep->baseid + ep->cids <= id || ep->baseid > id)
fillcache(ep, id); if (fillcache(ep, id) < 1)
return 0;
from = ep->cache + (id - ep->baseid) * ep->size; from = ep->cache + (id - ep->baseid) * ep->size;
} }
memcpy(into, from, ep->size); memcpy(into, from, ep->size);
@ -233,15 +233,48 @@ ef_read(int type, int id, void *into)
return 1; return 1;
} }
static void /*
* Fill cache of EP with elements starting at ID.
* If any were read, return their number.
* Else return -1 and leave the cache unchanged.
*/
static int
fillcache(struct empfile *ep, int start) fillcache(struct empfile *ep, int start)
{ {
int n; int n, ret;
char *p;
if (CANT_HAPPEN(ep->fd < 0 || !ep->cache))
return -1;
if (lseek(ep->fd, start * ep->size, SEEK_SET) == (off_t)-1) {
logerror("Error seeking %s (%s)", ep->file, strerror(errno));
return -1;
}
p = ep->cache;
n = ep->csize * ep->size;
while (n > 0) {
ret = read(ep->fd, p, n);
if (ret < 0) {
if (errno != EAGAIN) {
logerror("Error reading %s (%s)", ep->file, strerror(errno));
break;
}
} else if (ret == 0) {
break;
} else {
p += ret;
n -= ret;
}
}
if (p == ep->cache)
return -1; /* nothing read, old cache still ok */
ep->baseid = start; ep->baseid = start;
lseek(ep->fd, start * ep->size, SEEK_SET); ep->cids = (p - ep->cache) / ep->size;
n = read(ep->fd, ep->cache, ep->csize * ep->size); return ep->cids;
ep->cids = n / ep->size;
} }
/* /*