#include <errno.h>
#include <assert.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
#include "pack.h"
#include "misc.h"
#include "lbx.h"
int lbx_errno = 0;
struct lbx_state {
- const char *name;
+ char *name;
const struct lbx_file_ops *fops;
int (*dtor)(void *handle);
return lbx;
}
+static char *str_dup(const char *s)
+{
+ char *buf;
+
+ buf = malloc(strlen(s)+1);
+ if (buf)
+ strcpy(buf, s);
+ return buf;
+}
+
struct lbx_state *lbx_open(void *f, const struct lbx_file_ops *fops,
int (*destructor)(void *), const char *name)
{
unsigned char hdr_buf[LBX_HDR_SIZE];
- struct lbx_state *lbx;
+ struct lbx_state *lbx = NULL;
+ char *dupname = NULL;
+
+ dupname = str_dup(name);
+ if (!dupname) {
+ lbx_errno = -errno;
+ goto err;
+ }
if (fops->read(hdr_buf, sizeof hdr_buf, f) != sizeof hdr_buf) {
lbx_errno = -errno;
- return NULL;
+ goto err;
}
lbx = lbx_init(hdr_buf);
if (!lbx)
- return NULL;
+ goto err;
+ lbx->name = dupname;
lbx->dtor = destructor;
- lbx->name = name;
lbx->fops = fops;
lbx->f = f;
lbx_errno = -errno;
if (fops->eof(f))
lbx_errno = LBX_EEOF;
- free(lbx);
- return NULL;
+ goto err;
}
lbx->offsets[i] = unpack_32_le(buf);
}
return lbx;
+err:
+ free(dupname);
+ free(lbx);
+ return NULL;
+}
+
+static int file_close(void *f)
+{
+ return fclose((FILE *)f);
+}
+
+static int pipe_close(void *f)
+{
+ struct lbx_pipe_state *p = f;
+ int rc;
+
+ rc = fclose(p->f);
+ free(p);
+ return rc;
+}
+
+static char *last_component(const char *name)
+{
+ char *c;
+
+ /* TODO: Handle other path separators. */
+ c = strrchr(name, '/');
+ if (!c)
+ return (char *)name;
+ return c+1;
}
-struct lbx_state *lbx_fopen(FILE *f, const char *name)
+struct lbx_state *lbx_fopen(const char *file)
{
- return lbx_open(f, &lbx_default_fops, NULL, name);
+ const char *name = last_component(file);
+ struct lbx_pipe_state *p;
+ FILE *f;
+
+ f = fopen(file, "rb");
+ if (!f)
+ return NULL;
+
+ if (fseek(f, 0, SEEK_CUR) == 0)
+ return lbx_open(f, &lbx_default_fops, file_close, name);
+
+ p = malloc(sizeof *p);
+ if (!p) {
+ fclose(f);
+ return NULL;
+ }
+
+ *p = (struct lbx_pipe_state) { .f = f };
+ return lbx_open(p, &lbx_pipe_fops, pipe_close, name);
}
size_t lbx_numfiles(struct lbx_state *lbx)
if (lbx && lbx->dtor)
rc = lbx->dtor(lbx->f);
+ free(lbx->name);
free(lbx);
return rc;
f->lbx->last_file = NULL;
if (fops->seek(f->lbx->f, f->base + pos, SEEK_SET) != 0)
return -1;
+
+ f->offset = pos;
f->lbx->last_file = f;
f->eof = 0;