Annotation of rpm2html/rdf.c, revision 1.11
1.1 httpng 1: /*
2: * rdf.c : implementation for the RDF encoding/decoding of RPM informations.
3: */
4:
1.2 httpng 5: #include "config.h"
1.6 veillard 6: #include <sys/stat.h>
1.2 httpng 7: #ifdef HAVE_FCNTL_H
8: #include <fcntl.h>
9: #endif
10: #include <stdio.h>
11: #include <stdlib.h>
12: #include <string.h>
13: #ifdef HAVE_UNISTD_H
14: #include <unistd.h>
15: #endif
16: #include <time.h>
1.1 httpng 17: #include <errno.h>
1.2 httpng 18: #include <ctype.h>
1.1 httpng 19:
20: #include "rpm2html.h"
21: #include "rpmdata.h"
1.4 veillard 22: #include "html.h"
1.7 veillard 23: #include "language.h"
1.4 veillard 24:
25: #include "rdf_api.h"
1.1 httpng 26: #include "rdf.h"
27:
28: /*
29: * Open an RDF file call the parser to create a XML tree
30: * Then walk the tree and build an rpmData structure for
31: * the corresponding package.
32: */
1.5 veillard 33: rpmDataPtr rpmOpenRdf(char *nameRdf, rpmDirPtr dir, rpmSubdirPtr tree) {
34: char file[1000];
1.6 veillard 35: char nameBuffer[200];
1.5 veillard 36: rdfSchema rdf;
37: rdfNamespace rpmNs;
38: rdfNamespace rdfNs;
39: rdfDescription desc;
40: rdfBag bag;
1.7 veillard 41: rdfElement elem;
1.5 veillard 42: char *value;
43: rpmDataPtr rpm;
1.6 veillard 44: struct stat buf;
1.7 veillard 45: int i;
1.5 veillard 46:
47: /*
48: * open the file for reading
49: */
50: if (tree->htmlpath[0] != '\0')
51: sprintf(file, "%s/%s/%s", dir->rpmdir, tree->rpmpath, nameRdf);
52: else
53: sprintf(file, "%s/%s", dir->rpmdir, nameRdf);
54:
55: rdf = rdfRead(file);
56: if (rdf == NULL) return(NULL);
57:
58: /*
59: * Start the analyze, check that's an RDf for RPM packages.
60: */
61: rdfNs = rdfGetNamespace(rdf, "http://www.w3.org/TR/WD-rdf-syntax#");
62: if (rdfNs == NULL) {
63: fprintf(stderr, "%s is not an RDF schema\n", file);
64: rdfDestroySchema(rdf);
65: return(NULL);
66: }
67: rpmNs = rdfGetNamespace(rdf, "http://www.rpm.org/");
68: if (rdfNs == NULL) {
69: fprintf(stderr, "%s is not an RPM specific RDF schema\n", file);
70: rdfDestroySchema(rdf);
71: return(NULL);
72: }
73: desc = rdfFirstDescription(rdf);
74: if (rdfNs == NULL) {
75: fprintf(stderr, "%s RDF schema seems empty\n", file);
76: rdfDestroySchema(rdf);
77: return(NULL);
78: }
79:
80: /*
81: * We are pretty sure that it will be a valid schema,
1.6 veillard 82: * Allocate the rpmData structure, initialize it.
1.5 veillard 83: */
84: rpm = (rpmDataPtr) malloc(sizeof(rpmData));
85: if (rpm == NULL) {
86: fprintf(stderr, "rpmOpenRdf : out of memory !\n");
87: rdfDestroySchema(rdf);
88: return(NULL);
89: }
1.6 veillard 90: memset(rpm, 0, sizeof(rpmData));
91: rpm->dir = dir;
92: if (tree) {
93: if ((tree->rpmpath != NULL) && (tree->rpmpath[0] != '\0'))
94: rpm->subdir = strdup(tree->rpmpath);
95: else
96: rpm->subdir = NULL;
97: } else
98: rpm->subdir = NULL;
1.5 veillard 99:
1.6 veillard 100: stat(file, &buf);
101: rpm->stamp = buf.st_mtime;
102:
103: /*
104: * Now extract all the metadata informations from the RDF tree
105: */
1.5 veillard 106: rdfGetValue(desc, "Name", rpmNs, &value, NULL);
107: if (value != NULL) rpm->name = strdup(value);
108: else {
109: fprintf(stderr, "%s RDF schema invalid : no Name\n", file);
110: rdfDestroySchema(rdf);
111: return(NULL);
112: }
113: rdfGetValue(desc, "Version", rpmNs, &value, NULL);
114: if (value != NULL) rpm->version = strdup(value);
115: else {
116: fprintf(stderr, "%s RDF schema invalid : no Version\n", file);
117: rdfDestroySchema(rdf);
118: return(NULL);
119: }
120: rdfGetValue(desc, "Release", rpmNs, &value, NULL);
121: if (value != NULL) rpm->release = strdup(value);
122: else {
123: fprintf(stderr, "%s RDF schema invalid : no Release\n", file);
124: rdfDestroySchema(rdf);
125: return(NULL);
126: }
127: rdfGetValue(desc, "URL", rpmNs, &value, NULL);
128: if (value != NULL) rpm->url = strdup(value);
1.7 veillard 129: else rpm->url = NULL;
130:
1.5 veillard 131: rdfGetValue(desc, "Arch", rpmNs, &value, NULL);
132: if (value != NULL) rpm->arch = strdup(value);
1.7 veillard 133: else rpm->arch = strdup(localizedStrings[LANG_NONE]);
134:
1.5 veillard 135: rdfGetValue(desc, "Os", rpmNs, &value, NULL);
136: if (value != NULL) rpm->os = strdup(value);
1.7 veillard 137: else rpm->os = strdup("linux");
138:
1.5 veillard 139: rdfGetValue(desc, "Distribution", rpmNs, &value, NULL);
140: if (value != NULL) rpm->distribution = strdup(value);
1.7 veillard 141: else rpm->distribution = strdup(localizedStrings[LANG_UNKNOWN]);
142:
1.5 veillard 143: rdfGetValue(desc, "Vendor", rpmNs, &value, NULL);
144: if (value != NULL) rpm->vendor = strdup(value);
1.7 veillard 145: else rpm->vendor = strdup(localizedStrings[LANG_UNKNOWN]);
146:
1.5 veillard 147: rdfGetValue(desc, "Packager", rpmNs, &value, NULL);
148: if (value != NULL) rpm->packager = strdup(value);
1.7 veillard 149: else rpm->packager = NULL;
150:
1.5 veillard 151: rdfGetValue(desc, "Group", rpmNs, &value, NULL);
152: if (value != NULL) rpm->group = strdup(value);
1.7 veillard 153: else rpm->group = strdup(localizedStrings[LANG_NO_GROUP]);
154:
1.5 veillard 155: rdfGetValue(desc, "Summary", rpmNs, &value, NULL);
156: if (value != NULL) rpm->summary = strdup(value);
1.7 veillard 157: else rpm->summary = strdup(localizedStrings[LANG_NO_SUMMARY]);
158:
1.5 veillard 159: rdfGetValue(desc, "Description", rpmNs, &value, NULL);
160: if (value != NULL) rpm->description = strdup(value);
1.7 veillard 161: else rpm->description = strdup(localizedStrings[LANG_NO_DESCRIPTION]);
162:
1.5 veillard 163: rdfGetValue(desc, "Copyright", rpmNs, &value, NULL);
164: if (value != NULL) rpm->copyright = strdup(value);
1.7 veillard 165: else rpm->copyright = NULL;
166:
1.5 veillard 167: rdfGetValue(desc, "Changelog", rpmNs, &value, NULL);
168: if (value != NULL) rpm->changelog = strdup(value);
1.7 veillard 169: else rpm->changelog = NULL;
170:
171: rdfGetValue(desc, "Sources", rpmNs, &value, NULL);
172: if (value != NULL) {
173: rpm->srcrpm = strdup(value);
174: } else rpm->srcrpm = strdup("");
175:
176: rdfGetValue(desc, "Size", rpmNs, &value, NULL);
177: if (value != NULL) {
178: if (sscanf(value, "%d", &(rpm->size)) != 1)
179: rpm->size = 0;
180: } else rpm->size = 0;
181:
182: rdfGetValue(desc, "Date", rpmNs, &value, NULL);
183: if (value != NULL) {
1.8 veillard 184: if (sscanf(value, "%d", &i) != 1)
1.7 veillard 185: rpm->date = 0;
1.8 veillard 186: else
187: rpm->date = i;
1.7 veillard 188: } else rpm->date = 0;
189:
190: rdfGetValue(desc, "BuildHost", rpmNs, &value, NULL);
191: if (value != NULL) rpm->host = strdup(value);
192: else rpm->host = strdup(localizedStrings[LANG_NO_HOST]);
193:
194: rdfGetValue(desc, "Files", rpmNs, &value, NULL);
195: if (value != NULL) rpm->filelist = strdup(value);
196: else rpm->filelist = NULL;
197:
198: /*
199: * Fetching packages provided is a bit more tricky, one have to
200: * find the RDF Bag, and scan it's values.
201: */
202: rpm->nb_resources = 0;
203: rdfGetValue(desc, "Provides", rpmNs, NULL, &bag);
204: if (bag != NULL) {
205: elem = rdfFirstChild(bag);
1.11 ! veillard 206: rpm->max_resources = 5;
! 207: rpm->resources = (rpmRessPtr *) malloc(rpm->max_resources *
! 208: sizeof(rpmRessPtr));
! 209: if (rpm->resources == NULL) {
! 210: fprintf(stderr, "rpmOpenRdf : ran out of memory\n");
! 211: exit(1);
! 212: }
1.7 veillard 213: i = 0;
214: while (elem != NULL) {
1.11 ! veillard 215: if (i >= rpm->max_resources) {
! 216: rpm->max_resources *= 2;
! 217: rpm->resources = (rpmRessPtr *) realloc(rpm->resources,
! 218: rpm->max_resources * sizeof(rpmRessPtr));
! 219: if (rpm->resources == NULL) {
! 220: fprintf(stderr, "rpmOpenRdf : ran out of memory\n");
! 221: exit(1);
! 222: }
1.7 veillard 223: }
224: /*
225: * Check that we are scanning an RPM Resource.
226: */
227: if ((!strcmp(rdfElemGetPropertyName(elem), "Resource")) &&
228: (rdfElemGetNamespace(elem) == rpmNs)) {
229: value = rdfElemGetValue(elem);
230: if (value != NULL) {
231: rpm->resources[i] = rpmRessAdd(value, rpm, 0);
232: i++;
233: rpm->nb_resources++;
1.8 veillard 234: } else if (verbose > 1) {
1.7 veillard 235: fprintf(stderr, "%s : malformed Resource element !\n", file);
236: }
1.8 veillard 237: } else if (verbose > 1) {
1.7 veillard 238: fprintf(stderr, "%s : malformed Provides bag !\n", file);
239: }
240: elem = rdfNextElem(elem);
241: }
1.8 veillard 242: } else if (verbose > 1) {
1.7 veillard 243: fprintf(stderr, "%s doesn't export any resource\n", file);
244: }
245:
246: /*
247: * idem for the dependencies.
248: */
249: rpm->nb_requires = 0;
250: rdfGetValue(desc, "Requires", rpmNs, NULL, &bag);
251: if (bag != NULL) {
252: elem = rdfFirstChild(bag);
1.11 ! veillard 253: rpm->max_requires = 5;
! 254: rpm->requires = (rpmRessPtr *) malloc(rpm->max_requires *
! 255: sizeof(rpmRessPtr));
! 256: if (rpm->requires == NULL) {
! 257: fprintf(stderr, "rpmOpenRdf : ran out of memory\n");
! 258: exit(1);
! 259: }
1.7 veillard 260: i = 0;
261: while (elem != NULL) {
1.11 ! veillard 262: if (i >= rpm->max_requires) {
! 263: rpm->max_requires *= 2;
! 264: rpm->requires = (rpmRessPtr *) realloc(rpm->requires,
! 265: rpm->max_requires * sizeof(rpmRessPtr));
! 266: if (rpm->requires == NULL) {
! 267: fprintf(stderr, "rpmOpenRdf : ran out of memory\n");
! 268: exit(1);
! 269: }
1.7 veillard 270: }
271: /*
272: * Check that we are scanning an RPM Resource.
273: */
274: if ((!strcmp(rdfElemGetPropertyName(elem), "Resource")) &&
275: (rdfElemGetNamespace(elem) == rpmNs)) {
276: value = rdfElemGetValue(elem);
277: if (value != NULL) {
278: rpm->requires[i] = rpmRequAdd(value, rpm, 0);
279: i++;
280: rpm->nb_requires++;
1.8 veillard 281: } else if (verbose > 1) {
1.7 veillard 282: fprintf(stderr, "%s : malformed Resource element !\n", file);
283: }
1.8 veillard 284: } else if (verbose > 1) {
1.7 veillard 285: fprintf(stderr, "%s : malformed Provides bag !\n", file);
286: }
287: elem = rdfNextElem(elem);
288: }
289: }
1.5 veillard 290:
1.6 veillard 291: /*
292: * Finish filling the rpmData structure.
293: */
294: #ifdef HAVE_SNPRINTF
295: sprintf(nameBuffer, "%s-%s-%s.rpm",
296: rpm->name, rpm->version, rpm->release);
297: #else
298: snprintf(nameBuffer, 200, "%s-%s-%s.rpm",
299: rpm->name, rpm->version, rpm->release);
300: #endif
301: rpm->filename = strdup(nameBuffer);
302:
303: /* Add the package files to the real filesystem tree if asked for */
304: if ((dir->build_tree != 0) && (rpm->filelist != NULL)) {
305: char *cur, *filename;
306:
307: cur = rpm->filelist;
308: while ((*cur != '\0') && (*cur != '/')) cur++;
309: filename = cur;
310: while (*cur != '\0') {
311: if ((*cur == '\n') || (*cur == '\r')) {
312: if (cur != filename)
313: rpmAddRealFile(dir->root, filename, rpm);
314: while ((*cur != '\0') && (*cur != '/')) cur++;
315: filename = cur;
316: } else
317: cur++;
318: }
319: if (cur != filename)
320: rpmAddRealFile(dir->root, filename, rpm);
321: }
322:
323: /* Register this package */
324: rpmAddSoftware(rpm);
325:
326: /* dump the HTML related to this package */
327: if (rpm2html_dump_html)
328: dumpRpmHtml(rpm, tree);
329: if (rpm2html_dump_rdf)
330: dumpRpmRdf(rpm, tree);
331:
332: /* free large amount of data not used later */
333: if (rpm->filelist) free(rpm->filelist);
334: rpm->filelist = NULL;
335: if (rpm->copyright) free(rpm->copyright);
336: rpm->copyright = NULL;
337: if (rpm->changelog) free(rpm->changelog);
338: rpm->changelog = NULL;
339: if (rpm->description) free(rpm->description);
340: rpm->description = NULL;
341:
342: /* increment the counters */
343: rpm2html_files++;
344: rpm2html_size += rpm->size / 1024;
345:
346: /*
347: * Cleanup.
348: */
1.5 veillard 349: rdfDestroySchema(rdf);
350: return(rpm);
1.1 httpng 351: }
352:
353: /*
1.4 veillard 354: * Create and RDF file containing the description for the given RPM data.
1.1 httpng 355: */
356: void dumpRpmRdf(rpmDataPtr rpm, rpmSubdirPtr tree) {
357: struct tm * tstruct;
358: rpmDirPtr dir = rpm->dir;
1.3 veillard 359: char *base = dir->dir;
1.1 httpng 360: int i;
1.4 veillard 361: char buf[10000];
362: char file[1000];
363: rdfSchema rdf;
364: rdfNamespace rpmNs;
365: rdfDescription desc;
366: rdfBag bag;
1.1 httpng 367:
1.7 veillard 368: if (!rpm2html_dump_rdf) return;
369:
1.3 veillard 370: if (rpm2html_rdf_dir != NULL) base = rpm2html_rdf_dir;
371:
1.1 httpng 372: if ((dir->subdir != NULL) && (dir->subdir[0] != '\0')) {
373: if ((rpm->subdir != NULL) && (rpm->subdir[0] != '\0'))
1.4 veillard 374: sprintf(file, "%s/%s/%s/%s.rdf", base, dir->subdir,
1.1 httpng 375: rpm->subdir, rpmName(rpm));
376: else
1.4 veillard 377: sprintf(file, "%s/%s/%s.rdf", base, dir->subdir, rpmName(rpm));
1.1 httpng 378: } else {
379: if ((rpm->subdir != NULL) && (rpm->subdir[0] != '\0'))
1.4 veillard 380: sprintf(file, "%s/%s/%s.rdf", base, rpm->subdir, rpmName(rpm));
1.1 httpng 381: else
1.4 veillard 382: sprintf(file, "%s/%s.rdf", base, rpmName(rpm));
1.1 httpng 383: }
384:
1.4 veillard 385: if (checkDate(file, rpm->stamp)) return;
1.9 veillard 386:
387: /*
388: * Create the directory if needed
389: */
390: if ((dir->subdir != NULL) && (dir->subdir[0] != '\0')) {
391: if ((rpm->subdir != NULL) && (rpm->subdir[0] != '\0'))
392: sprintf(buf, "%s/%s/%s", base, dir->subdir, rpm->subdir);
393: else
394: sprintf(buf, "%s/%s", base, dir->subdir);
395: } else {
396: if ((rpm->subdir != NULL) && (rpm->subdir[0] != '\0'))
397: sprintf(buf, "%s/%s", base, rpm->subdir);
398: else
399: sprintf(buf, "%s", base);
400: }
401: createDirectory(buf);
402:
1.1 httpng 403: if (verbose > 1) {
1.4 veillard 404: printf("Dumping %s\n", file);
1.1 httpng 405: }
1.4 veillard 406:
407: /*
408: * build the RDF document tree
409: * Note : the order is not important but following the rpmData
410: * structure order is easier to check.
411: */
412: rdf = rdfNewSchema();
413: rpmNs = rdfNewNamespace(rdf, "http://www.rpm.org/", "RPM");
414:
1.2 httpng 415: if ((rpm->subdir != NULL) && (rpm->subdir[0] != '\0')) {
416: if (dir->mirrors[0] != NULL)
1.4 veillard 417: sprintf(buf, "%s/%s/%s",
1.2 httpng 418: dir->mirrors[0], rpm->subdir, rpm->filename);
419: else
1.4 veillard 420: sprintf(buf, "%s/%s/%s",
1.2 httpng 421: dir->ftp, rpm->subdir, rpm->filename);
422: } else {
423: if (dir->mirrors[0] != NULL)
1.4 veillard 424: sprintf(buf, "%s/%s",
1.2 httpng 425: dir->mirrors[0], rpm->filename);
426: else
1.4 veillard 427: sprintf(buf, "%s/%s",
1.2 httpng 428: dir->ftp, rpm->filename);
429: }
1.4 veillard 430: desc = rdfAddDescription(rdf, NULL, buf);
431:
432: rdfSetValue(desc, "Name", rpmNs, rpm->name);
433: rdfSetValue(desc, "Version", rpmNs, rpm->version);
434: rdfSetValue(desc, "Release", rpmNs, rpm->release);
435: if (rpm->url)
436: rdfSetValue(desc, "URL", rpmNs, rpm->url);
437: if (rpm->arch)
438: rdfSetValue(desc, "Arch", rpmNs, rpm->arch);
439: if (rpm->os)
440: rdfSetValue(desc, "Os", rpmNs, rpm->os);
1.2 httpng 441: if (rpm->distribution)
1.4 veillard 442: rdfSetValue(desc, "Distribution", rpmNs, rpm->distribution);
1.2 httpng 443: if (rpm->vendor)
1.4 veillard 444: rdfSetValue(desc, "Vendor", rpmNs, rpm->vendor);
445: if (rpm->packager)
446: rdfSetValue(desc, "Packager", rpmNs, rpm->packager);
447: if (rpm->group)
448: rdfSetValue(desc, "Group", rpmNs, rpm->group);
449: if (rpm->summary)
450: rdfSetValue(desc, "Summary", rpmNs, rpm->summary);
451: if (rpm->description)
452: rdfSetValue(desc, "Description", rpmNs, rpm->description);
453: if (rpm->copyright)
454: rdfSetValue(desc, "Copyright", rpmNs, rpm->copyright);
455: if (rpm->changelog)
456: rdfSetValue(desc, "Changelog", rpmNs, rpm->changelog);
457: if (rpm->srcrpm) {
1.7 veillard 458: rdfSetValue(desc, "Sources", rpmNs, rpm->srcrpm);
1.4 veillard 459: if (dir->ftpsrc) {
1.7 veillard 460: rdfSetValue(desc, "SourcesFtp", rpmNs, dir->ftpsrc);
1.4 veillard 461: }
462: }
1.2 httpng 463: tstruct = localtime(&(rpm->date));
464: #ifdef HAVE_STRFTIME
465: strftime(buf, sizeof(buf) - 1, "%c", tstruct);
466: #else
467: #error "no strftime, please check !"
468: #endif
1.4 veillard 469: rdfSetValue(desc, "BuildDate", rpmNs, buf);
1.10 veillard 470: sprintf(buf, "%d", rpm->date);
471: rdfSetValue(desc, "Date", rpmNs, buf);
1.4 veillard 472: sprintf(buf, "%d", rpm->size);
473: rdfSetValue(desc, "Size", rpmNs, buf);
1.2 httpng 474: if (rpm->host)
1.4 veillard 475: rdfSetValue(desc, "BuildHost", rpmNs, rpm->host);
1.2 httpng 476: if (rpm->nb_resources > 0) {
1.7 veillard 477: /** !!!!!
478: sprintf(buf, "%d", rpm->nb_resources);
479: rdfSetValue(desc, "NbProvides", rpmNs, buf);
480: */
1.4 veillard 481: bag = rdfBagCreate(rdf, desc, "Provides", rpmNs);
1.2 httpng 482: for (i = 0;i < rpm->nb_resources;i++) {
1.4 veillard 483: rdfBagAddValue(bag, "Resource", rpmNs,
484: rpm->resources[i]->name, NULL);
1.2 httpng 485: }
486: }
487: if (rpm->nb_requires > 0) {
1.7 veillard 488: /** !!!!!
489: sprintf(buf, "%d", rpm->nb_requires);
490: rdfSetValue(desc, "NbRequires", rpmNs, buf);
491: */
1.4 veillard 492: bag = rdfBagCreate(rdf, desc, "Requires", rpmNs);
1.2 httpng 493: for (i = 0;i < rpm->nb_requires;i++) {
1.4 veillard 494: rdfBagAddValue(bag, "Resource", rpmNs,
495: rpm->requires[i]->name, NULL);
1.2 httpng 496: }
497: }
498: if (rpm->filelist)
1.4 veillard 499: rdfSetValue(desc, "Files", rpmNs, rpm->filelist);
500:
501: /*
502: * Save the RDF file and cleanup the tree.
503: */
504: rdfWrite(rdf, file);
505: rdfDestroySchema(rdf);
1.1 httpng 506: }
507:
Webmaster