Annotation of rpm2html/rpmopen.c, revision 1.62

1.1       veillard    1: /*
                      2:  * rpmopen.c : open an extract informations from RPM files.
                      3:  *
1.50      veillard    4:  * See Copyright for the status of this software.
1.1       veillard    5:  *
1.62    ! daniel      6:  * $Id: rpmopen.c,v 1.61 1998/11/15 05:10:11 daniel Exp $
1.1       veillard    7:  */
                      8: 
1.9       veillard    9: #include <config.h>
1.1       veillard   10: #include <sys/types.h>
                     11: #include <sys/stat.h>
1.9       veillard   12: #ifdef HAVE_FCNTL_H
1.1       veillard   13: #include <fcntl.h>
1.9       veillard   14: #endif
1.1       veillard   15: #include <stdio.h>
                     16: #include <stdlib.h>
                     17: #include <string.h>
1.9       veillard   18: #ifdef HAVE_UNISTD_H
1.1       veillard   19: #include <unistd.h>
1.9       veillard   20: #endif
1.6       veillard   21: #include <dirent.h>
1.13      veillard   22: #include <errno.h>
1.31      veillard   23: #include <time.h>
1.1       veillard   24: 
                     25: #include <rpm/rpmlib.h>
                     26: 
                     27: #include "rpmdata.h"
1.7       veillard   28: #include "html.h"
1.40      httpng     29: #include "rdf.h"
1.8       veillard   30: #include "rpm2html.h"
1.12      veillard   31: #include "language.h"
1.1       veillard   32: 
                     33: /*
                     34:  * Get the internal number associated to an RPM tag.
                     35:  */
                     36: static int getTagNumber(char *tag) {
                     37:     int i;
                     38:     const struct headerTagTableEntry * t;
                     39: 
                     40:     for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
                     41:        if (!strcasecmp(tag, t->name)) return(t->val);
                     42:     }
                     43:     fprintf(stderr, "getTagNumber(%s) : unknown tag !\n", tag);
                     44:     return(-1);
                     45: }
                     46: 
                     47: /*
1.58      daniel     48:  * Free up the extra data not needed for the last stage processing.
                     49:  */
                     50: 
                     51: void rpmFreeExtraData(rpmDataPtr rpm) {
                     52:     rpmExtraDataPtr extra;
                     53: 
                     54:     if ((rpm == NULL) || (rpm->extra == NULL)) return;
                     55:     extra = rpm->extra;
1.61      daniel     56:     if (extra->packager != NULL) debugFree(extra->packager);
                     57:     if (extra->description != NULL) debugFree(extra->description);
                     58:     if (extra->copyright != NULL) debugFree(extra->copyright);
                     59:     if (extra->changelog != NULL) debugFree(extra->changelog);
                     60:     if (extra->srcrpm != NULL) debugFree(extra->srcrpm);
                     61:     if (extra->host != NULL) debugFree(extra->host);
                     62:     if (extra->resources != NULL) debugFree(extra->resources);
                     63:     if (extra->requires != NULL) debugFree(extra->requires);
                     64:     if (extra->filelist != NULL) debugFree(extra->filelist);
                     65:     debugFree(extra);
1.58      daniel     66: }
                     67: 
                     68: /*
1.59      daniel     69:  * check a dependancy name to get rid of bad deps due to bad scripts
1.55      daniel     70:  * or spec files.
1.53      veillard   71:  */
                     72: int checkResourceName(const char *res) {
1.59      daniel     73:     int isname = 0;
                     74:     const char *base = res;
1.55      daniel     75: 
1.53      veillard   76:     if (*res == 0) return(0);
1.55      daniel     77: 
                     78:     /*
1.59      daniel     79:      * we only accept absolute pathnames.
1.55      daniel     80:      */
1.59      daniel     81:     if (*res == '/') isname = 1;
1.53      veillard   82:     while (*res != 0) {
1.59      daniel     83:         if (((*res >= 'A') && (*res <= 'Z')) ||
                     84:            ((*res >= 'a') && (*res <= 'z')) ||
1.53      veillard   85:             ((*res >= '0') && (*res <= '9')) ||
1.55      daniel     86:            (*res == '-') || (*res == '.') ||
                     87:            (*res == '@') || (*res == '_') ||
1.59      daniel     88:            (*res == '+') ||
                     89:            ((*res == '/') && (isname == 1)))
1.53      veillard   90:            res++;
                     91:        else
                     92:            return(0);
1.59      daniel     93:        if ((res - base) > 100) return(0);
                     94:     }
                     95:     return(1);
                     96: }
                     97: 
                     98: /*
                     99:  * check a release name
                    100:  */
                    101: int checkReleaseName(const char *res) {
                    102:     const char *base = res;
                    103: 
                    104:     if (*res == 0) return(0);
                    105: 
                    106:     while (*res != 0) {
                    107:         if (((*res >= 'A') && (*res <= 'Z')) ||
                    108:            ((*res >= 'a') && (*res <= 'z')) ||
                    109:             ((*res >= '0') && (*res <= '9')) ||
                    110:            (*res == '-') || (*res == '.') ||
                    111:            (*res == '@') || (*res == '_') ||
                    112:            (*res == '+'))
                    113:            res++;
                    114:        else
                    115:            return(0);
                    116:        if ((res - base) > 20) return(0);
                    117:     }
                    118:     return(1);
                    119: }
                    120: 
                    121: /*
                    122:  * check a group name
                    123:  */
                    124: int checkGroupName(const char *res) {
                    125:     const char *base = res;
                    126: 
                    127:     /* Grrr !!! Suse packages have an empty Group name
                    128:     if (*res == 0) return(0);
                    129:      */
                    130: 
                    131:     while (*res != 0) {
                    132:         if (((*res >= 'A') && (*res <= 'Z')) ||
                    133:            ((*res >= 'a') && (*res <= 'z')) ||
                    134:             ((*res >= '0') && (*res <= '9')) ||
                    135:            (*res == ' ') || (*res == '.') ||
                    136:            (*res == '+') || (*res == '/') ||
                    137:            (*res == '-'))
                    138:            res++;
                    139:        else
                    140:            return(0);
                    141:        if ((res - base) > 60) return(0);
                    142:     }
                    143:     return(1);
                    144: }
                    145: 
                    146: /*
                    147:  * check a version name
                    148:  */
                    149: int checkVersionName(const char *res) {
                    150:     const char *base = res;
                    151: 
                    152:     if (*res == 0) return(0);
                    153: 
                    154:     while (*res != 0) {
                    155:         if (((*res >= 'A') && (*res <= 'Z')) ||
                    156:            ((*res >= 'a') && (*res <= 'z')) ||
                    157:             ((*res >= '0') && (*res <= '9')) ||
                    158:            (*res == '-') || (*res == '.') ||
                    159:            (*res == '@') || (*res == '_') ||
                    160:            (*res == '+'))
                    161:            res++;
                    162:        else
                    163:            return(0);
                    164:        if ((res - base) > 20) return(0);
1.53      veillard  165:     }
                    166:     return(1);
                    167: }
