File:  [Public] / rpm2html / rpmopen.c
Revision 1.79: download - view: text, annotated - select for diffs
Fri Sep 8 10:54:03 2000 UTC (23 years, 8 months ago) by veillard
Branches: MAIN
CVS tags: HEAD
getting distrib id on Package records, Daniel

/*
 * rpmopen.c : open an extract informations from RPM files.
 *
 * See Copyright for the status of this software.
 *
 * $Id: rpmopen.c,v 1.79 2000/09/08 10:54:03 veillard Exp $
 */

#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <dirent.h>
#include <errno.h>
#include <time.h>

#include <rpm/rpmlib.h>
#include <rpm/rpmmacro.h> /* Added by A. Gibert */

#include "rpm2html.h"
#include "rpmdata.h"
#include "html.h"
#include "rdf.h"
#include "language.h"
#ifdef WITH_SQL
#include "sql.h"
#endif

#ifndef HAVE_SNPRINTF
#error You really need snprintf ...
#endif
/*
 * Get the internal number associated with an RPM tag.
 */
static int getTagNumber(char *tag) {
    int i;
    const struct headerTagTableEntry * t;

    for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
	if (!strcasecmp(tag, t->name)) return(t->val);
    }
    fprintf(stderr, "getTagNumber(%s) : unknown tag !\n", tag);
    return(-1);
}

/*
 * Free up the extra data not needed for the last stage processing.
 */

void rpmFreeExtraData(rpmDataPtr rpm) {
    rpmExtraDataPtr extra;

    if ((rpm == NULL) || (rpm->extra == NULL)) return;
    extra = rpm->extra;
    if (extra->packager != NULL) debugFree(extra->packager);
    if (extra->description != NULL) debugFree(extra->description);
    if (extra->copyright != NULL) debugFree(extra->copyright);
    if (extra->changelog != NULL) debugFree(extra->changelog);
    if (extra->srcrpm != NULL) debugFree(extra->srcrpm);
    if (extra->host != NULL) debugFree(extra->host);
    if (extra->resources != NULL) debugFree(extra->resources);
    if (extra->requires != NULL) debugFree(extra->requires);
    if (extra->filelist != NULL) debugFree(extra->filelist);
    debugFree(extra);
}

/*
 * check a dependancy name to get rid of bad deps due to bad scripts
 * or spec files.
 */
int checkResourceName(const char *res) {
    int isname = 0;
    const char *base = res;

    if (*res == 0) return(0);

    /*
     * we only accept absolute pathnames.
     */
    if (*res == '/') isname = 1;
    while (*res != 0) {
        if (((*res >= 'A') && (*res <= 'Z')) ||
	    ((*res >= 'a') && (*res <= 'z')) ||
            ((*res >= '0') && (*res <= '9')) ||
	    (*res == '-') || (*res == '.') ||
	    (*res == '@') || (*res == '_') ||
	    (*res == '+') ||
	    ((*res == '/') && (isname == 1)))
	    res++;
	else
	    return(0);
	if ((res - base) > 100) return(0);
    }
    return(1);
}

/*
 * check a release name
 */
int checkReleaseName(const char *res) {
    const char *base = res;

    if (*res == 0) return(0);

    while (*res != 0) {
        if (((*res >= 'A') && (*res <= 'Z')) ||
	    ((*res >= 'a') && (*res <= 'z')) ||
            ((*res >= '0') && (*res <= '9')) ||
	    (*res == '-') || (*res == '.') ||
	    (*res == '@') || (*res == '_') ||
	    (*res == '+'))
	    res++;
	else
	    return(0);
	if ((res - base) > 20) return(0);
    }
    return(1);
}

/*
 * check a group name
 */
int checkGroupName(const char *res) {
    const char *base = res;

    /* Grrr !!! Suse packages have an empty Group name
    if (*res == 0) return(0);
     */

    while (*res != 0) {
        if (((*res >= 'A') && (*res <= 'Z')) ||
	    ((*res >= 'a') && (*res <= 'z')) ||
            ((*res >= '0') && (*res <= '9')) ||
	    (*res == ' ') || (*res == '.') ||
	    (*res == '+') || (*res == '/') ||
	    (*res == '-'))
	    res++;
	else
	    return(0);
	if ((res - base) > 60) return(0);
    }
    return(1);
}

/*
 * check a version name
 */
int checkVersionName(const char *res) {
    const char *base = res;

    if (*res == 0) return(0);

    while (*res != 0) {
        if (((*res >= 'A') && (*res <= 'Z')) ||
	    ((*res >= 'a') && (*res <= 'z')) ||
            ((*res >= '0') && (*res <= '9')) ||
	    (*res == '-') || (*res == '.') ||
	    (*res == '@') || (*res == '_') ||
	    (*res == '+'))
	    res++;
	else
	    return(0);
	if ((res - base) > 20) return(0);
    }
    return(1);
}

