From b144af9a1a50583d9177ea4d2b0f94eee4178f84 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Sat, 22 Dec 2007 23:11:26 -0500 Subject: [PATCH] Fix lbx_extract's seeking to maintain a correct offset even on errors. --- src/lbx.c | 66 +++++++++++++++++++++++++-------------------------- src/lbxtool.c | 1 + 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/lbx.c b/src/lbx.c index 3eac708..597d043 100644 --- a/src/lbx.c +++ b/src/lbx.c @@ -106,26 +106,40 @@ int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf) return 0; } -/* - * Read and discard len bytes from the file. On success, returns 0. On - * failure, returns -1 and sets lbx_errno. - */ -static int skipdata(FILE *f, size_t len) +/* Advance to the beginning of the index'th file by either fseek or reading. */ +static int _lbx_fseek(struct lbx_state *lbx, size_t base) { - unsigned char buf[1024]; - - while (len) { - if (fread(buf, MIN(sizeof buf, len), 1, f) != 1) { - if (feof(f)) { - lbx_errno = LBX_EEOF; - } else { - lbx_errno = -errno; + static unsigned char oblivion[1024]; + long dist; + + if (lbx->foff < base) { + dist = base - lbx->foff; + } else if (lbx->foff > base) { + dist = -(long)(lbx->foff - base); + } else { + return 0; + } + + if (fseek(lbx->f, dist, SEEK_CUR) == 0) { + lbx->foff += dist; + } else if (lbx->foff < base) { + while (dist) { + size_t rc, amt = MIN(sizeof oblivion, dist); + rc = fread(oblivion, 1, amt, lbx->f); + lbx->foff += rc; + dist -= rc; + if (rc < amt) { + if (feof(lbx->f)) + lbx_errno = LBX_EEOF; + else + lbx_errno = -errno; + return -1; } - return -1; } - len -= MIN(sizeof buf, len); + } else { + lbx_errno = -errno; + return -1; } - return 0; } @@ -142,23 +156,9 @@ size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of) base = lbx->offsets[index]; len = lbx->offsets[index+1] - lbx->offsets[index]; - /* Seek to the beginning of the file. */ - if (lbx->foff != base) { - int seekrc; - long dist = (lbx->foff < base) ? (base - lbx->foff) - : -(lbx->foff - base); - - seekrc = fseek(lbx->f, dist, SEEK_CUR); - if (seekrc == -1 && lbx->foff < base) { - if (skipdata(lbx->f, dist) == -1) { - /* lbx_errno set by skipdata */ - return 0; - } - } else if (seekrc == -1) { - lbx_errno = -errno; - return 0; - } - lbx->foff += dist; /* FIXME: failed skipdata breaks this. */ + if (_lbx_fseek(lbx, base) == -1) { + /* lbx_errno set by _lbx_fseek(). */ + return 0; } /* Copy file data */ diff --git a/src/lbxtool.c b/src/lbxtool.c index a220cea..5435d5f 100644 --- a/src/lbxtool.c +++ b/src/lbxtool.c @@ -81,6 +81,7 @@ int extract(FILE *f, const char *name, int verbose) { if (verbose) printf("extracting %s...\n", stat.name); rc = lbx_extract(lbx, i, of); if (rc < stat.size) { + if (rc == 0) remove(stat.name); errmsg("error extracting %s: %s.\n", stat.name, lbx_strerror()); break; -- 2.43.2