1.60      daniel    168: 
1.53      veillard  169: /*
1.11      veillard  170:  * rpmAnalyze : analyze an RPM record, read and parse the header and 
                    171:  *              fill the informations in the database.
1.1       veillard  172:  */
1.62    ! daniel    173: #define ENTRY_CLEANUP(p)                                               \
        !           174:     if ((type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE)&&\
        !           175:         (p != NULL)) { free((p)); p = NULL; }
        !           176: 
1.60      daniel    177: static char *buffer = NULL;
                    178: static int buffer_size = 50 * 1024 * sizeof(char);
1.61      daniel    179: 
1.36      veillard  180: rpmDataPtr rpmAnalyze(char *nameRpm, Header h, rpmDirPtr dir,
1.52      daniel    181:                       rpmSubdirPtr tree, time_t stamp, int isSource) {
1.11      veillard  182:     int installed = dir->installbase;
1.2       veillard  183:     char * name = NULL, * version = NULL, * release = NULL;
1.1       veillard  184:     int_32 count, type;
1.2       veillard  185:     void * p = NULL;
1.10      veillard  186:     int val, i, j;
1.1       veillard  187:     rpmDataPtr rpm = NULL;
1.11      veillard  188:     static char nameBuffer[500];
1.1       veillard  189: 
1.41      veillard  190:     if (buffer == NULL) {
1.61      daniel    191:         buffer = (char *) debugMalloc(buffer_size);
1.41      veillard  192:        if (buffer == NULL) {
                    193:            fprintf(stderr, "cannot allocate %d bytes: %s\n", buffer_size,
                    194:                    strerror(errno));
                    195:            exit(1);
                    196:        }
                    197:     }
                    198: 
1.1       veillard  199:     /* extract informations from the header */
                    200:     headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
1.49      veillard  201:     if (name == NULL) {
                    202:         fprintf(stderr, "Invalid package %s : no name\n", nameRpm);
                    203:        return(NULL);
                    204:     }
                    205:     if (!(((name[0] >= 'a') && (name[0] <= 'z')) ||
                    206:           ((name[0] >= 'A') && (name[0] <= 'Z')) ||
                    207:          ((name[0] >= '0') && (name[0] <= '9')))) {
                    208:         fprintf(stderr, "Invalid package %s : garbled name\n", nameRpm);
1.62    ! daniel    209:        ENTRY_CLEANUP(name)
1.49      veillard  210:        return(NULL);
                    211:     }    
1.59      daniel    212:     if (!checkResourceName(name)) {
                    213:         fprintf(stderr, "Invalid package %s : garbled name\n", nameRpm);
1.62    ! daniel    214:        ENTRY_CLEANUP(name)
1.59      daniel    215:        return(NULL);
                    216:     }
1.1       veillard  217:     headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
1.49      veillard  218:     if ((version == NULL) || (version[0] == 0)) {
                    219:         fprintf(stderr, "Invalid package %s : version invalid\n", nameRpm);
1.62    ! daniel    220:        ENTRY_CLEANUP(name)
        !           221:        ENTRY_CLEANUP(version)
1.49      veillard  222:        return(NULL);
                    223:     }
1.59      daniel    224:     if (!checkVersionName(version)) {
                    225:         fprintf(stderr, "Invalid package %s : garbled version\n", nameRpm);
1.62    ! daniel    226:        ENTRY_CLEANUP(name)
        !           227:        ENTRY_CLEANUP(version)
1.59      daniel    228:        return(NULL);
                    229:     }
1.1       veillard  230:     headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
1.49      veillard  231:     if ((release == NULL) || (release[0] == 0)) {
                    232:         fprintf(stderr, "Invalid package %s : release invalid\n", nameRpm);
1.62    ! daniel    233:        ENTRY_CLEANUP(name)
        !           234:        ENTRY_CLEANUP(version)
        !           235:        ENTRY_CLEANUP(release)
1.49      veillard  236:        return(NULL);
                    237:     }
1.59      daniel    238:     if (!checkReleaseName(release)) {
                    239:         fprintf(stderr, "Invalid package %s : garbled release\n", nameRpm);
1.62    ! daniel    240:        ENTRY_CLEANUP(name)
        !           241:        ENTRY_CLEANUP(version)
        !           242:        ENTRY_CLEANUP(release)
1.59      daniel    243:        return(NULL);
                    244:     }
1.1       veillard  245:         
1.58      daniel    246:     /* allocate a new rpmData block, and an rpmExtraData block fill them */
1.61      daniel    247:     rpm = (rpmDataPtr) debugMalloc(sizeof(rpmData));
1.1       veillard  248:     if (rpm == NULL) {
1.41      veillard  249:         fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmData),
                    250:                strerror(errno));
                    251:         return(NULL);
1.1       veillard  252:     }
1.44      veillard  253:     memset(rpm, 0, sizeof(rpmData));
1.61      daniel    254:     rpm->extra = (rpmExtraDataPtr) debugMalloc(sizeof(rpmExtraData));
1.58      daniel    255:     if (rpm == NULL) {
                    256:         fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmExtraData),
                    257:                strerror(errno));
                    258:         return(NULL);
                    259:     }
                    260:     memset(rpm->extra, 0, sizeof(rpmExtraData));
1.6       veillard  261:     rpm->dir = dir;
1.36      veillard  262:     if (tree) {
                    263:         if ((tree->rpmpath != NULL) && (tree->rpmpath[0] != '\0'))
1.61      daniel    264:            rpm->subdir = stringAdd(tree->rpmpath);
1.36      veillard  265:        else
                    266:            rpm->subdir = NULL;
                    267:     } else
                    268:        rpm->subdir = NULL;
