/* * rpmdata.c : handle the data in the RPM database. * * Copyright (c) 1997 Daniel Veillard * See COPYING for the status of this software. * * $Id: rpmdata.c,v 1.27 1998/05/11 03:31:29 veillard Exp $ */ #include #include #include #ifdef HAVE_FCNTL_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include "rpm2html.h" #include "rpmdata.h" /* * An hash table for the RPM list */ #define HASH_SIZE 256 rpmDataPtr rpmHashTable[HASH_SIZE]; /* * the lists of RPM and resources collected so far. */ rpmDataPtr rpmList = NULL; rpmDataPtr rpmInstalledList = NULL; rpmDataPtr rpmSoftwareList = NULL; rpmRessPtr ressList = NULL; rpmRessPtr ressInstalledList = NULL; rpmArchPtr archList = NULL; rpmDirPtr dirList = NULL; rpmSubdirPtr dirTree = NULL; rpmRealDirPtr treeRoot = NULL; /* * Hash table initialization. */ static int rpmHashInitialized = 0; void rpmHashInitialize(void) { int i; for (i = 0; i < HASH_SIZE; i++) { rpmHashTable[i] = NULL; } rpmHashInitialized = 1; } /* * Compute an hash key, seems of for < 256 hash entries. */ int rpmGetHash(const char *name, const char *version, const char *release) { unsigned char res = 0; while (*name != 0) res += *(name++); while (*version != 0) res += *(version++); while (*release != 0) res += *(release++); return((int) (res % HASH_SIZE)); } /* * Insert a new RPM, managing the list of various software. */ void rpmAddSoftware(rpmDataPtr rpm) { rpmDataPtr cur; int hash; if (!rpmHashInitialized) rpmHashInitialize(); hash = rpmGetHash(rpm->name, rpm->version, rpm->release); cur = rpmHashTable[hash]; while (cur != NULL) { if (!strcmp(rpm->name, cur->name) && !strcmp(rpm->version, cur->version) && !strcmp(rpm->release, cur->release)) { /* * this is already in the sofware list, link in as * a new arch support. */ #ifdef DEBUG_HASH fprintf(stderr, "clash : (%d) %s-%s-%s.%s and %s-%s-%s.%s\n", hash, rpm->name, rpm->version, rpm->release, rpm->arch, cur->name, cur->version, cur->release, cur->arch); #endif rpm->nextArch = cur->nextArch; cur->nextArch = rpm; rpm->nextSoft = NULL; /* this one is not in the software list */ return; } cur = cur->nextHash; } /* * this wasn't found in the software list ! */ #ifdef DEBUG_HASH fprintf(stderr, "new : (%d) %s-%s-%s.%s\n", hash, rpm->name, rpm->version, rpm->release, rpm->arch); #endif rpm->nextHash = rpmHashTable[hash]; rpmHashTable[hash] = rpm; rpm->nextArch = NULL; rpm->nextSoft = rpmSoftwareList; rpmSoftwareList = rpm; } /* * Add a resource to the list if it doesn't exists and add the * corresponding RPM as a provider. */ rpmRessPtr rpmRessAdd(char *ress, rpmDataPtr rpm, int installed) { rpmRessPtr cur; if (installed) cur = ressInstalledList; else cur = ressList; /* search for the resource */ while (cur != NULL) { if (!strcmp(ress, cur->name)) goto found; cur = cur->next; } /* not found allocate a new resource block and fill it */ cur = (rpmRessPtr) malloc(sizeof(rpmRess)); memset(cur, 0, sizeof(rpmRess)); if (cur == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmRess), strerror(errno)); return(NULL); } cur->name = strdup(ress); cur->nb_provider = 0; cur->stamp = rpm->stamp; if (installed) { cur->next = ressInstalledList; ressInstalledList = cur; } else { cur->next = ressList; ressList = cur; } found: /* add the provider to the array */ if (cur->nb_provider >= MAX_PROVIDE) { fprintf(stderr, "MAX_PROVIDE %d overflow, increase the limit!\n", MAX_PROVIDE); return(NULL); } cur->provider[cur->nb_provider++] = rpm; if (rpm->stamp > cur->stamp) cur->stamp = rpm->stamp; return(cur); } /* * Add a resource to the list if it doesn't exists and add the * corresponding RPM as a requester. */ rpmRessPtr rpmRequAdd(char *requ, rpmDataPtr rpm, int installed) { rpmRessPtr cur; if (installed) cur = ressInstalledList; else cur = ressList; /* search for the resource */ while (cur != NULL) { if (!strcmp(requ, cur->name)) goto found; cur = cur->next; } /* not found allocate a new resource block and fill it */ cur = (rpmRessPtr) malloc(sizeof(rpmRess)); memset(cur, 0, sizeof(rpmRess)); if (cur == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmRess), strerror(errno)); return(NULL); } cur->name = strdup(requ); cur->nb_provider = 0; cur->stamp = rpm->stamp; if (installed) { cur->next = ressInstalledList; ressInstalledList = cur; } else { cur->next = ressList; ressList = cur; } found: if (rpm->stamp > cur->stamp) cur->stamp = rpm->stamp; return(cur); } /* * print an RPM data block */ void rpmDataPrint(rpmDataPtr rpm) { int i; printf("%s\n", rpm->filename); printf("%s-%s-%s\n", rpm->name, rpm->version, rpm->release); if (rpm->summary) printf(" %s\n", rpm->summary); for (i = 0; i < rpm->nb_resources ;i++) printf("-> %s\n", rpm->resources[i]->name); } /* * Add two RPM lists */ rpmDataPtr rpmAddList(rpmDataPtr ret, rpmDataPtr cur) { rpmDataPtr tmp; if (ret == NULL) return (cur); if (cur == NULL) return (ret); if (cur->next == NULL) { cur->next = ret; return(cur); } if (ret->next == NULL) { ret->next = cur; return(ret); } tmp = ret; while (tmp->next != NULL) tmp = tmp->next; tmp->next = cur; return(ret); } /* * A generic sort function for an RPM list. * NOTE : since doing a fast sort on a linked list is a pain, * we allocate an array, copy the rpmDataPtr in the array * and use the standard qsort() for decent performances on * large databases. */ typedef int (*rpmCmpFunc)(const rpmData *a, const rpmData *b); typedef int (*qsortCmpFunc)(const void * a, const void * b); static rpmCmpFunc currentCmpFunc = NULL; static rpmDataPtr *array = NULL; static int max_elems = 1024; int rpmPtrCmpFunc(const rpmData **a, const rpmData **b) { return(currentCmpFunc(*a, *b)); } rpmDataPtr rpmGenericSort(rpmCmpFunc rpmCmp, rpmDataPtr list, int installed) { int i, nb_elems = 0; if (list == NULL) return(NULL); if (array == NULL) array = (rpmDataPtr *) malloc(max_elems * sizeof(rpmDataPtr)); /* * Step 1 : copy the list in the Array */ while (list != NULL) { if (nb_elems == max_elems) { max_elems *= 2; array = (rpmDataPtr *) realloc(array, max_elems * sizeof(rpmDataPtr)); } array[nb_elems++] = list; list = list->next; } /* * Step 2 : qsort() the Array */ currentCmpFunc = rpmCmp; qsort(array, nb_elems, sizeof(rpmDataPtr), (qsortCmpFunc) rpmPtrCmpFunc); /* * Step 3 : rebuild the list. */ for (i = 0;i < nb_elems - 1; i++) array[i]->next = array[i + 1]; array[nb_elems - 1]->next = NULL; list = array[0]; return(list); } /* * A generic sort function for the software list. */ void rpmGenericSortSoftware(rpmCmpFunc rpmCmp, int installed) { rpmDataPtr list; int i, nb_elems = 0; list = rpmSoftwareList; if (list == NULL) return; if (array == NULL) array = (rpmDataPtr *) malloc(max_elems * sizeof(rpmDataPtr)); /* * Step 1 : copy the list in the Array */ while (list != NULL) { if (nb_elems == max_elems) { max_elems *= 2; array = (rpmDataPtr *) realloc(array, max_elems * sizeof(rpmDataPtr)); } array[nb_elems++] = list; list = list->nextSoft; } /* * Step 2 : qsort() the Array */ currentCmpFunc = rpmCmp; qsort(array, nb_elems, sizeof(rpmDataPtr), (qsortCmpFunc) rpmPtrCmpFunc); /* * Step 3 : rebuild the list. */ for (i = 0;i < nb_elems - 1; i++) array[i]->nextSoft = array[i + 1]; array[nb_elems - 1]->nextSoft = NULL; rpmSoftwareList = array[0]; } /* * rpmGroupCmp : comparison of groupe values, if equal, compare * the names. */ int rpmGroupCmp(const rpmData *a, const rpmData *b) { int res = strcmp(a->group, b->group); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Group. */ rpmDataPtr rpmGroupSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmGroupCmp, list, installed); rpmGenericSortSoftware(rpmGroupCmp, installed); return(res); } /* * rpmDistribCmp : comparison of distributions values, if equal, compare * the names. */ int rpmDistribCmp(const rpmData *a, const rpmData *b) { int res = strcmp(a->distribution, b->distribution); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Distribution. */ rpmDataPtr rpmDistribSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmDistribCmp, list, installed); return(res); } /* * rpmVendorCmp : comparison of vendor values, if equal, compare * distributions, then compares the names. */ int rpmVendorCmp(const rpmData *a, const rpmData *b) { int res = strcmp(a->vendor, b->vendor); if (res) return(res); res = strcmp(a->distribution, b->distribution); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Vendor. */ rpmDataPtr rpmVendorSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmVendorCmp, list, installed); return(res); } /* * rpmDateCmp : comparison of date values, if equal, compare * distributions, then compares the names. */ int rpmDateCmp(const rpmData *a, const rpmData *b) { int res = (b->date - a->date) / (60 * 60 * 12); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Date. */ rpmDataPtr rpmDateSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmDateCmp, list, installed); return(res); } /* * rpmNameCmp : comparison of names. */ int rpmNameCmp(const rpmData *a, const rpmData *b) { int res = strcasecmp(a->name, b->name); return(res); } /* * sort all the RPMs by Name. */ rpmDataPtr rpmNameSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmNameCmp, list, installed); rpmGenericSortSoftware(rpmNameCmp, installed); return(res); } /* * Create a subdirectory of a given directory */ rpmSubdirPtr rpmNewSubdir(rpmSubdirPtr dir, const char *name, const char *htmlpath, const char *rpmpath, const char *color) { rpmSubdirPtr res; res = (rpmSubdirPtr) malloc(sizeof(rpmSubdir)); if (res == NULL) { fprintf(stderr, "rpmNewSubdir : running out of memory !\n"); exit(1); } res->max_subdirs = 8; res->subdirs = (rpmSubdirPtr *) malloc(res->max_subdirs * sizeof(rpmSubdirPtr)); if (res->subdirs == NULL) { fprintf(stderr, "rpmNewSubdir : running out of memory !\n"); exit(1); } res->name = strdup(name); res->nb_subdirs = 0; if (color) res->color = strdup(color); else res->color = NULL; memset(res->subdirs, 0, sizeof(res->subdirs)); if (dir == NULL) { res->htmlpath = strdup(name); res->parent = NULL; } else { res->parent = dir; if (htmlpath == NULL) { if (dir->htmlpath[0] != '\0') { char buf[500]; sprintf(buf, "%s/%s", dir->htmlpath, name); res->htmlpath = strdup(buf); } else res->htmlpath = strdup(name); } else res->htmlpath = strdup(htmlpath); if (rpmpath == NULL) { if (dir->rpmpath[0] != '\0') { char buf[500]; sprintf(buf, "%s/%s", dir->rpmpath, name); res->rpmpath = strdup(buf); } else res->rpmpath = strdup(name); } else res->rpmpath = strdup(rpmpath); if (dir->nb_subdirs >= dir->max_subdirs) { dir->max_subdirs *= 2; dir->subdirs = (rpmSubdirPtr *) realloc(dir->subdirs, dir->max_subdirs * sizeof(rpmSubdirPtr)); if (dir->subdirs == NULL) { fprintf(stderr, "rpmNewSubdir : running out of memory !\n"); exit(1); } } dir->subdirs[dir->nb_subdirs++] = res; } return(res); } /* * Remove one subdirectory from it's parent. */ void rpmRemoveSubdir(rpmSubdirPtr tree) { int i; rpmSubdirPtr cur = tree->parent; if (cur == NULL) return; /* * search the child in the parent list. */ for (i = 0;i < cur->nb_subdirs;i++) if (cur->subdirs[i] == tree) break; if (i >= cur->nb_subdirs) { fprintf(stderr, "rpmRemoveSubdir : child not referenced by parent\n"); return; } /* * Decrement the parent count, and shift the end of the array. */ cur->nb_subdirs--; for (;i < cur->nb_subdirs;i++) cur->subdirs[i] = cur->subdirs[i + 1]; cur->subdirs[i] = NULL; } /* * Free a full directory tree. */ void rpmFreeSubdir(rpmSubdirPtr tree) { int i; for (i = 0;i < tree->nb_subdirs; i++) rpmFreeSubdir(tree->subdirs[i]); free(tree->name); free(tree->htmlpath); free(tree->rpmpath); if (tree->color != NULL) free(tree->color); tree->parent = NULL; free(tree->subdirs); free(tree); } /* * print all RPM data blocks */ void rpmDataPrintAll(void) { rpmDataPtr cur = rpmList; while (cur != NULL) { rpmDataPrint(cur); cur = cur->next; } } /* * Try to extract an E-mail address from a string. * The string is truncated to the beginning of the E-Mail. * e.g. "Joe Average " should be truncated * to "Joe Average" */ char *extractEMail(char *string) { static char buf[200]; char *start; char *end; start = strchr(string, '@'); if (start == NULL) return(NULL); end = start; do { start--; if ((!isprint(*start)) || (*start == ' ') || (*start == '\t') || (*start == '\n') || (*start == '\r') || (*start == '@') || (*start == '<') || (*start == '>') || (*start == '(') || (*start == ')') || (*start == '[') || (*start == ']') || (*start == ';') || (*start == ',') || (*start == ',')) { start++; break; } } while (start != string); do { end++; if ((!isprint(*end)) || (*start == ' ') || (*start == '\t') || (*start == '\n') || (*start == '\r') || (*end == '@') || (*end == '<') || (*end == '>') || (*end == '(') || (*end == ')') || (*end == '[') || (*end == ']') || (*end == ';') || (*end == ',') || (*end == ',')) { break; } } while (*end != '\0'); strncpy(buf, start, end - start); buf[end - start] = '\0'; return(buf); } /* * Try to extract an URL address from a string. * The string is truncated to the beginning of the URL * e.g. "Nifty Project http://www.nifty.org/project/" * to "Nifty Project" */ char *extractURL(char *string) { static char buf[500]; char *start; char *end; start = strstr(string, "http://"); if (start == NULL) start = strstr(string, "ftp://"); if (start == NULL) return(NULL); end = start; do { start--; if ((!isprint(*start)) || (*start == ' ') || (*start == '\t') || (*start == '\n') || (*start == '\r') || (*start == '@') || (*start == '<') || (*start == '>') || (*start == '(') || (*start == ')') || (*start == '[') || (*start == ']') || (*start == ';') || (*start == ',') || (*start == ',')) { start++; break; } } while (start != string); do { end++; if ((!isprint(*end)) || (*start == ' ') || (*start == '\t') || (*start == '\n') || (*start == '\r') || (*end == '@') || (*end == '<') || (*end == '>') || (*end == '(') || (*end == ')') || (*end == '[') || (*end == ']') || (*end == ';') || (*end == ',') || (*end == ',')) { break; } } while (*end != '\0'); strncpy(buf, start, end - start); buf[end - start] = '\0'; return(buf); } /* * Create a root directory for the installation space, i.e. the * filesystem that would be created if the packages were installed * on a real system * Basic array allocation is 16 items. */ rpmRealDirPtr rpmCreateRealRoot(void) { rpmRealDirPtr res; res = (rpmRealDirPtr) malloc(sizeof(rpmRealDir)); if (res == NULL) { fprintf(stderr, "rpmCreateRealRoot : out of memory !\n"); exit(1); } res->parent = NULL; res->name = strdup("/"); res->nb_elem = 0; res->elems = (void *) malloc(16 * sizeof(void *)); res->names = (void *) malloc(16 * sizeof(char *)); res->flags = (char *) malloc(16 * sizeof(char)); if ((res->elems == NULL) || (res->flags == NULL) || (res->names == NULL)) { fprintf(stderr, "rpmCreateRealRoot : out of memory !\n"); exit(1); } res->max_elem = 16; return(res); } /* * Add a given file to a directory. */ int rpmGetRealFile(rpmRealDirPtr parent, const char *file, void *elem) { int i, min, max; int res; /* * Search the index for the new file. */ min = i = 0; if (parent->nb_elem == 0) goto add_first_elem; max = parent->nb_elem - 1; while (min < max) { i = min + max; i /= 2; res = strcmp(file, parent->names[i]); if (res < 0) max = i - 1; else if (res > 0) min = i + 1; else { return(i); } } i = min; res = strcmp(file, parent->names[i]); if (res == 0) { return(i); } else if (res > 0) i++; /* * If more space is needed grow the arrays. */ if (parent->nb_elem >= parent->max_elem) { parent->max_elem *= 2; parent->elems = (void *) realloc(parent->elems, parent->max_elem * sizeof(void *)); parent->names = (void *) realloc(parent->names, parent->max_elem * sizeof(char *)); parent->flags = (void *) realloc(parent->flags, parent->max_elem * sizeof(char)); if ((parent->elems == NULL) || (parent->flags == NULL) || (parent->names == NULL)) { fprintf(stderr, "rpmAddRealFile : out of memory !\n"); exit(1); } } /* * Shift the end of the arrays. */ if (i < parent->nb_elem) { memmove(&parent->elems[i + 1], &parent->elems[i], (parent->nb_elem - i) * sizeof(void *)); memmove(&parent->names[i + 1], &parent->names[i], (parent->nb_elem - i) * sizeof(char *)); memmove(&parent->flags[i + 1], &parent->flags[i], (parent->nb_elem - i) * sizeof(char)); } add_first_elem: parent->nb_elem++; /* * Create the new entry. */ parent->elems[i] = elem; parent->names[i] = strdup(file); parent->flags[i] = 0; return(i); } /* * Get a given subdirectory of a directory. If it doesn't exist, * the subdir is added. The filename may have been added as a file * in that case turn it into a directory. */ rpmRealDirPtr rpmGetRealSubdir(rpmRealDirPtr parent, const char *subdir) { rpmRealDirPtr res; int i = rpmGetRealFile(parent, subdir, NULL); /* * Check if such a directory already exists. */ if (parent->flags[i] & RPM_ELEM_DIRECTORY) { return((rpmRealDirPtr) parent->elems[i]); } /* * Allocate a new rpmRealDir block and link it in. */ res = (rpmRealDirPtr) malloc(sizeof(rpmRealDir)); if (res == NULL) { fprintf(stderr, "rpmCreateRealRoot : out of memory !\n"); exit(1); } res->parent = parent; res->name = strdup(subdir); res->nb_elem = 0; res->elems = (void *) malloc(16 * sizeof(void *)); res->names = (void *) malloc(16 * sizeof(char *)); res->flags = (char *) malloc(16 * sizeof(char)); if ((res->elems == NULL) || (res->flags == NULL) || (res->names == NULL)) { fprintf(stderr, "rpmCreateRealRoot : out of memory !\n"); exit(1); } res->max_elem = 16; parent->elems[i] = res; parent->flags[i] = RPM_ELEM_DIRECTORY; return(res); } /* * Add a file to the real filesystem tree, and all memorize which * RPM provided it */ void rpmAddRealFile(rpmRealDirPtr root, const char *file, rpmDataPtr rpm) { static char path[2000]; char *filename; char *cur, save; rpmRealDirPtr curDir = root; if (root == NULL) return; if (file == NULL) return; if (rpm == NULL) return; strncpy(path, file, sizeof(path)); filename = &path[0]; if (*filename != '/') { if (verbose > 1) fprintf(stderr, "rpmAddRealFile : %s invalid\n", file); return; } cur = ++filename; while (*cur != '\0') { if (*cur == '/') { *cur = '\0'; curDir = rpmGetRealSubdir(curDir, filename); *cur = '/'; cur++; while (*cur == '/') cur++; filename = cur; } else if ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || (*cur == '\r')) { break; } else cur++; } if (*filename == '\0') return; save = *cur; *cur = '\0'; rpmGetRealFile(curDir, filename, rpm); *cur = save; } /* * Merge two real tree, this is somewhat messy since * we keep references to only one source package even if * two different distributions carries the same file (which * have a high probability). * * NOTE : the old trees are destoyed !!! */ rpmRealDirPtr rpmMergeRealRoots(rpmRealDirPtr root1, rpmRealDirPtr root2) { rpmRealDirPtr base, add; int j; if (root1 == NULL) return(root2); if (root2 == NULL) return(root1); /* * We keep the bigger one as-is and add-in the smaller one. */ if (root1->nb_elem > root2->nb_elem) { base = root1; add = root2; } else { base = root2; add = root1; } /* * For every element in add, search for the same entry in base. * If both exists, keep only the directories, if both are directories, * recurse ! */ for (j = 0;j < add->nb_elem;j++) { int i, min, max; int res; /* * Search the index for the new file. */ min = i = 0; max = base->nb_elem - 1; while (min < max) { i = min + max; i /= 2; res = strcmp(add->names[j], base->names[i]); if (res < 0) max = i - 1; else if (res > 0) min = i + 1; else goto entry_found; } i = min; res = strcmp(add->names[j], base->names[i]); if (res == 0) { goto entry_found; } else if (res > 0) i++; /* * The name was not found in base, add it ! * If more space is needed grow the arrays. */ if (base->nb_elem >= base->max_elem) { base->max_elem *= 2; base->elems = (void *) realloc(base->elems, base->max_elem * sizeof(void *)); base->names = (void *) realloc(base->names, base->max_elem * sizeof(char *)); base->flags = (void *) realloc(base->flags, base->max_elem * sizeof(char)); if ((base->elems == NULL) || (base->flags == NULL) || (base->names == NULL)) { fprintf(stderr, "rpmMergeRealRoots : out of memory !\n"); exit(1); } } /* * Shift the end of the arrays. */ if (i < base->nb_elem) { memmove(&base->elems[i + 1], &base->elems[i], (base->nb_elem - i) * sizeof(void *)); memmove(&base->names[i + 1], &base->names[i], (base->nb_elem - i) * sizeof(char *)); memmove(&base->flags[i + 1], &base->flags[i], (base->nb_elem - i) * sizeof(char)); } base->nb_elem++; /* * Create the new entry. */ base->elems[i] = add->elems[j]; base->names[i] = add->names[j]; base->flags[i] = add->flags[j]; continue; entry_found: /* * the name is present in both directories. */ if ((base->flags[i] & RPM_ELEM_DIRECTORY) && (add->flags[j] & RPM_ELEM_DIRECTORY)) { /* Two subdirectories, merge them */ base->elems[i] = rpmMergeRealRoots(base->elems[i], add->elems[j]); free(add->names[j]); } else if (base->flags[i] & RPM_ELEM_DIRECTORY) { /* Keep base directory */ free(add->names[j]); } else if (add->flags[j] & RPM_ELEM_DIRECTORY) { /* Keep add directory */ free(base->names[i]); base->names[i] = add->names[j]; base->elems[i] = add->elems[j]; base->flags[i] = add->flags[j]; } else { /* Two files, arbitrarily keep base one, this is simpler ! */ free(add->names[j]); } } free(add->elems); free(add->names); free(add->flags); free(add->name); free(add); return(base); } /* * Destroy a real tree root. */ void rpmDestroyRealRoot(rpmRealDirPtr dir) { int i; for (i = 0;i < dir->nb_elem;i++) { if (dir->flags[i] & RPM_ELEM_DIRECTORY) { rpmDestroyRealRoot(dir->elems[i]); } free(dir->names[i]); } free(dir->elems); free(dir->names); free(dir->flags); free(dir); } /* * Dump a real tree subdir. */ void rpmDumpRealDir(rpmRealDirPtr dir, char *buffer, int index) { int i; for (i = 0;i < dir->nb_elem;i++) { if (dir->flags[i] & RPM_ELEM_DIRECTORY) { sprintf(&buffer[index], "%s/", dir->names[i]); rpmDumpRealDir(dir->elems[i], buffer, strlen(buffer)); buffer[index] = '\0'; } else { printf("%s%s\n", buffer, dir->names[i]); } } } /* * Dump a real tree root. */ void rpmDumpRealRoot(rpmRealDirPtr dir) { char buf[1000] = "/"; if (dir == NULL) return; printf("\n Tree :\n\n"); rpmDumpRealDir(dir, buf, 1); printf("\n\n"); }