/*
 * rpmAnalyze : analyze an RPM record, read and parse the header and 
 *              fill the informations in the database.
 */
#define ENTRY_CLEANUP(p)						\
    if ((type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE)&&\
        (p != NULL)) { free((p)); p = NULL; }

static char *buffer = NULL;
static int buffer_size = 50 * 1024 * sizeof(char);

rpmDataPtr rpmAnalyze(char *path, char *nameRpm, Header h, rpmDirPtr dir,
                      rpmSubdirPtr tree, time_t stamp, int isSource) {
    int installed = dir->installbase;
    char * name = NULL, * version = NULL, * release = NULL;
    int_32 count, type;
    void * p = NULL;
    int val, i, j;
    rpmDataPtr rpm = NULL;
    static char nameBuffer[500];
#ifdef WITH_SQL
    int id;
#endif

    if (buffer == NULL) {
        buffer = (char *) debugMalloc(buffer_size);
	if (buffer == NULL) {
	    fprintf(stderr, "cannot allocate %d bytes: %s\n", buffer_size,
		    strerror(errno));
	    exit(1);
	}
    }

    /* extract informations from the header */
    headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
    if (name == NULL) {
        fprintf(stderr, "Invalid package %s : no name\n", nameRpm);
	return(NULL);
    }
    if (!(((name[0] >= 'a') && (name[0] <= 'z')) ||
          ((name[0] >= 'A') && (name[0] <= 'Z')) ||
	  ((name[0] >= '0') && (name[0] <= '9')))) {
        fprintf(stderr, "Invalid package %s : garbled name\n", nameRpm);
	ENTRY_CLEANUP(name)
	return(NULL);
    }	  
    if (!checkResourceName(name)) {
        fprintf(stderr, "Invalid package %s : garbled name\n", nameRpm);
	ENTRY_CLEANUP(name)
	return(NULL);
    }
    headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
    if ((version == NULL) || (version[0] == 0)) {
        fprintf(stderr, "Invalid package %s : version invalid\n", nameRpm);
	ENTRY_CLEANUP(name)
	ENTRY_CLEANUP(version)
	return(NULL);
    }
    if (!checkVersionName(version)) {
        fprintf(stderr, "Invalid package %s : garbled version\n", nameRpm);
	ENTRY_CLEANUP(name)
	ENTRY_CLEANUP(version)
	return(NULL);
    }
    headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
    if ((release == NULL) || (release[0] == 0)) {
        fprintf(stderr, "Invalid package %s : release invalid\n", nameRpm);
	ENTRY_CLEANUP(name)
	ENTRY_CLEANUP(version)
	ENTRY_CLEANUP(release)
	return(NULL);
    }
    if (!checkReleaseName(release)) {
        fprintf(stderr, "Invalid package %s : garbled release\n", nameRpm);
	ENTRY_CLEANUP(name)
	ENTRY_CLEANUP(version)
	ENTRY_CLEANUP(release)
	return(NULL);
    }
        
    /* allocate a new rpmData block, and an rpmExtraData block fill them */
    rpm = (rpmDataPtr) debugMalloc(sizeof(rpmData));
    if (rpm == NULL) {
        fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmData),
	        strerror(errno));
        return(NULL);
    }
    memset(rpm, 0, sizeof(rpmData));
    rpm->extra = (rpmExtraDataPtr) debugMalloc(sizeof(rpmExtraData));
    if (rpm == NULL) {
        fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmExtraData),
	        strerror(errno));
        return(NULL);
    }
    memset(rpm->extra, 0, sizeof(rpmExtraData));
    rpm->dir = dir;
    if (tree) {
        if ((tree->rpmpath != NULL) && (tree->rpmpath[0] != '\0'))
	    rpm->subdir = stringAdd(tree->rpmpath);
	else
	    rpm->subdir = NULL;
    } else
	rpm->subdir = NULL;
    rpm->extra->stamp = stamp;
    rpm->name = stringAdd(name);
    ENTRY_CLEANUP(name)
    rpm->version = stringAdd(version);
    ENTRY_CLEANUP(version)
    rpm->release = stringAdd(release);
    ENTRY_CLEANUP(release)

    /* get all the resources provided by this RPM */
    if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, &p, &count) || !p) {
        rpm->summary = debugStrdup(localizedStrings[LANG_NO_SUMMARY]);
    } else {
	rpm->summary = debugStrdup((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->extra->description = debugStrdup(localizedStrings[LANG_NO_DESCRIPTION]);
    } else {
	rpm->extra->description = debugStrdup((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_DISTRIBUTION, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->distribution = stringAdd(localizedStrings[LANG_UNKNOWN]);
    } else {
	rpm->distribution = stringAdd((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (isSource) {
        rpm->arch = stringAdd("src");
	if (nameRpm == NULL) {
	    snprintf(nameBuffer, sizeof(nameBuffer), "%s-%s-%s.src.rpm",
		    name, version, release);
	    nameRpm = nameBuffer;
	}
    } else {
	if (!headerGetEntry(h, RPMTAG_ARCH, &type, &p, &count) || !p ||
	    (type != RPM_STRING_TYPE)) {
	    if (type == RPM_INT8_TYPE) {
		/*
		 * Old packages.
		 */
		switch (*((char *) p)) {
		    case 1:
			rpm->arch = stringAdd("i386");
			break;
		    default:
			rpm->arch = stringAdd("src");
			break;
		}
	    } else
		rpm->arch = stringAdd(localizedStrings[LANG_NONE]);
	    if (nameRpm == NULL) {
		snprintf(nameBuffer, sizeof(nameBuffer), "%s-%s-%s.rpm", name, version, release);
		nameRpm = nameBuffer;
	    }
	} else {
	    rpm->arch = stringAdd((char *) p);
	    if (nameRpm == NULL) {
		snprintf(nameBuffer, sizeof(nameBuffer), "%s-%s-%s.%s.rpm",
			name, version, release, (char *)p);
		nameRpm = nameBuffer;
	    }
	}
	ENTRY_CLEANUP(p);
    }
    if (!headerGetEntry(h, RPMTAG_OS, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
	if (type == RPM_INT8_TYPE) {
	    /*
	     * Old packages.
	     */
	    switch (*((char *) p)) {
	        case 1:
		    rpm->os = stringAdd("linux");
		    break;
	        default:
		    rpm->os = stringAdd("linux");
		    break;
	    }
	} else
	    rpm->os = stringAdd("");
    } else {
	rpm->os = stringAdd((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_VENDOR, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->vendor = NULL;
    } else {
	rpm->vendor = stringAdd((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_GROUP, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->group = stringAdd(localizedStrings[LANG_NO_GROUP]);
    } else {
	rpm->group = stringAdd((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!checkGroupName(rpm->group)) {
        fprintf(stderr, "Invalid package %s : garbled group\n", nameRpm);
	if (rpm->name)
	    stringFree(rpm->name);
	if (rpm->version)
	    stringFree(rpm->version);
	if (rpm->release)
	    stringFree(rpm->release);
	if (rpm->summary)
	    debugFree(rpm->summary);
	if (rpm->distribution)
	    stringFree(rpm->distribution);
	if (rpm->arch)
	    stringFree(rpm->arch);
	if (rpm->os)
	    stringFree(rpm->os);
	if (rpm->vendor != NULL)
	    stringFree(rpm->vendor);
	if (rpm->group != NULL)
	    stringFree(rpm->group);
	debugFree(rpm);
	return(NULL);
    }
    if (!headerGetEntry(h, RPMTAG_BUILDHOST, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->extra->host = debugStrdup(localizedStrings[LANG_NO_HOST]);
    } else {
	rpm->extra->host = debugStrdup((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_SIZE, &type, &p, &count) || !p) {
        rpm->size = 0;
    } else {
	rpm->size = *((int *) p);
    }
    ENTRY_CLEANUP(p);
    if (installed) {
	if (!headerGetEntry(h, RPMTAG_INSTALLTIME, &type, &p, &count) || !p) {
	    rpm->date = 0;
	} else {
	    rpm->date = *((int_32 *) p);
	}
	ENTRY_CLEANUP(p);
    } else {
	if (!headerGetEntry(h, RPMTAG_BUILDTIME, &type, &p, &count) || !p) {
	    rpm->date = 0;
	} else {
	    rpm->date = *((int_32 *) p);
	}
	ENTRY_CLEANUP(p);
    }
    if (!headerGetEntry(h, RPMTAG_SOURCERPM, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->extra->srcrpm = debugStrdup("");
    } else {
	rpm->extra->srcrpm = debugStrdup((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_URL, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->url = NULL;
    } else {
	rpm->url = debugStrdup((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_PACKAGER, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->extra->packager = NULL;
    } else {
	rpm->extra->packager = debugStrdup((char *) p);
    }
    ENTRY_CLEANUP(p);
    if (!headerGetEntry(h, RPMTAG_COPYRIGHT, &type, &p, &count) || !p ||
        (type != RPM_STRING_TYPE)) {
        rpm->extra->copyright = NULL;
    } else {
	rpm->extra->copyright = debugStrdup((char *) p);
    }
    ENTRY_CLEANUP(p);
    /* Pick up changelog entries */
    if (!headerGetEntry(h, RPMTAG_CHANGELOGTEXT, &type, &p, &count) || !p) {
        rpm->extra->changelog = NULL;
    } else {
      time_t *dates;
      char **names;
      char **holdp = (char **)p;
      char *cp;
      struct tm *tm_buf;
      int i, len, pos;
      char date_string[50];
      char *res = buffer;

      *res = '\0';
      headerGetEntry(h, RPMTAG_CHANGELOGTIME, &type, (void *)&dates, &count);
      headerGetEntry(h, RPMTAG_CHANGELOGNAME, &type, (void *)&names, &count);
      for (i = 0;  i < count;  i++) {
        if ((res - buffer) > (buffer_size - 1024)) {
	    int delta = res - buffer;

	    buffer_size *= 2;
	    buffer = (char *) debugRealloc(buffer, buffer_size);
	    if (buffer == NULL) {
		fprintf(stderr, "cannot re-allocate %d bytes: %s\n",
		        buffer_size, strerror(errno));
		exit(1);
	    }
	    res = &buffer[delta];
	}
	tm_buf = localtime(&dates[i]);
        strftime(date_string, sizeof(date_string) - 1, "%a %b %d %Y", tm_buf);
	len = snprintf(res, buffer_size, "* %s %s\n", date_string, names[i]);
	res += len;
	cp = holdp[i];
	pos = 0;
	while (*cp) {
	  if (pos++ == 0) {
	    *res++ = ' ';
	    *res++ = ' ';	    
	  }
	  *res++ = *cp;
	  if (*cp++ == '\n') pos = 0;
	}
	*res++ = '\n';
      }
      *res = '\0';
      rpm->extra->changelog = debugStrdup(buffer);
    }
    ENTRY_CLEANUP(p);
    if (rpm->vendor == NULL) {
        if (rpm->extra->packager != NULL) rpm->vendor = debugStrdup(rpm->extra->packager);
	else rpm->vendor = debugStrdup(localizedStrings[LANG_UNKNOWN]);
    }

    rpm->filename = debugStrdup(nameRpm);

    /* package-xxx.rpm provides at least the resource "package" */
    val = getTagNumber("RPMTAG_PROVIDES");
    if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
        rpm->extra->nb_resources = 1;
        rpm->extra->max_resources = 1;
	rpm->extra->resources = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) *
	                                      rpm->extra->max_resources);
	if (rpm->extra->resources == NULL) {
	    fprintf(stderr, ": ran out of memory\n");
	    exit(1);
	}
	rpm->extra->resources[0] = rpmRessAdd(name, rpm, installed);
    } else {
        rpm->extra->max_resources = count + 1;
	rpm->extra->resources = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) *
	                                      rpm->extra->max_resources);
	if (rpm->extra->resources == NULL) {
	    fprintf(stderr, ": ran out of memory\n");
	    exit(1);
	}
	rpm->extra->resources[0] = rpmRessAdd(name, rpm, installed);
        rpm->extra->nb_resources = 1;

        for (i = 0, j = rpm->extra->nb_resources; i < count;i++) {
	    if (!checkResourceName(((char **) p)[i])) continue;
	    rpm->extra->resources[j++] = rpmRessAdd(((char **) p)[i], rpm, installed);
	}
	rpm->extra->nb_resources = j;
    }
    ENTRY_CLEANUP(p);

    val = getTagNumber("RPMTAG_REQUIRENAME");
    if (!headerGetEntry(h, val, &type, &p, &count) || !p) {
	rpm->extra->nb_requires = 0;
	rpm->extra->requires = NULL;
    } else {
	int_32 count2, count3, type2, type3;
	void * q = NULL;
	void * r = NULL;
	int valv, valf;

	rpm->extra->max_requires = count;
	rpm->extra->requires = (rpmRessPtr *) debugMalloc(sizeof(rpmRessPtr) *
	                                           rpm->extra->max_requires);
	if (rpm->extra->requires == NULL) {
	    fprintf(stderr, ": ran out of memory\n");
	    exit(1);
  	}
	valv = getTagNumber("RPMTAG_REQUIREVERSION");
	valf = getTagNumber("RPMTAG_REQUIREFLAGS");
	headerGetEntry(h, valv, &type2, &q, &count2);
	headerGetEntry(h, valf, &type3, &r, &count3);

	rpm->extra->nb_requires = 0;

        for (i = 0, j = 0; (i < count2) && (i < count3);i++) {
	    long anint = *(((long *)r)+i);
	    rpm_dep_flag flag = RPM2HTML_REQ_NONE;
     
	    if ((anint & RPMSENSE_LESS) && (anint & RPMSENSE_EQUAL))
		flag = RPM2HTML_REQ_LEQ;
	    else if (anint & RPMSENSE_LESS)
		flag = RPM2HTML_REQ_LT;
	    if ((anint & RPMSENSE_GREATER) && (anint & RPMSENSE_EQUAL))
		flag = RPM2HTML_REQ_GEQ;
	    else if (anint & RPMSENSE_GREATER)
		flag = RPM2HTML_REQ_GT;
	    else if (anint & RPMSENSE_EQUAL)
	        flag = RPM2HTML_REQ_EQU;
	    if (!checkResourceName(((char **) p)[i])) continue;
 	    rpm->extra->requires[j++] = 
		rpmRequAdd(((char **) p)[i],((char **) q)[i],
			   flag , rpm, installed);
	}
	rpm->extra->nb_requires = j;
	if ((type2 == RPM_STRING_ARRAY_TYPE || type2 == RPM_I18NSTRING_TYPE)&&
	    (q != NULL)) { free((q)); q = NULL; }
	if ((type3 == RPM_STRING_ARRAY_TYPE || type3 == RPM_I18NSTRING_TYPE)&&
	    (r != NULL)) { free((r)); r = NULL; }
	for (;i < count;i++)
	    rpmRequAdd(((char **) p)[i], NULL, RPM2HTML_REQ_NONE,
		       rpm, installed);
    }
    ENTRY_CLEANUP(p);

#if defined(RPMTAG_FILENAMES)
    val = getTagNumber("RPMTAG_FILENAMES");
    headerGetEntry(h, val, &type, &p, &count);
#else
    rpmBuildFileList(h, (const char ***) &p, &count);
#endif

    if (count == 0) {
        rpm->extra->filelist = NULL; /* No filelist in the package ! */
    } else {
        char *ptr = buffer;

	for (i = 0; i < count;i++) {
	    if ((ptr - buffer) > (buffer_size - 1024)) {
		int delta = ptr - buffer;

		buffer_size *= 2;
		buffer = (char *) debugRealloc(buffer, buffer_size);
		if (buffer == NULL) {
		    fprintf(stderr, "cannot re-allocate %d bytes: %s\n",
		            buffer_size, strerror(errno));
		    exit(1);
		}
		ptr = &buffer[delta];
	    }
	    ptr += snprintf(ptr, buffer_size, "%s\n", ((char **) p)[i]);
	}
	rpm->extra->filelist = debugStrdup(buffer);
    }
    ENTRY_CLEANUP(p);

#ifdef WITH_SQL
    id = sql_add_package(path, rpm->name, rpm->version, rpm->release,
			 rpm->arch, dir->no, rpm->url, rpm->extra->srcrpm,
			 dir->vendor, rpm->extra->packager,
			 rpm->group, rpm->summary, rpm->extra->description,
			 rpm->extra->copyright);
    if (id > 0) {
	for (i = 0;i < rpm->extra->nb_resources;i++)
	    sql_add_provides(id, rpm->extra->resources[i]->name);
	for (i = 0;i < rpm->extra->nb_requires;i++)
	    sql_add_requires(id, rpm->extra->requires[i]->name,
			     rpm->extra->requires[i]->flag,
			     rpm->extra->requires[i]->version);
    }
#endif

    /* Add the package files to the real filesystem tree if asked for */
#ifdef WITH_SQL
    if ((rpm->extra->filelist != NULL) &&
	((dir->build_tree != 0) || (id > 0))) {
#else
    if ((dir->build_tree != 0) && (rpm->extra->filelist != NULL)) {
#endif
        char *cur, *filename;
	
	cur = rpm->extra->filelist;
	while ((*cur != '\0') && (*cur != '/')) cur++;
	filename = cur;
	while (*cur != '\0') {
	    if ((*cur == '\n') || (*cur == '\r')) {
	        if (cur != filename) {
#ifdef WITH_SQL
		    if (dir->build_tree != 0)
			rpmAddRealFile(dir->root, filename, rpm);
		    if (id > 0) {
			*cur = 0;
			sql_add_file(filename,id);
			*cur = '\n';
		    }
#else
		    rpmAddRealFile(dir->root, filename, rpm);
#endif
		}
		while ((*cur != '\0') && (*cur != '/')) cur++;
                filename = cur;
	    } else
	        cur++;
	}
	if (cur != filename)
	    rpmAddRealFile(dir->root, filename, rpm);
    }

    /* Register this package */
    rpmAddSoftware(rpm);

    /* dump the HTML related to this package */
    if ((rpm2html_dump_html) && (dir->html))
	dumpRpmHtml(rpm, tree);
    if (rpm2html_dump_rdf)
	dumpRpmRdf(rpm, tree);

    /* free the extra data */
    rpmFreeExtraData(rpm);

    /* increment the counters */
    if (installed) {
	rpm2html_install_files++;
	rpm2html_install_size += rpm->size / 1024;
    } else {
	rpm2html_files++;
	rpm2html_size += rpm->size / 1024;
    }

    return(rpm);
}

/*
 * rpmOpen : open an RPM file, read and parse the header and 
 *           fill the informations in the database.
 */
rpmDataPtr rpmOpen(char *nameRpm, rpmDirPtr dir, rpmSubdirPtr tree) {
    rpmDataPtr cur;
#if defined(HAVE_RPM_RPMIO_H)
    FD_t fd;
#else
    int fd;
#define	fdOpen(_a, _b, _c)	open((_a), (_b))
#define	fdClose(_a)		close(_a)
#endif
    int rc;
    Header h = NULL;
    int isSource;
    char buffer[500];
    struct stat buf;

    /* open the file for reading */
    if (tree->htmlpath[0] != '\0')
	snprintf(buffer, sizeof(buffer), "%s/%s/%s", dir->rpmdir, tree->rpmpath, nameRpm);
    else
	snprintf(buffer, sizeof(buffer), "%s/%s", dir->rpmdir, nameRpm);

    if (access(buffer, R_OK) < 0) {
         fprintf(stderr, "open of %s failed: %s\n", buffer,
	         strerror(errno));
	 return(NULL);
    }
#if defined(USE_RPMIO)
    fd = Fopen(buffer, "r.fdio");
    if (fd == NULL || Ferror(fd)) {
         fprintf(stderr, "Fopen of %s failed: %s\n", buffer,
	         Fstrerror(fd));
	 return(NULL);
    }
#else
    if ((fd = fdOpen(buffer, O_RDONLY, 0)) < 0) {
         fprintf(stderr, "open of %s failed: %s\n", buffer,
	         strerror(errno));
	 return(NULL);
    }
#endif

    stat(buffer, &buf);

    /* read the RPM header */
    rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
    switch (rc) {
	case 0:
	    if (!h) {
		fprintf(stderr,
			"old format source packages cannot be queried\n");
		fdClose(fd);
		return(NULL);
	    }
	    break;
	case 1:
	    fprintf(stderr, "%s does not appear to be a RPM package\n",
		    nameRpm);
	    fdClose(fd);
	    return(NULL);
	case 2:
	    fprintf(stderr, "query of %s failed\n", nameRpm);
	    fdClose(fd);
	    return(NULL);
	default:
	    fprintf(stderr, "rpmReadPackageHeader(%s): unknown error %d\n",
		    nameRpm, rc);
	    fdClose(fd);
	    return(NULL);
    }

    cur = rpmAnalyze(buffer, nameRpm, h, dir, tree, buf.st_mtime, isSource);

    /* free the header and close the descriptor */
    headerFree(h);
#if defined(USE_RPMIO)
    Fclose(fd);
#else
    fdClose(fd);
#endif

    return(cur);
}

/*
 * Scan one directory for RPM files this is where the recursive handling
 * is done.
 */
static rpmDataPtr rpmOneDirScan(rpmDirPtr dir, rpmSubdirPtr tree) {
    rpmSubdirPtr subtree;
    rpmDataPtr ret = NULL, cur;
    char *filename;
    static char path[2000];
    struct stat buf;
    int len;
    DIR *d;
    struct dirent *file;


    /*
     * Create the directory for the HTML pages
     */
    if ((rpm2html_dump_html) && (dir->html)) {
	if (tree->htmlpath[0] != '\0')
	    snprintf(path, sizeof(path), "%s/%s", dir->dir, tree->htmlpath);
	else
	    snprintf(path, sizeof(path), "%s", dir->dir);
	createDirectory(path);
    }

    /*
     * Create the directory for the RDF pages
    if (rpm2html_rdf_dir != NULL) {
	if (tree->htmlpath[0] != '\0')
	    snprintf(path, sizeof(path), "%s/%s", rpm2html_rdf_dir, tree->htmlpath);
	else
	    snprintf(path, sizeof(path), "%s", rpm2html_rdf_dir);
        createDirectory(path);
    }
     */

    /*
     * Scan the repository.
     */
    if (tree->rpmpath[0] != '\0')
	snprintf(path, sizeof(path), "%s/%s", dir->rpmdir, tree->rpmpath);
    else
	snprintf(path, sizeof(path), "%s", dir->rpmdir);
    if (rpm2htmlVerbose > 1)
        printf("Scanning directory %s\n", path);

    d = opendir(path);
    if (d == NULL) {
        fprintf(stderr, "Listing of %s failed: %s\n", path,
	        strerror(errno));
        rpmRemoveSubdir(tree);
        rpmFreeSubdir(tree);
	return(NULL);
    } else {
        while ((file = readdir(d)) != NULL) {
	    cur = NULL;
	    filename = file->d_name;
	    len = strlen(filename);

	    /*
	     * Compute the full path
	     */
	    if (tree->rpmpath[0] != '\0')
		snprintf(path, sizeof(path), "%s/%s/%s", dir->rpmdir, tree->rpmpath,
		        filename);
	    else
		snprintf(path, sizeof(path), "%s/%s", dir->rpmdir, filename);

	    /*
	     * Stat() the file to detect directory and symlimks
	     */
	    if (lstat(path, &buf) != 0) {
	        fprintf(stderr, "Couldn't stat(%s)\n", path);
		continue;
	    }

	    /*
	     * Check for RPM files by looking at the suffix
	     * Note that SuSE source RPMs have a ".spm" suffix
	     * We may or may not follow symlinks to RPM files
	     */
	    if (((len >= 5) &&
	               (!strcasecmp(&filename[len - 4], ".rpm"))) ||
		     ((len >= 5) &&
		       (!strcasecmp(&filename[len - 4], ".spm")))) {
 
		if ((S_ISLNK(buf.st_mode)) && (dir->rpm_symlinks == 0)) {
		    if (rpm2htmlVerbose > 1)
			fprintf(stderr, "Dropping symlink %s\n", path);
		    continue;
		}
	        cur = rpmOpen(filename, dir, tree);
	    }

	    /*
	     * Don't follow of analyze symlinks,
	     */
            else if ((S_ISLNK(buf.st_mode)) && (dir->follow_symlinks == 0)) {
		if (rpm2htmlVerbose > 1)
		    fprintf(stderr, "Dropping symlink %s\n", path);
	        continue;
	    }

	    /*
	     * Check for RDF files by looking at the suffix
	     */
	    else if ((len >= 5) && (!strcasecmp(&filename[len - 4], ".rdf"))) {
	        cur = rpmOpenRdf(filename, dir, tree);
	    }

	    /*
	     * Else if this is a directory, recurse !
	     */
	    else if (S_ISDIR(buf.st_mode)) {
		if (filename[0] != '.') {
		    subtree = rpmNewSubdir(tree, filename, NULL, NULL, NULL, 0);
		    cur = rpmOneDirScan(dir, subtree);
		}
	    }
	    if (cur != NULL) ret = rpmAddList(ret, cur);
	}
    }
    closedir(d);

    /*
     * Dump the pages related to this directory.
     */
    if (ret != NULL) ret = dumpDirIndex(dir, tree, ret);
    else {
        rpmRemoveSubdir(tree);
	rpmFreeSubdir(tree);
    }

    return(ret);
}

/*
 * Scan a directory for RPM files.
 */
static rpmDataPtr rpmDirScan(rpmDirPtr dir, rpmSubdirPtr tree) {
    rpmSubdirPtr cur;
    rpmDataPtr ret;
    
    if ((rpm2html_dump_html) && (dir->html) && (dir->build_tree != 0)) {
	dir->root = rpmCreateRealRoot();
    }
    cur = rpmNewSubdir(tree, dir->name,
              dir->subdir == NULL ? "" : dir->subdir, "", dir->color,
	      dir->html);
    ret = rpmOneDirScan(dir, cur);
    rpmDumpHtmlRealRoot(dir);
    return(ret);
}

/*
 * Scan the local RPM database for RPM files.
 */
static rpmDataPtr rpmBaseScan(rpmDirPtr dir) {
    static char path[2000];
    rpmDataPtr ret = NULL, cur;
    rpmdb db;
    Header h = NULL;
#ifndef	USE_RPMIO
    int offset;
#endif
    char *prefix = "/";

    /*
     * Create the directory for the HTML pages
     */
    if ((rpm2html_dump_html) && (dir->html)) {
	if (dir->subdir)
	    snprintf(path, sizeof(path), "%s/%s", dir->dir, dir->subdir);
	else
	    snprintf(path, sizeof(path), "%s", dir->dir);
	createDirectory(path);
    }

    /*
     * Create the directory for the RDF pages
     */
    if (rpm2html_rdf_dir != NULL) {
	if (dir->subdir)
	    snprintf(path, sizeof(path), "%s/%s", rpm2html_rdf_dir, dir->subdir);
	else
	    snprintf(path, sizeof(path), "%s", rpm2html_rdf_dir);
        createDirectory(path);
    }

    if (rpm2htmlVerbose)
        printf("Scanning the database of installed RPMs\n");

    if (dir->dbpath != NULL)
	addMacro(NULL, "_dbpath", NULL, dir->dbpath, -7); /* Added by A.Gibert */

    if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
        return(NULL);
    }

#ifdef USE_RPMIO
    {	rpmdbMatchIterator mi;
	mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
	while ((h = rpmdbNextIterator(mi)) != NULL) {
	    cur = rpmAnalyze(NULL, NULL, h, dir, NULL, 0, 0);
	    if (cur != NULL) ret = rpmAddList(ret, cur);
	}
	rpmdbFreeIterator(mi);
    }
#else	/* USE_RPMIO */
    offset = rpmdbFirstRecNum(db);
    while (offset) {
        h = rpmdbGetRecord(db, offset);
	if (!h) {
	    fprintf(stderr, "could not read database record!\n");
	    return(ret);
	}
	cur = rpmAnalyze(NULL, NULL, h, dir, NULL, 0, 0);
	if (cur != NULL) ret = rpmAddList(ret, cur);
	headerFree(h);
	offset = rpmdbNextRecNum(db, offset);
    }
#endif	/* USE_RPMIO */

    rpmdbClose(db);

    return(ret);
}

/*
 * Scan all registered directories.
 * One fist check for completeness of the informations in
 * the rpmDir structure.
 */

rpmDataPtr rpmDirScanAll(void) {
    rpmDirPtr dir, next;
    rpmDataPtr ret = NULL, cur;
    int maxLists = 50;
    rpmDataPtr *rpmLists;
    int nbLists = 0;
    int i;

    /*
     * first reverse the list ....
     */
    dir = dirList;
    dirList = NULL;
    while (dir != NULL) {
        next = dir->next;
	dir->next = dirList;
	dirList = dir;
	dir = next;
    }
    dir = dirList;

    /*
     * Allocate a directory tree.
     */
    dirTree = rpmNewSubdir(NULL, "", "", "", NULL, 1);

    rpmLists = (rpmDataPtr *) debugMalloc(maxLists * sizeof(rpmDataPtr));
    if (rpmLists == NULL) {
        fprintf(stderr, "rpmDirScanAll : running out of memory !\n");
	exit(1);
    }

    while (dir != NULL) {
        cur  = NULL;

	/*
	 * Override default setting.
	 */
	if ((dir->maint == NULL) && (rpm2html_maint != NULL))
	    dir->maint = debugStrdup(rpm2html_maint);
	if ((dir->mail == NULL) && (rpm2html_mail != NULL))
	    dir->mail = debugStrdup(rpm2html_mail);
	if ((dir->ftp == NULL) && (rpm2html_ftp != NULL))
	    dir->ftp = debugStrdup(rpm2html_ftp);
	if ((dir->ftpsrc == NULL) && (rpm2html_ftpsrc != NULL))
	    dir->ftpsrc = debugStrdup(rpm2html_ftpsrc);
	if ((dir->dir == NULL) && (rpm2html_dir != NULL))
	    dir->dir = debugStrdup(rpm2html_dir);
	if ((dir->host == NULL) && (rpm2html_host != NULL))
	    dir->host = debugStrdup(rpm2html_host);
	if ((dir->name == NULL) && (rpm2html_name != NULL))
	    dir->name = debugStrdup(rpm2html_name);
	if ((dir->url == NULL) && (rpm2html_url != NULL))
	    dir->url = debugStrdup(rpm2html_url);

        if (dir->rpmdir == NULL) {
	    fprintf(stderr, "?!? rpmDir without directory ?!? disabled !\n");
	} else if (!strncmp(dir->rpmdir, "localbase", 9)) {   /* Added by A. Gibert */
	    /* Scan the local RPM database instead of a directory */
            cur = rpmBaseScan(dir);
	} else if (dir->ftp == NULL) {
	    fprintf(stderr, "Directory %s disabled : no ftp field\n",
	            dir->rpmdir);
	} else {
	    dir->no = sql_get_distrib_by_directory(dir->rpmdir);
	    if (rpm2htmlVerbose)
		printf("Scanning directory %s for RPMs\n",dir->rpmdir);
	    cur = rpmDirScan(dir, dirTree);
	}

	if (cur != NULL) {
	    if (nbLists >= maxLists) {
	        maxLists *= 2;
		rpmLists = (rpmDataPtr *) debugRealloc(rpmLists,
                                            maxLists * sizeof(rpmDataPtr));
		if (rpmLists == NULL) {
		    fprintf(stderr, "rpmDirScanAll : running out of memory!\n");
		    exit(1);
		}
	    }
	    rpmLists[nbLists] = cur;
	    nbLists++;
	}
	if (dir->root != NULL) {
	    /************************************************
	    if (rpm2html_build_tree)
	        treeRoot = rpmMergeRealRoots(treeRoot, dir->root);
            else
	     ************************************************/
	    rpmDestroyRealRoot(dir->root);
	    dir->root = NULL;
	}

        dir = dir->next;
    }
    for (i = 0;i < nbLists;i++)
	ret = rpmAddList(ret, rpmLists[i]);
    debugFree(rpmLists);
    return(ret);
}

/*
 * Cleanup the global variables from this module
 */
void rpmopenCleanup(void) {
    if (buffer != NULL)
        debugFree(buffer);
    buffer = NULL;
    buffer_size = 50 * 1024 * sizeof(char);
}


Webmaster