1.58      daniel    269:     rpm->extra->stamp = stamp;
1.61      daniel    270:     rpm->name = stringAdd(name);
1.62    ! daniel    271:     ENTRY_CLEANUP(name)
1.61      daniel    272:     rpm->version = stringAdd(version);
1.62    ! daniel    273:     ENTRY_CLEANUP(version)
1.61      daniel    274:     rpm->release = stringAdd(release);
1.62    ! daniel    275:     ENTRY_CLEANUP(release)
1.1       veillard  276: 
1.26      veillard  277:     /* get all the resources provided by this RPM */
1.2       veillard  278:     if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, &p, &count) || !p) {
1.61      daniel    279:         rpm->summary = debugStrdup(localizedStrings[LANG_NO_SUMMARY]);
1.2       veillard  280:     } else {
1.61      daniel    281:        rpm->summary = debugStrdup((char *) p);
1.2       veillard  282:     }
1.62    ! daniel    283:     ENTRY_CLEANUP(p);
1.28      veillard  284:     if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, &p, &count) || !p ||
                    285:         (type != RPM_STRING_TYPE)) {
1.61      daniel    286:         rpm->extra->description = debugStrdup(localizedStrings[LANG_NO_DESCRIPTION]);
1.2       veillard  287:     } else {
1.61      daniel    288:        rpm->extra->description = debugStrdup((char *) p);
1.2       veillard  289:     }
1.62    ! daniel    290:     ENTRY_CLEANUP(p);
1.28      veillard  291:     if (!headerGetEntry(h, RPMTAG_DISTRIBUTION, &type, &p, &count) || !p ||
                    292:         (type != RPM_STRING_TYPE)) {
1.61      daniel    293:         rpm->distribution = stringAdd(localizedStrings[LANG_UNKNOWN]);
1.2       veillard  294:     } else {
1.61      daniel    295:        rpm->distribution = stringAdd((char *) p);
1.2       veillard  296:     }
1.62    ! daniel    297:     ENTRY_CLEANUP(p);
1.52      daniel    298:     if (isSource) {
1.61      daniel    299:         rpm->arch = stringAdd("src");
1.11      veillard  300:        if (nameRpm == NULL) {
1.52      daniel    301:            sprintf(nameBuffer, "%s-%s-%s.src.rpm",
                    302:                    name, version, release);
1.11      veillard  303:            nameRpm = nameBuffer;
                    304:        }
1.2       veillard  305:     } else {
1.52      daniel    306:        if (!headerGetEntry(h, RPMTAG_ARCH, &type, &p, &count) || !p ||
                    307:            (type != RPM_STRING_TYPE)) {
                    308:            if (type == RPM_INT8_TYPE) {
                    309:                /*
                    310:                 * Old packages.
                    311:                 */
                    312:                switch (*((char *) p)) {
                    313:                    case 1:
1.61      daniel    314:                        rpm->arch = stringAdd("i386");
1.52      daniel    315:                        break;
                    316:                    default:
1.61      daniel    317:                        rpm->arch = stringAdd("src");
1.52      daniel    318:                        break;
                    319:                }
                    320:            } else
1.61      daniel    321:                rpm->arch = stringAdd(localizedStrings[LANG_NONE]);
1.52      daniel    322:            if (nameRpm == NULL) {
                    323:                sprintf(nameBuffer, "%s-%s-%s.rpm", name, version, release);
                    324:                nameRpm = nameBuffer;
                    325:            }
                    326:        } else {
1.61      daniel    327:            rpm->arch = stringAdd((char *) p);
1.52      daniel    328:            if (nameRpm == NULL) {
                    329:                sprintf(nameBuffer, "%s-%s-%s.%s.rpm",
                    330:                        name, version, release, (char *)p);
                    331:                nameRpm = nameBuffer;
                    332:            }
1.11      veillard  333:        }
1.62    ! daniel    334:        ENTRY_CLEANUP(p);
1.2       veillard  335:     }
1.28      veillard  336:     if (!headerGetEntry(h, RPMTAG_OS, &type, &p, &count) || !p ||
                    337:         (type != RPM_STRING_TYPE)) {
1.29      veillard  338:        if (type == RPM_INT8_TYPE) {
                    339:            /*
1.32      veillard  340:             * Old packages.
1.29      veillard  341:             */
                    342:            switch (*((char *) p)) {
                    343:                case 1:
1.61      daniel    344:                    rpm->os = stringAdd("linux");
1.29      veillard  345:                    break;
                    346:                default:
1.61      daniel    347:                    rpm->os = stringAdd("linux");
1.29      veillard  348:                    break;
                    349:            }
                    350:        } else
1.61      daniel    351:            rpm->os = stringAdd("");
1.7       veillard  352:     } else {
1.61      daniel    353:        rpm->os = stringAdd((char *) p);
1.7       veillard  354:     }
1.62    ! daniel    355:     ENTRY_CLEANUP(p);
1.28      veillard  356:     if (!headerGetEntry(h, RPMTAG_VENDOR, &type, &p, &count) || !p ||
                    357:         (type != RPM_STRING_TYPE)) {
1.7       veillard  358:         rpm->vendor = NULL;
1.2       veillard  359:     } else {
1.61      daniel    360:        rpm->vendor = stringAdd((char *) p);
1.2       veillard  361:     }
1.62    ! daniel    362:     ENTRY_CLEANUP(p);
1.28      veillard  363:     if (!headerGetEntry(h, RPMTAG_GROUP, &type, &p, &count) || !p ||
                    364:         (type != RPM_STRING_TYPE)) {
1.61      daniel    365:         rpm->group = stringAdd(localizedStrings[LANG_NO_GROUP]);
1.2       veillard  366:     } else {
1.61      daniel    367:        rpm->group = stringAdd((char *) p);
1.59      daniel    368:     }
1.62    ! daniel    369:     ENTRY_CLEANUP(p);
1.59      daniel    370:     if (!checkGroupName(rpm->group)) {
                    371:         fprintf(stderr, "Invalid package %s : garbled group\n", nameRpm);
1.61      daniel    372:        stringFree(rpm->name);
                    373:        stringFree(rpm->version);
                    374:        stringFree(rpm->release);
                    375:        debugFree(rpm->summary);
                    376:        stringFree(rpm->distribution);
                    377:        stringFree(rpm->arch);
                    378:        stringFree(rpm->os);
                    379:        stringFree(rpm->vendor);
                    380:        stringFree(rpm->group);
                    381:        debugFree(rpm);
1.59      daniel    382:        return(NULL);
1.2       veillard  383:     }
1.28      veillard  384:     if (!headerGetEntry(h, RPMTAG_BUILDHOST, &type, &p, &count) || !p ||
                    385:         (type != RPM_STRING_TYPE)) {
1.61      daniel    386:         rpm->extra->host = debugStrdup(localizedStrings[LANG_NO_HOST]);
1.2       veillard  387:     } else {
1.61      daniel    388:        rpm->extra->host = debugStrdup((char *) p);
1.2       veillard  389:     }
1.62    ! daniel    390:     ENTRY_CLEANUP(p);
1.2       veillard  391:     if (!headerGetEntry(h, RPMTAG_SIZE, &type, &p, &count) || !p) {
                    392:         rpm->size = 0;
                    393:     } else {
                    394:        rpm->size = *((int *) p);
                    395:     }
