summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ustar.c147
-rw-r--r--src/ustar.h20
2 files changed, 127 insertions, 40 deletions
diff --git a/src/ustar.c b/src/ustar.c
index 7f9666a..69071c7 100644
--- a/src/ustar.c
+++ b/src/ustar.c
@@ -45,18 +45,35 @@ struct _opkg_opk_ustar_header {
unsigned char padding [12];
} __attribute__((__packed__));
+struct opkg_opk_ustar {
+ struct opkg_opk_gzip *gzip;
+ int32_t data_size_remaining;
+};
+
+struct opkg_opk_ustar *
+opkg_opk_ustar_init(struct opkg_opk_gzip *gzip)
+{
+ struct opkg_opk_ustar *ustar;
+
+ ustar = malloc(sizeof(*ustar));
+ if (ustar == NULL) {
+ return NULL;
+ }
+
+ ustar->gzip = gzip;
+ ustar->data_size_remaining = 0;
+
+ return ustar;
+}
+
static int
-_opkg_opk_ustar_next(struct opkg_opk_gzip_state *gzip_state, const char *member,
- struct _opkg_opk_ustar_header *header, unsigned char **contents)
+_opkg_opk_ustar_next(struct opkg_opk_ustar *ustar,
+ struct _opkg_opk_ustar_header *header)
{
static unsigned char record[512];
- int ret;
char *size_end;
- uint32_t size;
- unsigned char *contents_cursor;
- uint32_t i;
- switch ((ret = opkg_opk_gzip_next_record(gzip_state, header))) {
+ switch (opkg_opk_gzip_read(ustar->gzip, header)) {
case OPKG_OPK_OK:
break;
case OPKG_OPK_END:
@@ -64,56 +81,114 @@ _opkg_opk_ustar_next(struct opkg_opk_gzip_state *gzip_state, const char *member,
return OPKG_OPK_ERROR;
}
memset(record, 0, 512);
- if (strncmp(header, record, 512) == 0) {
+ if (memcmp(header, record, 512) == 0) {
/* TODO: End gzip stream */
return OPKG_OPK_END;
}
- if (strncmp(header->magic, "ustar", strlen("ustar")) != 0) {
+ if (memcmp(header->magic, "ustar", strlen("ustar")) != 0) {
return OPKG_OPK_ERROR;
}
- size = strtol(header->size, &size_end, 8);
+ ustar->data_size_remaining = strtol((char *) header->size, &size_end,
+ 8);
if (*size_end != '\0') {
return OPKG_OPK_ERROR;
}
- for (i = 0; i < (size + 511) / 512; ++i) {
- switch ((ret = opkg_opk_gzip_next_record(gzip_state, record))) {
- case OPKG_OPK_OK:
- break;
- case OPKG_OPK_END:
- case OPKG_OPK_ERROR:
- return OPKG_OPK_ERROR;
+
+ return OPKG_OPK_OK;
+}
+
+int
+opkg_opk_ustar_list(struct opkg_opk_ustar *ustar,
+ struct opkg_opk_ustar_member *member)
+{
+ static struct _opkg_opk_ustar_header record;
+ int ret;
+
+ if ((ret =_opkg_opk_ustar_next(ustar, &record)) != OPKG_OPK_OK) {
+ return ret; /* Error or end of archive */
+ }
+
+ if (record.prefix[0] != '\0') {
+ sprintf(member->name, "%s/%s", record.prefix, record.name);
+ } else {
+ memcpy(member->name, record.name, 100);
+ member->name[100] = '\0';
+ }
+
+ while (ustar->data_size_remaining > 0) {
+ if (opkg_opk_ustar_read(ustar, (char *) &record, NULL) ==
+ OPKG_OPK_ERROR) {
+ return OPKG_OPK_ERROR;
}
}
- return ret;
+ return OPKG_OPK_OK; /* Possibly more members in archive */
}
-unsigned char *
-opkg_opk_ustar_read(struct opkg_opk_gzip_state *gzip_state, const char *member)
+int
+opkg_opk_ustar_seek(struct opkg_opk_ustar *ustar, const char *member)
{
- struct _opkg_opk_ustar_header header;
- int ret;
- unsigned char *contents;
+ static struct _opkg_opk_ustar_header record;
+ static unsigned char name[257];
+ int ret;
- while ((ret = _opkg_opk_ustar_next(gzip_state, member,
- &header, &contents)) == OPKG_OPK_OK) {
- /* TODO: End gzip stream */
- return contents;
+ for (;;) {
+ if ((ret =_opkg_opk_ustar_next(ustar, &record)) != OPKG_OPK_OK)
+ {
+ return OPKG_OPK_ERROR; /* Error or end (not found) */
+ }
+
+ if (record.prefix[0] != '\0') {
+ sprintf((char *) name, "%s/%s", record.prefix,
+ record.name);
+ } else {
+ memcpy(name, record.name, 100);
+ name[100] = '\0';
+ }
+
+ if (strcmp((char *) name, member) == 0) {
+ ret = OPKG_OPK_OK; /* Member found */
+ } else {
+ ret = OPKG_OPK_ERROR; /* Member not found (yet) */
+ }
+
+ while (ustar->data_size_remaining > 0) {
+ if (opkg_opk_ustar_read(ustar, (char *) &record, NULL)
+ == OPKG_OPK_ERROR) {
+ return OPKG_OPK_ERROR;
+ }
+ }
}
- return NULL;
+
+ return ret;
}
int
-opkg_opk_ustar_list(struct opkg_opk_gzip_state *gzip_state,
- void (*member)(const char *name))
+opkg_opk_ustar_read(struct opkg_opk_ustar *ustar, char *buffer, size_t *size)
{
- struct _opkg_opk_ustar_header header;
- int ret;
+ if (ustar->data_size_remaining == 0) {
+ return OPKG_OPK_END;
+ }
- while ((ret = _opkg_opk_ustar_next(gzip_state, NULL, &header, NULL)) ==
- OPKG_OPK_OK) {
- printf("%s\n", header.name);
+ switch (opkg_opk_gzip_read(ustar->gzip, buffer)) {
+ case OPKG_OPK_OK:
+ break;
+ case OPKG_OPK_END:
+ case OPKG_OPK_ERROR:
+ return OPKG_OPK_ERROR;
}
- return ret;
+
+ if (ustar->data_size_remaining >= 512) {
+ if (size != NULL) {
+ *size = 512;
+ }
+ ustar->data_size_remaining -= 512;
+ } else {
+ if (size != NULL) {
+ *size = ustar->data_size_remaining;
+ }
+ ustar->data_size_remaining = 0;
+ }
+ return OPKG_OPK_OK;
}
diff --git a/src/ustar.h b/src/ustar.h
index a6959c7..a1c5e75 100644
--- a/src/ustar.h
+++ b/src/ustar.h
@@ -20,11 +20,23 @@
#ifndef OPKG_OPK_USTAR_H_
#define OPKG_OPK_USTAR_H_
-unsigned char *
-opkg_opk_ustar_read(struct opkg_opk_gzip_state *gzip_state, const char *member);
+struct opkg_opk_ustar;
+
+struct opkg_opk_ustar_member {
+ char name[257]; /* prefix[155] + '/' + name[100] + '\0' */
+};
+
+struct opkg_opk_ustar *
+opkg_opk_ustar_init(struct opkg_opk_gzip *gzip);
+
+int
+opkg_opk_ustar_list(struct opkg_opk_ustar *ustar,
+ struct opkg_opk_ustar_member *member);
+
+int
+opkg_opk_ustar_seek(struct opkg_opk_ustar *ustar, const char *member);
int
-opkg_opk_ustar_list(struct opkg_opk_gzip_state *gzip_state,
- void (*member)(const char *name));
+opkg_opk_ustar_read(struct opkg_opk_ustar *ustar, char *buffer, size_t *size);
#endif /* OPKG_OPK_USTAR_H_ */