+int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
+{
+ static char str[256]; /* FIXME */
+
+ if (index >= lbx->nfiles) {
+ buf->name = NULL;
+ lbx_errno = LBX_ERANGE;
+ return -1;
+ }
+
+ snprintf(str, sizeof str, "%s.%03zu", lbx->name, index);
+ buf->name = str;
+ buf->size = lbx->offsets[index+1] - lbx->offsets[index];
+ return 0;
+}
+
+static size_t
+_lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
+{
+ unsigned char buf[1024];
+ size_t rc, written = 0;
+
+ assert(lbx->f);
+
+ if (lbx->fops->seek(lbx->f, base, SEEK_SET) != 0) {
+ lbx_errno = -errno;
+ return 0;
+ }
+
+ while (len) {
+ size_t amt = MIN(len, sizeof buf);
+
+ rc = lbx->fops->read(buf, amt, lbx->f);
+ len -= rc;
+ if (rc < amt) {
+ if (lbx->fops->eof(lbx->f)) lbx_errno = LBX_EEOF;
+ else lbx_errno = -errno;
+ break;
+ }
+
+ rc = fwrite(buf, 1, amt, of);
+ written += rc;
+ if (rc < amt) {
+ lbx_errno = -errno;
+ break;
+ }
+ }
+
+ return written;
+}
+
+size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
+{
+ size_t base, len;
+
+ if (index >= lbx->nfiles) {
+ lbx_errno = LBX_ERANGE;
+ return 0;
+ }
+
+ base = lbx->offsets[index];
+ len = lbx->offsets[index+1] - lbx->offsets[index];
+ return _lbx_fextract(lbx, base, len, of);
+}
+
+int lbx_close(struct lbx_state *lbx)