1.62    ! daniel    396:     ENTRY_CLEANUP(p);
1.11      veillard  397:     if (installed) {
                    398:        if (!headerGetEntry(h, RPMTAG_INSTALLTIME, &type, &p, &count) || !p) {
                    399:            rpm->date = 0;
                    400:        } else {
                    401:            rpm->date = *((int_32 *) p);
                    402:        }
1.62    ! daniel    403:        ENTRY_CLEANUP(p);
1.2       veillard  404:     } else {
1.11      veillard  405:        if (!headerGetEntry(h, RPMTAG_BUILDTIME, &type, &p, &count) || !p) {
                    406:            rpm->date = 0;
                    407:        } else {
                    408:            rpm->date = *((int_32 *) p);
                    409:        }
1.62    ! daniel    410:        ENTRY_CLEANUP(p);
1.2       veillard  411:     }
1.28      veillard  412:     if (!headerGetEntry(h, RPMTAG_SOURCERPM, &type, &p, &count) || !p ||
                    413:         (type != RPM_STRING_TYPE)) {
1.61      daniel    414:         rpm->extra->srcrpm = debugStrdup("");
1.2       veillard  415:     } else {
1.61      daniel    416:        rpm->extra->srcrpm = debugStrdup((char *) p);
1.2       veillard  417:     }
1.62    ! daniel    418:     ENTRY_CLEANUP(p);
1.28      veillard  419:     if (!headerGetEntry(h, RPMTAG_URL, &type, &p, &count) || !p ||
                    420:         (type != RPM_STRING_TYPE)) {
1.7       veillard  421:         rpm->url = NULL;
                    422:     } else {
1.61      daniel    423:        rpm->url = debugStrdup((char *) p);
1.7       veillard  424:     }
1.62    ! daniel    425:     ENTRY_CLEANUP(p);
1.28      veillard  426:     if (!headerGetEntry(h, RPMTAG_PACKAGER, &type, &p, &count) || !p ||
                    427:         (type != RPM_STRING_TYPE)) {
1.58      daniel    428:         rpm->extra->packager = NULL;
1.7       veillard  429:     } else {
1.61      daniel    430:        rpm->extra->packager = debugStrdup((char *) p);
1.7       veillard  431:     }
1.62    ! daniel    432:     ENTRY_CLEANUP(p);
1.28      veillard  433:     if (!headerGetEntry(h, RPMTAG_COPYRIGHT, &type, &p, &count) || !p ||
                    434:         (type != RPM_STRING_TYPE)) {
1.58      daniel    435:         rpm->extra->copyright = NULL;
1.7       veillard  436:     } else {
1.61      daniel    437:        rpm->extra->copyright = debugStrdup((char *) p);
1.7       veillard  438:     }
1.62    ! daniel    439:     ENTRY_CLEANUP(p);
1.31      veillard  440:     /* Pick up changelog entries */
                    441:     if (!headerGetEntry(h, RPMTAG_CHANGELOGTEXT, &type, &p, &count) || !p) {
1.58      daniel    442:         rpm->extra->changelog = NULL;
1.31      veillard  443:     } else {
                    444:       time_t *dates;
                    445:       char **names;
                    446:       char **holdp = (char **)p;
                    447:       char *cp;
                    448:       struct tm *tm_buf;
                    449:       int i, len, pos;
                    450:       char date_string[50];
                    451:       char *res = buffer;
1.42      veillard  452: 
1.31      veillard  453:       *res = '\0';
                    454:       headerGetEntry(h, RPMTAG_CHANGELOGTIME, &type, (void *)&dates, &count);
                    455:       headerGetEntry(h, RPMTAG_CHANGELOGNAME, &type, (void *)&names, &count);
                    456:       for (i = 0;  i < count;  i++) {
1.42      veillard  457:         if ((res - buffer) > (buffer_size - 1024)) {
                    458:            int delta = res - buffer;
                    459: 
1.41      veillard  460:            buffer_size *= 2;
1.61      daniel    461:            buffer = (char *) debugRealloc(buffer, buffer_size);
1.42      veillard  462:            if (buffer == NULL) {
                    463:                fprintf(stderr, "cannot re-allocate %d bytes: %s\n",
                    464:                        buffer_size, strerror(errno));
                    465:                exit(1);
                    466:            }
                    467:            res = &buffer[delta];
1.41      veillard  468:        }
1.31      veillard  469:        tm_buf = localtime(&dates[i]);
                    470:         strftime(date_string, sizeof(date_string) - 1, "%a %b %d %Y", tm_buf);
                    471:        len = sprintf(res, "* %s %s\n", date_string, names[i]);
                    472:        res += len;
                    473:        cp = holdp[i];
                    474:        pos = 0;
                    475:        while (*cp) {
                    476:          if (pos++ == 0) {
                    477:            *res++ = ' ';
                    478:            *res++ = ' ';           
                    479:          }
                    480:          *res++ = *cp;
                    481:          if (*cp++ == '\n') pos = 0;
                    482:        }
                    483:        *res++ = '\n';
                    484:       }
                    485:       *res = '\0';
1.61      daniel    486:       rpm->extra->changelog = debugStrdup(buffer);
1.31      veillard  487:     }
1.62    ! daniel    488:     ENTRY_CLEANUP(p);
1.7       veillard  489:     if (rpm->vendor == NULL) {
1.61      daniel    490:         if (rpm->extra->packager != NULL) rpm->vendor = debugStrdup(rpm->extra->packager);
                    491:        else rpm->vendor = debugStrdup(localizedStrings[LANG_UNKNOWN]);
1.7       veillard  492:     }
1.2       veillard  493: 
1.61      daniel    494:     rpm->filename = debugStrdup(nameRpm);
1.11      veillard  495: 
1.48      veillard  496:     /* package-xxx.rpm provides at least the resource "package" */
1.1       veillard  497:     val = getTagNumber("RPMTAG_PROVIDES");
                    498:     if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
