From 45bcb0704e5200fde9d25cd84ee5fab668db5e04 Mon Sep 17 00:00:00 2001 From: ewt Date: Thu, 16 Jan 1997 16:46:37 +0000 Subject: [PATCH] Reimplemented header internals CVS patchset: 1289 CVS date: 1997/01/16 16:46:37 --- lib/header.c | 993 +++++++++++++++++++++++++++-------------------------------- lib/header.h | 52 +++- 2 files changed, 488 insertions(+), 557 deletions(-) diff --git a/lib/header.c b/lib/header.c index be24be5..1cee399 100644 --- a/lib/header.c +++ b/lib/header.c @@ -20,33 +20,52 @@ #include "tread.h" #define INDEX_MALLOC_SIZE 8 -#define DATA_MALLOC_SIZE 1024 static unsigned char header_magic[4] = { 0x8e, 0xad, 0xe8, 0x01 }; +/* handy -- this tells us alignments for defined elements as well */ +static int typeSizes[] = { + /* RPM_NULL_TYPE */ -1, + /* RPM_CHAR_TYPE */ 1, + /* RPM_INT8_TYPE */ 1, + /* RPM_INT16_TYPE */ 2, + /* RPM_INT32_TYPE */ 4, + /* RPM_INT64_TYPE */ -1, + /* RPM_STRING_TYPE */ -1, + /* RPM_BIN_TYPE */ 1, + /* RPM_STRING_ARRAY_TYPE */ -1, + /* RPM_I18NSTRING_TYPE */ -1 }; + struct headerToken { struct indexEntry *index; - int entries_malloced; - int entries_used; - - char *data; - int data_malloced; - int data_used; + int indexUsed; + int indexAlloced; - int fully_sorted; /* This means the index and the data! */ + int sorted; }; -struct indexEntry { +struct entryInfo { int_32 tag; int_32 type; - int_32 offset; /* Offset from beginning of data segment */ + int_32 offset; /* Offset from beginning of data segment, + only defined on disk */ int_32 count; }; -static int indexSort(const void *ap, const void *bp); -static struct indexEntry *findEntry(Header h, int_32 tag); -static void *dataHostToNetwork(Header h); -static void *dataNetworkToHost(Header h); +struct indexEntry { + struct entryInfo info; + void * data; + int length; /* Computable, but why bother */ +}; + +static void indexSort(Header h); +static int indexCmp(const void *ap, const void *bp); +static void *doHeaderUnload(Header h, int * lengthPtr); +static struct indexEntry *findEntry(Header h, int_32 tag, int_32 type); +static void * grabData(int_32 type, void * p, int_32 c, int * lengthPtr); +static int dataLength(int_32 type, void * p, int_32 count, int onDisk); +static void copyEntry(struct indexEntry * entry, + int_32 *type, void **p, int_32 *c); /********************************************************************/ /* */ @@ -62,6 +81,9 @@ struct headerIteratorS { HeaderIterator headerInitIterator(Header h) { HeaderIterator hi = malloc(sizeof(struct headerIteratorS)); + + indexSort(h); + hi->h = h; hi->next_index = 0; return hi; @@ -75,67 +97,26 @@ void headerFreeIterator(HeaderIterator iter) int headerNextIterator(HeaderIterator iter, int_32 *tag, int_32 *type, void **p, int_32 *c) { - struct headerToken *h = iter->h; - struct indexEntry *index = h->index; - int x = h->entries_used; + Header h = iter->h; int slot = iter->next_index; - char **spp; - char *sp; - if (slot == h->entries_used) { + if (slot == h->indexUsed) { return 0; } iter->next_index++; - *tag = index[slot].tag; - *type = index[slot].type; - *c = index[slot].count; - - /* Now look it up */ - switch (*type) { - case RPM_INT64_TYPE: - case RPM_INT32_TYPE: - case RPM_INT16_TYPE: - case RPM_INT8_TYPE: - case RPM_BIN_TYPE: - case RPM_CHAR_TYPE: - *p = h->data + index[slot].offset; - break; - case RPM_STRING_TYPE: - if (*c == 1) { - /* Special case -- just return a pointer to the string */ - *p = h->data + index[slot].offset; - break; - } - /* Fall through to RPM_STRING_ARRAY_TYPE */ - case RPM_STRING_ARRAY_TYPE: - /* Correction! */ - *type = RPM_STRING_ARRAY_TYPE; - /* Otherwise, build up an array of char* to return */ - x = index[slot].count; - *p = malloc(x * sizeof(char *)); - spp = (char **) *p; - sp = h->data + index[slot].offset; - while (x--) { - *spp++ = sp; - sp = strchr(sp, 0); - sp++; - } - break; - default: - fprintf(stderr, "Data type %d not supported\n", (int) *type); - exit(1); - } + *tag = h->index[slot].info.tag; + copyEntry(h->index + slot, type, p, c); return 1; } -static int indexSort(const void *ap, const void *bp) +static int indexCmp(const void *ap, const void *bp) { int_32 a, b; - a = ((struct indexEntry *)ap)->tag; - b = ((struct indexEntry *)bp)->tag; + a = ((struct indexEntry *)ap)->info.tag; + b = ((struct indexEntry *)bp)->info.tag; if (a > b) { return 1; @@ -146,6 +127,13 @@ static int indexSort(const void *ap, const void *bp) } } +static void indexSort(Header h) { + if (!h->sorted) { + qsort(h->index, h->indexUsed, sizeof(struct indexEntry), indexCmp); + h->sorted = 1; + } +} + Header headerCopy(Header h) { int_32 tag, type, count; @@ -153,18 +141,17 @@ Header headerCopy(Header h) HeaderIterator headerIter; Header res = headerNew(); - /* Sort the index */ - qsort(h->index, h->entries_used, sizeof(struct indexEntry), indexSort); + /* Sort the index -- not really necessary but some old apps may depend + on this and it certainly won't hurt anything */ + indexSort(h); headerIter = headerInitIterator(h); - /* The result here is that the data is also sorted */ while (headerNextIterator(headerIter, &tag, &type, &ptr, &count)) { headerAddEntry(res, tag, type, ptr, count); - if (type == RPM_STRING_ARRAY_TYPE) free(ptr); } - res->fully_sorted = 1; + res->sorted = 1; headerFreeIterator(headerIter); @@ -179,250 +166,74 @@ Header headerCopy(Header h) void headerWrite(int fd, Header h, int magicp) { + void * p; + int length; int_32 l; - struct indexEntry *p; - struct indexEntry *copyIndex; - int c; - void *converted_data; - /* This magic actually sorts the data */ - h = headerCopy(h); + p = doHeaderUnload(h, &length); - /* We must write using network byte order! */ - - /* Magic and 4 reserved bytes */ if (magicp) { write(fd, header_magic, sizeof(header_magic)); l = htonl(0); write(fd, &l, sizeof(l)); } - /* First write out the length of the index (count of index entries) */ - l = htonl(h->entries_used); - write(fd, &l, sizeof(l)); - - /* Then write the length of the data (number of bytes) */ - l = htonl(h->data_used); - write(fd, &l, sizeof(l)); - - /* Make a copy of the index for htonl() */ - copyIndex = malloc(sizeof(struct indexEntry) * h->entries_used); - memcpy(copyIndex, h->index, sizeof(struct indexEntry) * h->entries_used); - - /* Convert the index */ - c = h->entries_used; - p = copyIndex; - while (c--) { - p->tag = htonl(p->tag); - p->type = htonl(p->type); - p->offset = htonl(p->offset); - p->count = htonl(p->count); - p++; - } - - /* Write the index */ - write(fd, copyIndex, sizeof(struct indexEntry) * h->entries_used); - free(copyIndex); - - /* Finally convert and write the data */ - converted_data = dataHostToNetwork(h); - write(fd, converted_data, h->data_used); - free(converted_data); + write(fd, p, length); - headerFree(h); -} - -static void *dataHostToNetwork(Header h) -{ - char *data, *p; - struct indexEntry *index = h->index; - int entries = h->entries_used; - int count; - - data = malloc(h->data_used); - memcpy(data, h->data, h->data_used); - - while (entries--) { - p = data + index->offset; - count = index->count; - switch (index->type) { - case RPM_INT64_TYPE: - while (count--) { - *((int_64 *)p) = htonl(*((int_64 *)p)); - p += sizeof(int_64); - } - break; - case RPM_INT32_TYPE: - while (count--) { - *((int_32 *)p) = htonl(*((int_32 *)p)); - p += sizeof(int_32); - } - break; - case RPM_INT16_TYPE: - while (count--) { - *((int_16 *)p) = htons(*((int_16 *)p)); - p += sizeof(int_16); - } - break; - case RPM_INT8_TYPE: - case RPM_BIN_TYPE: - case RPM_CHAR_TYPE: - case RPM_STRING_TYPE: - case RPM_STRING_ARRAY_TYPE: - /* No conversion necessary */ - break; - default: - fprintf(stderr, "Data type %d not supprted\n", (int) index->type); - exit(1); - } - - index++; - } - - return data; + free(p); } Header headerRead(int fd, int magicp) { - int_32 il, dl; - unsigned char magic[4]; int_32 reserved; - struct indexEntry *p; - int c; - void *converted_data; - - struct headerToken *h = (struct headerToken *) - malloc(sizeof(struct headerToken)); + int_32 * p; + int_32 il, dl; + int_32 magic; + Header h; + void * block; + int totalSize; if (magicp == HEADER_MAGIC_YES) { - c = timedRead(fd, magic, sizeof(magic)); - rpmMessage(RPMMESS_DEBUG, "magic: %02x %02x %02x %02x\n", - header_magic[0], - header_magic[1], - header_magic[2], - header_magic[3]); - rpmMessage(RPMMESS_DEBUG, "got : %02x %02x %02x %02x\n", - magic[0], - magic[1], - magic[2], - magic[3]); - if (memcmp(magic, header_magic, sizeof(magic))) { - free(h); + if (timedRead(fd, &magic, sizeof(magic)) != sizeof(magic)) + return NULL; + if (memcmp(&magic, header_magic, sizeof(magic))) { return NULL; } - timedRead(fd, &reserved, sizeof(reserved)); - reserved = ntohl(reserved); + + if (timedRead(fd, &reserved, sizeof(reserved)) != sizeof(reserved)) + return NULL; } /* First read the index length (count of index entries) */ - if (timedRead(fd, &il, sizeof(il)) != sizeof(il)) { - free(h); + if (timedRead(fd, &il, sizeof(il)) != sizeof(il)) return NULL; - } + il = ntohl(il); /* Then read the data length (number of bytes) */ - if (timedRead(fd, &dl, sizeof(dl)) != sizeof(dl)) { - free(h); + if (timedRead(fd, &dl, sizeof(dl)) != sizeof(dl)) return NULL; - } + dl = ntohl(dl); - /* Next read the index */ - h->index = malloc(il * sizeof(struct indexEntry)); - h->entries_malloced = il; - h->entries_used = il; - if (timedRead(fd, h->index, sizeof(struct indexEntry) * il) != - sizeof(struct indexEntry) * il) { - if (h->index) - free(h->index); - free(h); - return NULL; - } + totalSize = sizeof(int_32) + sizeof(int_32) + + (il * sizeof(struct entryInfo)) + dl; - /* Convert the index */ - c = h->entries_used; - p = h->index; - while (c--) { - p->tag = ntohl(p->tag); - p->type = ntohl(p->type); - p->offset = ntohl(p->offset); - p->count = ntohl(p->count); - p++; - } + block = p = malloc(totalSize); + *p++ = htonl(il); + *p++ = htonl(dl); - /* Finally, read the data */ - h->data = malloc(dl); - h->data_malloced = dl; - h->data_used = dl; - if (timedRead(fd, h->data, dl) != dl) { - if (h->data) - free(h->data); - if (h->index) - free(h->index); - free(h); + totalSize -= sizeof(int_32) + sizeof(int_32); + if (timedRead(fd, p, totalSize) != totalSize) return NULL; - } - /* and convert it */ - converted_data = dataNetworkToHost(h); - free(h->data); - h->data = converted_data; + + h = headerLoad(block); - h->fully_sorted = 1; + free(block); return h; } -static void *dataNetworkToHost(Header h) -{ - char *data, *p; - struct indexEntry *index = h->index; - int entries = h->entries_used; - int count; - - data = malloc(h->data_used); - memcpy(data, h->data, h->data_used); - - while (entries--) { - p = data + index->offset; - count = index->count; - switch (index->type) { - case RPM_INT64_TYPE: - while (count--) { - *((int_64 *)p) = ntohl(*((int_64 *)p)); - p += sizeof(int_64); - } - break; - case RPM_INT32_TYPE: - while (count--) { - *((int_32 *)p) = ntohl(*((int_32 *)p)); - p += sizeof(int_32); - } - break; - case RPM_INT16_TYPE: - while (count--) { - *((int_16 *)p) = ntohs(*((int_16 *)p)); - p += sizeof(int_16); - } - break; - case RPM_INT8_TYPE: - case RPM_BIN_TYPE: - case RPM_CHAR_TYPE: - case RPM_STRING_TYPE: - case RPM_STRING_ARRAY_TYPE: - /* No conversion necessary */ - break; - default: - fprintf(stderr, "Data type %d not supprted\n", (int) index->type); - exit(1); - } - - index++; - } - - return data; -} - /********************************************************************/ /* */ /* Header loading and unloading */ @@ -431,59 +242,151 @@ static void *dataNetworkToHost(Header h) Header headerLoad(void *pv) { - int_32 il, dl; /* index length, data length */ + int_32 il; /* index length, data length */ char *p = pv; + char * dataStart; + struct entryInfo * pe; + struct indexEntry * entry; struct headerToken *h = malloc(sizeof(struct headerToken)); + char * src, * dst; + int i; + int count; - il = *((int_32 *) p); + il = ntohl(*((int_32 *) p)); p += sizeof(int_32); - dl = *((int_32 *) p); + + /* we can skip the data length -- we only store this to allow reading + from disk */ p += sizeof(int_32); - h->entries_malloced = il; - h->entries_used = il; + h->indexAlloced = il; + h->indexUsed = il; h->index = malloc(il * sizeof(struct indexEntry)); - memcpy(h->index, p, il * sizeof(struct indexEntry)); - p += il * sizeof(struct indexEntry); - - h->data_malloced = dl; - h->data_used = dl; - h->data = malloc(dl); - memcpy(h->data, p, dl); /* This assumes you only headerLoad() something you headerUnload()-ed */ - h->fully_sorted = 1; + h->sorted = 1; + + pe = (struct entryInfo *) p; + dataStart = (char *) (pe + h->indexUsed); + + for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++, pe++) { + entry->info.type = htonl(pe->type); + entry->info.tag = htonl(pe->tag); + entry->info.count = htonl(pe->count); + entry->info.offset = -1; + + src = dataStart + htonl(pe->offset); + entry->length = dataLength(entry->info.type, src, + entry->info.count, 1); + entry->data = dst = malloc(entry->length); + + /* copy data w/ endian conversions */ + switch (entry->info.type) { + case RPM_INT32_TYPE: + count = entry->info.count; + while (count--) { + *((int_32 *)dst) = htonl(*((int_32 *)src)); + src += sizeof(int_32); + dst += sizeof(int_32); + } + break; + + case RPM_INT16_TYPE: + count = entry->info.count; + while (count--) { + *((int_16 *)dst) = htons(*((int_16 *)src)); + src += sizeof(int_16); + dst += sizeof(int_16); + } + break; + + default: + memcpy(dst, src, entry->length); + } + } return h; } -void *headerUnload(Header h) +static void *doHeaderUnload(Header h, int * lengthPtr) { + int i; + int type, diff; void *p; int_32 *pi; - char * chptr; + struct entryInfo * pe; + struct indexEntry * entry; + char * chptr, * src, * dataStart; + int count; + + indexSort(h); - /* This magic actually sorts the data */ - h = headerCopy(h); + *lengthPtr = headerSizeof(h, 0); + pi = p = malloc(*lengthPtr); - pi = p = malloc(2 * sizeof(int_32) + - h->entries_used * sizeof(struct indexEntry) + - h->data_used); + *pi++ = htonl(h->indexUsed); - *pi++ = h->entries_used; - *pi++ = h->data_used; + /* data length */ + *pi++ = htonl(*lengthPtr - sizeof(int_32) - sizeof(int_32) - + (sizeof(struct entryInfo) * h->indexUsed)); - chptr = (char *) pi; + pe = (struct entryInfo *) pi; + dataStart = chptr = (char *) (pe + h->indexUsed); + + for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++, pe++) { + pe->type = htonl(entry->info.type); + pe->tag = htonl(entry->info.tag); + pe->count = htonl(entry->info.count); + + /* Alignment */ + type = entry->info.type; + if (typeSizes[type] > 1) { + diff = typeSizes[type] - ((chptr - dataStart) % typeSizes[type]); + if (diff != typeSizes[type]) { + memset(chptr, 0, diff); + chptr += diff; + } + } - memcpy(chptr, h->index, h->entries_used * sizeof(struct indexEntry)); - chptr += h->entries_used * sizeof(struct indexEntry); - memcpy(chptr, h->data, h->data_used); + pe->offset = htonl(chptr - dataStart); - headerFree(h); + /* copy data w/ endian conversions */ + switch (entry->info.type) { + case RPM_INT32_TYPE: + count = entry->info.count; + src = entry->data; + while (count--) { + *((int_32 *)chptr) = htonl(*((int_32 *)src)); + chptr += sizeof(int_32); + src += sizeof(int_32); + } + break; + + case RPM_INT16_TYPE: + count = entry->info.count; + src = entry->data; + while (count--) { + *((int_16 *)chptr) = htons(*((int_16 *)src)); + chptr += sizeof(int_16); + src += sizeof(int_16); + } + break; + + default: + memcpy(chptr, entry->data, entry->length); + chptr += entry->length; + } + } return p; } +void *headerUnload(Header h) { + int length; + + return doHeaderUnload(h, &length); +} + /********************************************************************/ /* */ /* Header dumping */ @@ -499,24 +402,21 @@ void headerDump(Header h, FILE * f, int flags) char *type, *tag; /* First write out the length of the index (count of index entries) */ - fprintf(f, "Entry count: %d\n", h->entries_used); - - /* And the length of the data (number of bytes) */ - fprintf(f, "Data count : %d\n", h->data_used); + fprintf(f, "Entry count: %d\n", h->indexUsed); /* Now write the index */ p = h->index; fprintf(f, "\n CT TAG TYPE " " OFSET COUNT\n"); - for (i = 0; i < h->entries_used; i++) { - switch (p->type) { + for (i = 0; i < h->indexUsed; i++) { + switch (p->info.type) { case RPM_NULL_TYPE: type = "NULL_TYPE"; break; case RPM_CHAR_TYPE: type = "CHAR_TYPE"; break; case RPM_BIN_TYPE: type = "BIN_TYPE"; break; case RPM_INT8_TYPE: type = "INT8_TYPE"; break; case RPM_INT16_TYPE: type = "INT16_TYPE"; break; case RPM_INT32_TYPE: type = "INT32_TYPE"; break; - case RPM_INT64_TYPE: type = "INT64_TYPE"; break; + /*case RPM_INT64_TYPE: type = "INT64_TYPE"; break;*/ case RPM_STRING_TYPE: type = "STRING_TYPE"; break; case RPM_STRING_ARRAY_TYPE: type = "STRING_ARRAY_TYPE"; break; default: type = "(unknown)"; break; @@ -525,21 +425,22 @@ void headerDump(Header h, FILE * f, int flags) tag = "(unknown)"; c = 0; while (c < rpmTagTableSize) { - if (rpmTagTable[c].val == p->tag) { + if (rpmTagTable[c].val == p->info.tag) { tag = rpmTagTable[c].name + 7; } c++; } fprintf(f, "Entry : %.3d (%d)%-14s %-18s 0x%.8x %.8d\n", i, - p->tag, tag, type, (uint_32) p->offset, (uint_32) p->count); + p->info.tag, tag, type, (uint_32) p->info.offset, (uint_32) + p->info.count); if (flags & HEADER_DUMP_INLINE) { /* Print the data inline */ - dp = h->data + p->offset; - c = p->count; + dp = p->data; + c = p->info.count; ct = 0; - switch (p->type) { + switch (p->info.type) { case RPM_INT32_TYPE: while (c--) { fprintf(f, " Data: %.3d 0x%08x (%d)\n", ct++, @@ -598,7 +499,8 @@ void headerDump(Header h, FILE * f, int flags) } break; default: - fprintf(stderr, "Data type %d not supprted\n", (int) p->type); + fprintf(stderr, "Data type %d not supprted\n", + (int) p->info.type); exit(1); } } @@ -612,103 +514,110 @@ void headerDump(Header h, FILE * f, int flags) /* */ /********************************************************************/ -static int tagCompare(const void *key, const void *member) +static struct indexEntry *findEntry(Header h, int_32 tag, int_32 type) { - if (*((int_32 *)key) > ((struct indexEntry *)member)->tag) { - return 1; - } else if (*((int_32 *)key) < ((struct indexEntry *)member)->tag) { - return -1; - } else { - return 0; - } -} + struct indexEntry * entry, * entry2, * last; + struct indexEntry key; -static struct indexEntry *findEntry(Header h, int_32 tag) -{ - struct indexEntry *index = h->index; - int x = h->entries_used; + if (!h->sorted) indexSort(h); - if (h->fully_sorted) { - return bsearch(&tag, index, x, sizeof(struct indexEntry), tagCompare); - } else { - while (x && (tag != index->tag)) { - index++; - x--; - } - return (x ? index : NULL); - } + key.info.tag = tag; + + entry2 = entry = + bsearch(&key, h->index, h->indexUsed, sizeof(struct indexEntry), + indexCmp); + if (!entry) return NULL; + + if (type == RPM_NULL_TYPE) return entry; + + /* look backwards */ + while (entry->info.tag == tag && entry->info.type != type && + entry > h->index) entry--; + + if (entry->info.tag == tag && entry->info.type == type) + return entry; + + last = h->index + h->indexUsed; + while (entry2->info.tag == tag && entry2->info.type != type && + entry2 < last) entry2++; + + if (entry->info.tag == tag && entry->info.type == type) + return entry; + + return NULL; } int headerIsEntry(Header h, int_32 tag) { - return (findEntry(h, tag) ? 1 : 0); + return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0); } -int headerGetEntry(Header h, int_32 tag, int_32 * type, void **p, int_32 * c) -{ - struct indexEntry *index; - char **spp; - char *sp; - int x; - - if (!p) return headerIsEntry(h, tag); - - /* First find the tag */ - index = findEntry(h, tag); - if (! index) { - *p = NULL; - return 0; - } +static void copyEntry(struct indexEntry * entry, + int_32 *type, void **p, int_32 *c) { + int i, tableSize; + char ** ptrEntry; + char * chptr; - if (type) { - *type = (int) index->type; - } - if (c) { - *c = index->count; - } + if (type) + *type = entry->info.type; + if (c) + *c = entry->info.count; /* Now look it up */ - switch (index->type) { - case RPM_INT64_TYPE: - case RPM_INT32_TYPE: - case RPM_INT16_TYPE: - case RPM_INT8_TYPE: - case RPM_BIN_TYPE: - case RPM_CHAR_TYPE: - *p = h->data + index->offset; - break; - case RPM_STRING_TYPE: - if (index->count == 1) { - /* Special case -- just return a pointer to the string */ - *p = h->data + index->offset; + switch (entry->info.type) { + case RPM_STRING_TYPE: + if (entry->info.count == 1) { + *p = entry->data; break; } - /* Fall through to RPM_STRING_ARRAY_TYPE */ - case RPM_STRING_ARRAY_TYPE: - /* Correction! */ - if (type) { - *type = RPM_STRING_ARRAY_TYPE; - } - /* Otherwise, build up an array of char* to return */ - x = index->count; - *p = malloc(x * sizeof(char *)); - spp = (char **) *p; - sp = h->data + index->offset; - while (x--) { - *spp++ = sp; - sp = strchr(sp, 0); - sp++; + /* fallthrough */ + case RPM_STRING_ARRAY_TYPE: + *type = RPM_STRING_ARRAY_TYPE; + i = entry->info.count; + tableSize = i * sizeof(char *); + ptrEntry = *p = malloc(tableSize + entry->length); + chptr = ((char *) *p) + tableSize; + memcpy(chptr, entry->data, entry->length); + while (i--) { + *ptrEntry++ = chptr; + chptr = strchr(chptr, 0); + chptr++; } break; - default: - fprintf(stderr, "Data type %d not supprted\n", - (int) index->type); - exit(1); + + default: + *p = entry->data; } +} + +int headerGetRawEntry(Header h, int_32 tag, int_32 *type, void **p, int_32 *c) { + struct indexEntry * entry; + + if (!p) return headerIsEntry(h, tag); + + /* First find the tag */ + entry = findEntry(h, tag, RPM_NULL_TYPE); + if (!entry) { + *p = NULL; + return 0; + } + + copyEntry(entry, type, p, c); return 1; } +int headerGetEntry(Header h, int_32 tag, int_32 * type, void **p, int_32 * c) +{ + int_32 t = RPM_NULL_TYPE; + int rc; + + rc = headerGetRawEntry(h, tag, &t, p, c); + if (rc && type) *type = t; + + return rc; +} + /********************************************************************/ /* */ /* Header creation and deletion */ @@ -717,225 +626,223 @@ int headerGetEntry(Header h, int_32 tag, int_32 * type, void **p, int_32 * c) Header headerNew() { - struct headerToken *h = (struct headerToken *) - malloc(sizeof(struct headerToken)); - - h->data = malloc(DATA_MALLOC_SIZE); - h->data_malloced = DATA_MALLOC_SIZE; - h->data_used = 0; + Header h = malloc(sizeof(struct headerToken)); h->index = malloc(INDEX_MALLOC_SIZE * sizeof(struct indexEntry)); - h->entries_malloced = INDEX_MALLOC_SIZE; - h->entries_used = 0; + h->indexAlloced = INDEX_MALLOC_SIZE; + h->indexUsed = 0; - h->fully_sorted = 0; + h->sorted = 0; return (Header) h; } void headerFree(Header h) { + int i; + + for (i = 0; i < h->indexUsed; i++) + free(h->index[i].data); + free(h->index); - free(h->data); free(h); } unsigned int headerSizeof(Header h, int magicp) { unsigned int size; + int i, diff; + int_32 type; + + indexSort(h); - /* Do some real magic to determine the ON-DISK size */ - h = headerCopy(h); - size = sizeof(int_32); /* count of index entries */ size += sizeof(int_32); /* length of data */ - size += sizeof(struct indexEntry) * h->entries_used; - size += h->data_used; + size += sizeof(struct entryInfo) * h->indexUsed; if (magicp) { size += 8; } - headerFree(h); + for (i = 0; i < h->indexUsed; i++) { + /* Alignment */ + type = h->index[i].info.type; + if (typeSizes[type] > 1) { + diff = typeSizes[type] - (size % typeSizes[type]); + if (diff != typeSizes[type]) { + size += diff; + } + } + + size += h->index[i].length; + } return size; } -/********************************************************************/ -/* */ -/* Adding and modifying entries */ -/* */ -/********************************************************************/ - -int headerAddEntry(Header h, int_32 tag, int_32 type, void *p, int_32 c) -{ - struct indexEntry *entry; - void *ptr; - char **spp; - char *sp; - int i, length; - int pad; - - if (c <= 0) { - fprintf(stderr, "Bad count for headerAddEntry(): %d\n", (int) c); - exit(1); - } - - /* Allocate more index space if necessary */ - if (h->entries_used == h->entries_malloced) { - h->entries_malloced += INDEX_MALLOC_SIZE; - h->index = realloc(h->index, - h->entries_malloced * sizeof(struct indexEntry)); - } +static int dataLength(int_32 type, void * p, int_32 count, int onDisk) { + int thisLen, length, i; + char ** src, * chptr; - /* Fill in the index */ - i = h->entries_used++; - entry = &((h->index)[i]); - entry->tag = tag; - entry->type = type; - entry->count = c; - - /* Compute length of data to add */ - pad = 0; switch (type) { - case RPM_INT64_TYPE: - length = sizeof(int_64) * c; - pad = 8; - break; - case RPM_INT32_TYPE: - length = sizeof(int_32) * c; - pad = 4; - break; - case RPM_INT16_TYPE: - length = sizeof(int_16) * c; - pad = 2; - break; - case RPM_INT8_TYPE: - length = sizeof(int_8) * c; - break; - case RPM_BIN_TYPE: - case RPM_CHAR_TYPE: - length = sizeof(char) * c; - break; - case RPM_STRING_TYPE: - if (c == 1) { + case RPM_STRING_TYPE: + if (count == 1) { /* Special case -- p is just the string */ length = strlen(p) + 1; break; } - /* Otherwise fall through to RPM_STRING_ARRAY_TYPE */ /* This should not be allowed */ - fprintf(stderr, "headerAddEntry() RPM_STRING_TYPE count must be 1.\n"); + fprintf(stderr, "grabData() RPM_STRING_TYPE count must be 1.\n"); exit(1); - case RPM_STRING_ARRAY_TYPE: + + case RPM_STRING_ARRAY_TYPE: /* This is like RPM_STRING_TYPE, except it's *always* an array */ /* Compute sum of length of all strings, including null terminators */ - i = c; - spp = p; + i = count; length = 0; - while (i--) { - /* add one for null termination */ - length += strlen(*spp++) + 1; + + if (onDisk) { + chptr = (char *) p; + while (i--) { + thisLen = strlen(chptr) + 1; + length += thisLen; + chptr += thisLen; + } + } else { + src = (char **) p; + while (i--) { + /* add one for null termination */ + length += strlen(*src++) + 1; + } } break; - default: - fprintf(stderr, "Data type %d not supprted\n", (int) type); - exit(1); - } - if (pad) { - pad = (pad - (h->data_used % pad)) % pad; - } - - /* Allocate more data space if necessary */ - while ((length + pad + h->data_used) > h->data_malloced) { - h->data_malloced += DATA_MALLOC_SIZE; - h->data = realloc(h->data, h->data_malloced); + default: + if (typeSizes[type] != -1) + length = typeSizes[type] * count; + else { + fprintf(stderr, "Data type %d not supported\n", (int) type); + exit(1); + } } - /* Fill in the data */ - entry->offset = h->data_used + pad; - ptr = h->data + h->data_used + pad; + return length; +} + +static void * grabData(int_32 type, void * p, int_32 c, int * lengthPtr) { + int length; + char ** src, * dst; + void * data; + int i, len; + + length = dataLength(type, p, c, 0); + data = malloc(length); + switch (type) { - case RPM_INT32_TYPE: - case RPM_INT16_TYPE: - case RPM_INT8_TYPE: - case RPM_BIN_TYPE: - case RPM_CHAR_TYPE: - memcpy(ptr, p, length); - break; - case RPM_STRING_TYPE: - if (c == 1) { - /* Special case -- p is just the string */ - strcpy(ptr, p); - break; - } - /* Fall through to RPM_STRING_ARRAY_TYPE */ - /* This should not be allowed */ - fprintf(stderr, "headerAddEntry() internal error!.\n"); - exit(1); case RPM_STRING_ARRAY_TYPE: - /* Otherwise, p is char** */ - i = c; - spp = p; - sp = (char *) ptr; - while (i--) { - strcpy(sp, *spp); - sp += strlen(*spp++) + 1; - } + /* Otherwise, p is char** */ + i = c; + src = (char **) p; + dst = (char *) data; + while (i--) { + len = strlen(*src) + 1; + memcpy(dst, *src, len); + dst += len; + src++; + } break; + default: - fprintf(stderr, "Data type %d not supprted\n", (int) type); + memcpy(data, p, length); + } + + *lengthPtr = length; + return data; +} + +/********************************************************************/ +/* */ +/* Adding and modifying entries */ +/* */ +/********************************************************************/ + +int headerAddEntry(Header h, int_32 tag, int_32 type, void *p, int_32 c) +{ + struct indexEntry *entry; + + h->sorted = 0; + + if (c <= 0) { + fprintf(stderr, "Bad count for headerAddEntry(): %d\n", (int) c); exit(1); } - h->data_used += length + pad; - h->fully_sorted = 0; + /* Allocate more index space if necessary */ + if (h->indexUsed == h->indexAlloced) { + h->indexAlloced += INDEX_MALLOC_SIZE; + h->index = realloc(h->index, + h->indexAlloced * sizeof(struct indexEntry)); + } + + /* Fill in the index */ + entry = h->index + h->indexUsed++; + entry->info.tag = tag; + entry->info.type = type; + entry->info.count = c; + entry->info.offset = -1; + + entry->data = grabData(type, p, c, &entry->length); + + h->sorted = 0; return 1; } int headerModifyEntry(Header h, int_32 tag, int_32 type, void *p, int_32 c) { - struct indexEntry *index; + struct indexEntry *entry; + void * oldData; /* First find the tag */ - index = findEntry(h, tag); - if (! index) { + entry = findEntry(h, tag, type); + if (! entry) { return 0; } - if (type != index->type) { - return 0; - } + /* free after we've grabbed the new data in case the two are intertwined + -- that's a bad idea but at least we won't break */ + oldData = entry->data; - if (c != 1) { - return 0; - } + entry->info.count = c; + entry->info.type = type; + entry->data = grabData(type, p, c, &entry->length); - if (index->count != 1) { + free(oldData); + + return 1; +} + +int headerAppendEntry(Header h, int_32 tag, int_32 type, void * p, int_32 c) { + struct indexEntry *entry; + int length; + + /* First find the tag */ + entry = findEntry(h, tag, type); + if (!entry) { return 0; } - - switch (index->type) { - case RPM_INT64_TYPE: - *((int_64 *)(h->data + index->offset)) = *((int_64 *)p); - break; - case RPM_INT32_TYPE: - *((int_32 *)(h->data + index->offset)) = *((int_32 *)p); - break; - case RPM_INT16_TYPE: - *((int_16 *)(h->data + index->offset)) = *((int_16 *)p); - break; - case RPM_INT8_TYPE: - *((int_8 *)(h->data + index->offset)) = *((int_8 *)p); - break; - case RPM_BIN_TYPE: - case RPM_CHAR_TYPE: - *((char *)(h->data + index->offset)) = *((char *)p); - break; - default: + + if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) { + /* we can't do this */ return 0; } - return 1; + length = dataLength(type, p, c, 0); + + entry->data = realloc(entry->data, entry->length + length); + memcpy(((char *) entry->data) + entry->length, p, length); + + grabData(type, entry->data + entry->length, c, &length); + entry->length += length; + + return 0; } diff --git a/lib/header.h b/lib/header.h index 87adf9e..2328c40 100644 --- a/lib/header.h +++ b/lib/header.h @@ -3,8 +3,10 @@ * header.h - routines for managing rpm tagged structures */ -#ifndef _header_h -#define _header_h +/* WARNING: 1 means success, 0 means failure (yes, this is backwards) */ + +#ifndef H_HEADER +#define H_HEADER #include #if defined(__alpha__) @@ -50,10 +52,26 @@ void headerDump(Header h, FILE *f, int flags); #define HEADER_DUMP_INLINE 1 -int headerGetEntry(Header h, int_32 tag, int_32 *type, void **p, int_32 *c); +/* I18N items need an RPM_STRING_TYPE entry (used by default) and an + RPM_18NSTRING_TYPE table added. Dups are okay, but only defined for + iteration (with the exceptions noted below) */ int headerAddEntry(Header h, int_32 tag, int_32 type, void *p, int_32 c); int headerModifyEntry(Header h, int_32 tag, int_32 type, void *p, int_32 c); +/* Appends item p to entry w/ tag and type as passed. Won't work on + RPM_STRING_TYPE. Any pointers from headerGetEntry() for this entry + are invalid after this call has been made! */ +int headerAppendEntry(Header h, int_32 tag, int_32 type, void * p, int_32 c); + +/* Will never return RPM_I18NSTRING_TYPE! RPM_STRING_TYPE elements w/ + RPM_I18NSTRING_TYPE equivalent enreies are translated (if HEADER_I18NTABLE + entry is present). */ +int headerGetEntry(Header h, int_32 tag, int_32 *type, void **p, int_32 *c); + +/* If *type is RPM_NULL_TYPE any type will match, otherwise only *type will + match. */ +int headerGetRawEntry(Header h, int_32 tag, int_32 *type, void **p, int_32 *c); + int headerIsEntry(Header h, int_32 tag); HeaderIterator headerInitIterator(Header h); @@ -65,14 +83,20 @@ Header headerCopy(Header h); /* Entry Types */ -#define RPM_NULL_TYPE 0 -#define RPM_CHAR_TYPE 1 -#define RPM_INT8_TYPE 2 -#define RPM_INT16_TYPE 3 -#define RPM_INT32_TYPE 4 -#define RPM_INT64_TYPE 5 -#define RPM_STRING_TYPE 6 -#define RPM_BIN_TYPE 7 -#define RPM_STRING_ARRAY_TYPE 8 - -#endif _header_h +#define RPM_NULL_TYPE 0 +#define RPM_CHAR_TYPE 1 +#define RPM_INT8_TYPE 2 +#define RPM_INT16_TYPE 3 +#define RPM_INT32_TYPE 4 +/* #define RPM_INT64_TYPE 5 ---- These aren't supported (yet) */ +#define RPM_STRING_TYPE 6 +#define RPM_BIN_TYPE 7 +#define RPM_STRING_ARRAY_TYPE 8 +#define RPM_I18NSTRING_TYPE 9 + +/* Tags -- general use tags should start at 1000 (RPM's tag space starts + there) */ + +#define HEADER_I18NTABLE 100 + +#endif H_HEAER -- 2.7.4