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;
}
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 */
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;