1.58      daniel    499:         rpm->extra->nb_resources = 1;
                    500:         rpm->extra->max_resources = 1;
1.61      daniel    501:        rpm->extra->resources = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) *
1.58      daniel    502:                                              rpm->extra->max_resources);
                    503:        if (rpm->extra->resources == NULL) {
1.48      veillard  504:            fprintf(stderr, ": ran out of memory\n");
                    505:            exit(1);
                    506:        }
1.58      daniel    507:        rpm->extra->resources[0] = rpmRessAdd(name, rpm, installed);
1.1       veillard  508:     } else {
1.58      daniel    509:         rpm->extra->max_resources = count + 1;
1.61      daniel    510:        rpm->extra->resources = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) *
1.58      daniel    511:                                              rpm->extra->max_resources);
                    512:        if (rpm->extra->resources == NULL) {
1.48      veillard  513:            fprintf(stderr, ": ran out of memory\n");
                    514:            exit(1);
1.1       veillard  515:        }
1.58      daniel    516:        rpm->extra->resources[0] = rpmRessAdd(name, rpm, installed);
                    517:         rpm->extra->nb_resources = 1;
1.1       veillard  518: 
1.58      daniel    519:         for (i = 0, j = rpm->extra->nb_resources; i < count;i++) {
1.53      veillard  520:            if (!checkResourceName(((char **) p)[i])) continue;
1.58      daniel    521:            rpm->extra->resources[j++] = rpmRessAdd(((char **) p)[i], rpm, installed);
1.4       veillard  522:        }
1.58      daniel    523:        rpm->extra->nb_resources = j;
1.4       veillard  524:     }
1.62    ! daniel    525:     ENTRY_CLEANUP(p);
1.4       veillard  526: 
                    527:     val = getTagNumber("RPMTAG_REQUIRENAME");
                    528:     if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
1.58      daniel    529:         rpm->extra->nb_requires = 0;
                    530:        rpm->extra->requires = NULL;
1.4       veillard  531:     } else {
1.58      daniel    532:         rpm->extra->max_requires = count;
1.61      daniel    533:        rpm->extra->requires = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) *
1.58      daniel    534:                                              rpm->extra->max_requires);
                    535:        if (rpm->extra->requires == NULL) {
1.48      veillard  536:            fprintf(stderr, ": ran out of memory\n");
                    537:            exit(1);
1.4       veillard  538:        }
                    539: 
1.58      daniel    540:        rpm->extra->nb_requires = 0;
1.53      veillard  541:         for (i = 0, j = 0; i < count;i++) {
                    542:            if (!checkResourceName(((char **) p)[i])) continue;
1.58      daniel    543:            rpm->extra->requires[j++] = rpmRequAdd(((char **) p)[i], rpm, installed);
1.1       veillard  544:        }
1.58      daniel    545:        rpm->extra->nb_requires = j;
1.5       veillard  546:     }
1.62    ! daniel    547:     ENTRY_CLEANUP(p);
1.5       veillard  548:     val = getTagNumber("RPMTAG_FILENAMES");
                    549:     if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
1.58      daniel    550:         rpm->extra->filelist = NULL; /* No filelist in the package ! */
1.5       veillard  551:     } else {
                    552:         char *ptr = buffer;
1.42      veillard  553: 
1.5       veillard  554:        for (i = 0; i < count;i++) {
1.42      veillard  555:            if ((ptr - buffer) > (buffer_size - 1024)) {
                    556:                int delta = ptr - buffer;
                    557: 
1.41      veillard  558:                buffer_size *= 2;
1.61      daniel    559:                buffer = (char *) debugRealloc(buffer, buffer_size);
1.42      veillard  560:                if (buffer == NULL) {
                    561:                    fprintf(stderr, "cannot re-allocate %d bytes: %s\n",
                    562:                            buffer_size, strerror(errno));
                    563:                    exit(1);
                    564:                }
                    565:                ptr = &buffer[delta];
1.41      veillard  566:            }
1.5       veillard  567:            ptr += sprintf(ptr, "%s\n", ((char **) p)[i]);
                    568:        }
1.61      daniel    569:        rpm->extra->filelist = debugStrdup(buffer);
1.1       veillard  570:     }
1.62    ! daniel    571:     ENTRY_CLEANUP(p);
1.1       veillard  572: 
1.37      veillard  573:     /* Add the package files to the real filesystem tree if asked for */
1.58      daniel    574:     if ((dir->build_tree != 0) && (rpm->extra->filelist != NULL)) {
1.37      veillard  575:         char *cur, *filename;
                    576:        
1.58      daniel    577:        cur = rpm->extra->filelist;
1.37      veillard  578:        while ((*cur != '\0') && (*cur != '/')) cur++;
                    579:        filename = cur;
                    580:        while (*cur != '\0') {
                    581:            if ((*cur == '\n') || (*cur == '\r')) {
                    582:                if (cur != filename)
                    583:                    rpmAddRealFile(dir->root, filename, rpm);
                    584:                while ((*cur != '\0') && (*cur != '/')) cur++;
                    585:                 filename = cur;
                    586:            } else
                    587:                cur++;
                    588:        }
                    589:        if (cur != filename)
                    590:            rpmAddRealFile(dir->root, filename, rpm);
                    591:     }
1.17      veillard  592: 
                    593:     /* Register this package */
                    594:     rpmAddSoftware(rpm);
1.7       veillard  595: 
                    596:     /* dump the HTML related to this package */
1.56      daniel    597:     if ((rpm2html_dump_html) && (dir->html))
1.40      httpng    598:        dumpRpmHtml(rpm, tree);
                    599:     if (rpm2html_dump_rdf)
                    600:        dumpRpmRdf(rpm, tree);
1.7       veillard  601: 
1.58      daniel    602:     /* free the extra data */
                    603:     rpmFreeExtraData(rpm);
1.8       veillard  604: 
                    605:     /* increment the counters */
1.11      veillard  606:     if (installed) {
                    607:        rpm2html_install_files++;
1.21      veillard  608:        rpm2html_install_size += rpm->size / 1024;
1.11      veillard  609:     } else {
                    610:        rpm2html_files++;
1.21      veillard  611:        rpm2html_size += rpm->size / 1024;
1.11      veillard  612:     }
1.7       veillard  613: 
1.32      veillard  614:     return(rpm);
1.11      veillard  615: }
                    616: 
                    617: /*
                    618:  * rpmOpen : open an RPM file, read and parse the header and 
                    619:  *           fill the informations in the database.
                    620:  */
1.35      veillard  621: rpmDataPtr rpmOpen(char *nameRpm, rpmDirPtr dir, rpmSubdirPtr tree) {
1.32      veillard  622:     rpmDataPtr cur;
1.11      veillard  623:     int fd;
                    624:     int rc;
                    625:     Header h = NULL;
                    626:     int isSource;
                    627:     char buffer[500];
1.20      veillard  628:     struct stat buf;
1.11      veillard  629: 
                    630:     /* open the file for reading */
1.35      veillard  631:     if (tree->htmlpath[0] != '\0')
                    632:        sprintf(buffer, "%s/%s/%s", dir->rpmdir, tree->rpmpath, nameRpm);
1.24      veillard  633:     else
                    634:        sprintf(buffer, "%s/%s", dir->rpmdir, nameRpm);
1.11      veillard  635:     if ((fd = open(buffer, O_RDONLY)) < 0) {
                    636:          fprintf(stderr, "open of %s failed: %s\n", buffer,
                    637:                 strerror(errno));
1.32      veillard  638:         return(NULL);
1.11      veillard  639:     }
                    640: 
1.20      veillard  641:     stat(buffer, &buf);
                    642: 
1.11      veillard  643:     /* read the RPM header */
                    644:     rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
                    645:     switch (rc) {
                    646:        case 0:
                    647:            if (!h) {
                    648:                fprintf(stderr,
                    649:                        "old format source packages cannot be queried\n");
1.32      veillard  650:                return(NULL);
1.11      veillard  651:            }
                    652:            break;
                    653:        case 1:
                    654:            fprintf(stderr, "%s does not appear to be a RPM package\n",
                    655:                    nameRpm);
1.32      veillard  656:            return(NULL);
1.11      veillard  657:        case 2:
                    658:            fprintf(stderr, "query of %s failed\n", nameRpm);
1.32      veillard  659:            return(NULL);
1.11      veillard  660:        default:
                    661:            fprintf(stderr, "rpmReadPackageHeader(%s): unknown error %d\n",
                    662:                    nameRpm, rc);
1.32      veillard  663:            return(NULL);
1.11      veillard  664:     }
                    665: 
1.52      daniel    666:     cur = rpmAnalyze(nameRpm, h, dir, tree, buf.st_mtime, isSource);
1.11      veillard  667: 
                    668:     /* free the header and close the descriptor */
                    669:     headerFree(h);
                    670:     close(fd);
1.1       veillard  671: 
1.32      veillard  672:     return(cur);
1.6       veillard  673: }
                    674: 
                    675: /*
1.22      veillard  676:  * Scan one directory for RPM files this is where the recursive handling
                    677:  * is done.
1.6       veillard  678:  */
1.35      veillard  679: static rpmDataPtr rpmOneDirScan(rpmDirPtr dir, rpmSubdirPtr tree) {
                    680:     rpmSubdirPtr subtree;
1.32      veillard  681:     rpmDataPtr ret = NULL, cur;
1.7       veillard  682:     char *filename;
1.22      veillard  683:     static char path[2000];
1.23      veillard  684:     struct stat buf;
1.7       veillard  685:     int len;
1.39      veillard  686:     DIR *d;
                    687:     struct dirent *file;
1.6       veillard  688: 
1.24      veillard  689: 
                    690:     /*
                    691:      * Create the directory for the HTML pages
                    692:      */
1.56      daniel    693:     if ((rpm2html_dump_html) && (dir->html)) {
1.45      veillard  694:        if (tree->htmlpath[0] != '\0')
                    695:            sprintf(path, "%s/%s", dir->dir, tree->htmlpath);
                    696:        else
                    697:            sprintf(path, "%s", dir->dir);
                    698:        createDirectory(path);
                    699:     }
1.43      veillard  700: 
                    701:     /*
                    702:      * Create the directory for the RDF pages
                    703:     if (rpm2html_rdf_dir != NULL) {
                    704:        if (tree->htmlpath[0] != '\0')
                    705:            sprintf(path, "%s/%s", rpm2html_rdf_dir, tree->htmlpath);
                    706:        else
                    707:            sprintf(path, "%s", rpm2html_rdf_dir);
                    708:         createDirectory(path);
                    709:     }
1.47      veillard  710:      */
1.24      veillard  711: 
                    712:     /*
                    713:      * Scan the repository.
                    714:      */
1.35      veillard  715:     if (tree->rpmpath[0] != '\0')
                    716:        sprintf(path, "%s/%s", dir->rpmdir, tree->rpmpath);
1.24      veillard  717:     else
                    718:        sprintf(path, "%s", dir->rpmdir);
1.51      veillard  719:     if (rpm2htmlVerbose > 1)
1.24      veillard  720:         fprintf(stderr, "Scanning directory %s\n", path);
                    721: 
1.39      veillard  722:     d = opendir(path);
                    723:     if (d == NULL) {
1.24      veillard  724:         fprintf(stderr, "Listing of %s failed: %s\n", path,
1.6       veillard  725:                strerror(errno));
1.35      veillard  726:         rpmRemoveSubdir(tree);
1.36      veillard  727:         rpmFreeSubdir(tree);
1.32      veillard  728:        return(NULL);
1.6       veillard  729:     } else {
1.39      veillard  730:         while ((file = readdir(d)) != NULL) {
1.32      veillard  731:            cur = NULL;
1.39      veillard  732:            filename = file->d_name;
1.7       veillard  733:            len = strlen(filename);
1.24      veillard  734: 
                    735:            /*
                    736:             * Compute the full path
                    737:             */
1.35      veillard  738:            if (tree->rpmpath[0] != '\0')
                    739:                sprintf(path, "%s/%s/%s", dir->rpmdir, tree->rpmpath,
                    740:                        filename);
1.22      veillard  741:            else
1.24      veillard  742:                sprintf(path, "%s/%s", dir->rpmdir, filename);
1.22      veillard  743: 
                    744:            /*
1.25      veillard  745:             * Stat() the file to detect directory and symlimks
                    746:             */
1.30      veillard  747:            if (lstat(path, &buf) != 0) {
1.25      veillard  748:                fprintf(stderr, "Couldn't stat(%s)\n", path);
                    749:                continue;
                    750:            }
1.35      veillard  751: 
1.25      veillard  752:            /*
                    753:             * Don't follow of analyze symlinks,
                    754:             */
                    755:             if (S_ISLNK(buf.st_mode)) {
1.51      veillard  756:                if (rpm2htmlVerbose)
1.25      veillard  757:                    fprintf(stderr, "Dropping symlink %s\n", path);
                    758:                continue;
                    759:            }
1.35      veillard  760: 
1.25      veillard  761:            /*
1.23      veillard  762:             * Check for RPM files by looking at the suffix
1.54      veillard  763:             * Note that SuSE source RPMs have a ".spm" suffix
1.22      veillard  764:             */
1.54      veillard  765:            else if (((len >= 5) &&
                    766:                       (!strcasecmp(&filename[len - 4], ".rpm"))) ||
                    767:                     ((len >= 5) &&
                    768:                       (!strcasecmp(&filename[len - 4], ".spm")))) {
1.35      veillard  769:                cur = rpmOpen(filename, dir, tree);
1.44      veillard  770:            }
                    771: 
                    772:            /*
                    773:             * Check for RDF files by looking at the suffix
                    774:             */
                    775:            else if ((len >= 5) && (!strcasecmp(&filename[len - 4], ".rdf"))) {
                    776:                cur = rpmOpenRdf(filename, dir, tree);
1.22      veillard  777:            }
1.35      veillard  778: 
1.22      veillard  779:            /*
1.23      veillard  780:             * Else if this is a directory, recurse !
1.22      veillard  781:             */
1.25      veillard  782:            else if (S_ISDIR(buf.st_mode)) {
                    783:                if (filename[0] != '.') {
1.57      daniel    784:                    subtree = rpmNewSubdir(tree, filename, NULL, NULL, NULL, 0);
1.35      veillard  785:                    cur = rpmOneDirScan(dir, subtree);
1.25      veillard  786:                }
1.22      veillard  787:            }
1.32      veillard  788:            if (cur != NULL) ret = rpmAddList(ret, cur);
1.7       veillard  789:        }
1.6       veillard  790:     }
1.39      veillard  791:     closedir(d);
1.33      veillard  792: 
                    793:     /*
                    794:      * Dump the pages related to this directory.
                    795:      */
1.35      veillard  796:     if (ret != NULL) ret = dumpDirIndex(dir, tree, ret);
1.36      veillard  797:     else {
                    798:         rpmRemoveSubdir(tree);
                    799:        rpmFreeSubdir(tree);
                    800:     }
1.35      veillard  801: 
1.32      veillard  802:     return(ret);
1.22      veillard  803: }
                    804: 
                    805: /*
                    806:  * Scan a directory for RPM files.
                    807:  */
1.35      veillard  808: static rpmDataPtr rpmDirScan(rpmDirPtr dir, rpmSubdirPtr tree) {
1.37      veillard  809:     rpmSubdirPtr cur;
                    810:     rpmDataPtr ret;
                    811:     
1.56      daniel    812:     if ((rpm2html_dump_html) && (dir->html) && (dir->build_tree != 0)) {
1.37      veillard  813:        dir->root = rpmCreateRealRoot();
                    814:     }
                    815:     cur = rpmNewSubdir(tree, dir->name,
1.57      daniel    816:               dir->subdir == NULL ? "" : dir->subdir, "", dir->color,
                    817:              dir->html);
1.37      veillard  818:     ret = rpmOneDirScan(dir, cur);
1.38      veillard  819:     rpmDumpHtmlRealRoot(dir);
1.37      veillard  820:     return(ret);
1.6       veillard  821: }
                    822: 
                    823: /*
1.11      veillard  824:  * Scan the local RPM database for RPM files.
                    825:  */
1.32      veillard  826: static rpmDataPtr rpmBaseScan(rpmDirPtr dir) {
1.37      veillard  827:     static char path[2000];
1.32      veillard  828:     rpmDataPtr ret = NULL, cur;
1.11      veillard  829:     rpmdb db;
                    830:     Header h = NULL;
1.32      veillard  831:     int offset;
1.11      veillard  832:     char *prefix = "/";
                    833: 
1.37      veillard  834:     /*
                    835:      * Create the directory for the HTML pages
                    836:      */
1.56      daniel    837:     if ((rpm2html_dump_html) && (dir->html)) {
1.45      veillard  838:        if (dir->subdir)
                    839:            sprintf(path, "%s/%s", dir->dir, dir->subdir);
                    840:        else
                    841:            sprintf(path, "%s", dir->dir);
                    842:        createDirectory(path);
                    843:     }
                    844: 
                    845:     /*
                    846:      * Create the directory for the RDF pages
                    847:      */
                    848:     if (rpm2html_rdf_dir != NULL) {
                    849:        if (dir->subdir)
                    850:            sprintf(path, "%s/%s", rpm2html_rdf_dir, dir->subdir);
                    851:        else
                    852:            sprintf(path, "%s", rpm2html_rdf_dir);
                    853:         createDirectory(path);
                    854:     }
1.37      veillard  855: 
1.11      veillard  856:     if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
1.32      veillard  857:         return(NULL);
1.11      veillard  858:     }
                    859:     offset = rpmdbFirstRecNum(db);
                    860:     while (offset) {
                    861:         h = rpmdbGetRecord(db, offset);
                    862:        if (!h) {
                    863:            fprintf(stderr, "could not read database record!\n");
1.32      veillard  864:            return(ret);
1.11      veillard  865:        }
1.52      daniel    866:        cur = rpmAnalyze(NULL, h, dir, NULL, 0, 0);
1.32      veillard  867:        if (cur != NULL) ret = rpmAddList(ret, cur);
1.11      veillard  868:        headerFree(h);
                    869:        offset = rpmdbNextRecNum(db, offset);
                    870:     }
                    871:     rpmdbClose(db);
                    872: 
1.32      veillard  873:     return(ret);
1.11      veillard  874: }
                    875: 
                    876: /*
1.6       veillard  877:  * Scan all registered directories.
                    878:  * One fist check for completeness of the informations in
                    879:  * the rpmDir structure.
                    880:  */
                    881: 
1.32      veillard  882: rpmDataPtr rpmDirScanAll(void) {
1.18      veillard  883:     rpmDirPtr dir, next;
1.32      veillard  884:     rpmDataPtr ret = NULL, cur;
1.46      veillard  885:     int maxLists = 50;
                    886:     rpmDataPtr *rpmLists;
1.35      veillard  887:     int nbLists = 0;
                    888:     int i;
1.18      veillard  889: 
                    890:     /*
                    891:      * first reverse the list ....
                    892:      */
                    893:     dir = dirList;
                    894:     dirList = NULL;
                    895:     while (dir != NULL) {
                    896:         next = dir->next;
                    897:        dir->next = dirList;
                    898:        dirList = dir;
                    899:        dir = next;
                    900:     }
1.57      daniel    901:     dir = dirList;
1.18      veillard  902: 
1.35      veillard  903:     /*
                    904:      * Allocate a directory tree.
                    905:      */
1.57      daniel    906:     dirTree = rpmNewSubdir(NULL, "", "", "", NULL, 1);
1.6       veillard  907: 
1.61      daniel    908:     rpmLists = (rpmDataPtr *) debugMalloc(maxLists * sizeof(rpmDataPtr));
1.46      veillard  909:     if (rpmLists == NULL) {
                    910:         fprintf(stderr, "rpmDirScanAll : running out of memory !\n");
                    911:        exit(1);
                    912:     }
                    913: 
1.6       veillard  914:     while (dir != NULL) {
1.32      veillard  915:         cur  = NULL;
                    916: 
1.14      veillard  917:        /*
                    918:         * Override default setting.
                    919:         */
1.15      veillard  920:        if ((dir->maint == NULL) && (rpm2html_maint != NULL))
1.61      daniel    921:            dir->maint = debugStrdup(rpm2html_maint);
1.15      veillard  922:        if ((dir->mail == NULL) && (rpm2html_mail != NULL))
1.61      daniel    923:            dir->mail = debugStrdup(rpm2html_mail);
1.15      veillard  924:        if ((dir->ftp == NULL) && (rpm2html_ftp != NULL))
1.61      daniel    925:            dir->ftp = debugStrdup(rpm2html_ftp);
1.15      veillard  926:        if ((dir->ftpsrc == NULL) && (rpm2html_ftpsrc != NULL))
1.61      daniel    927:            dir->ftpsrc = debugStrdup(rpm2html_ftpsrc);
1.15      veillard  928:        if ((dir->dir == NULL) && (rpm2html_dir != NULL))
1.61      daniel    929:            dir->dir = debugStrdup(rpm2html_dir);
1.15      veillard  930:        if ((dir->host == NULL) && (rpm2html_host != NULL))
1.61      daniel    931:            dir->host = debugStrdup(rpm2html_host);
1.15      veillard  932:        if ((dir->name == NULL) && (rpm2html_name != NULL))
1.61      daniel    933:            dir->name = debugStrdup(rpm2html_name);
1.15      veillard  934:        if ((dir->url == NULL) && (rpm2html_url != NULL))
1.61      daniel    935:            dir->url = debugStrdup(rpm2html_url);
1.14      veillard  936: 
                    937:         if (dir->rpmdir == NULL) {
1.6       veillard  938:            fprintf(stderr, "?!? rpmDir without directory ?!? disabled !\n");
1.14      veillard  939:        } else if (!strcmp(dir->rpmdir, "localbase")) {
1.11      veillard  940:            /* Scan the local RPM database instead of a directory */
1.32      veillard  941:             cur = rpmBaseScan(dir);
1.7       veillard  942:        } else if (dir->ftp == NULL) {
                    943:            fprintf(stderr, "Directory %s disabled : no ftp field\n",
1.14      veillard  944:                    dir->rpmdir);
1.6       veillard  945:        } else {
1.51      veillard  946:            if (rpm2htmlVerbose)
1.16      veillard  947:                fprintf(stderr, "Scanning directory %s for RPMs\n",dir->rpmdir);
1.35      veillard  948:            cur = rpmDirScan(dir, dirTree);
1.6       veillard  949:        }
                    950: 
1.35      veillard  951:        if (cur != NULL) {
1.46      veillard  952:            if (nbLists >= maxLists) {
                    953:                maxLists *= 2;
1.61      daniel    954:                rpmLists = (rpmDataPtr *) debugRealloc(rpmLists,
1.46      veillard  955:                                             maxLists * sizeof(rpmDataPtr));
                    956:                if (rpmLists == NULL) {
                    957:                    fprintf(stderr, "rpmDirScanAll : running out of memory!\n");
                    958:                    exit(1);
1.35      veillard  959:                }
                    960:            }
1.46      veillard  961:            rpmLists[nbLists] = cur;
                    962:            nbLists++;
1.39      veillard  963:        }
                    964:        if (dir->root != NULL) {
1.48      veillard  965:            /************************************************
1.39      veillard  966:            if (rpm2html_build_tree)
                    967:                treeRoot = rpmMergeRealRoots(treeRoot, dir->root);
                    968:             else
1.48      veillard  969:             ************************************************/
                    970:            rpmDestroyRealRoot(dir->root);
                    971:            dir->root = NULL;
1.35      veillard  972:        }
1.32      veillard  973: 
1.6       veillard  974:         dir = dir->next;
                    975:     }
1.35      veillard  976:     for (i = 0;i < nbLists;i++)
                    977:        ret = rpmAddList(ret, rpmLists[i]);
1.61      daniel    978:     debugFree(rpmLists);
1.32      veillard  979:     return(ret);
1.60      daniel    980: }
                    981: 
                    982: /*
                    983:  * Cleanup the global variables from this module
                    984:  */
                    985: void rpmopenCleanup(void) {
                    986:     if (buffer != NULL)
1.61      daniel    987:         debugFree(buffer);
1.60      daniel    988:     buffer = NULL;
                    989:     buffer_size = 50 * 1024 * sizeof(char);
1.1       veillard  990: }
                    991: 

Webmaster