1 /** \ingroup header
2 * \file lib/formats.c
3 */
4
5 #include "system.h"
6
7 #include <rpm/rpmtypes.h>
8 #include <rpm/rpmlib.h>
9 #include <rpm/rpmmacro.h> /* XXX for %_i18ndomains */
10 #include <rpm/rpmfi.h>
11 #include <rpm/rpmstring.h>
12 #include <rpm/rpmlog.h>
13 #include "lib/misc.h" /* tag function proto */
14
15 #include "debug.h"
16
17 struct headerTagFunc_s {
18 rpmTag tag; /*!< Tag of extension. */
19 headerTagTagFunction func; /*!< Pointer to formatter function. */
20 };
21
22 /** \ingroup rpmfi
23 * Retrieve file names from header.
24 *
25 * The representation of file names in package headers changed in rpm-4.0.
26 * Originally, file names were stored as an array of absolute paths.
27 * In rpm-4.0, file names are stored as separate arrays of dirname's and
28 * basename's, * with a dirname index to associate the correct dirname
29 * with each basname.
30 *
31 * This function is used to retrieve file names independent of how the
32 * file names are represented in the package header.
33 *
34 * @param h header
35 * @param tagN RPMTAG_BASENAMES | PMTAG_ORIGBASENAMES
36 * @param withstate take file state into account?
37 * @retval td tag data container
38 * @return 1 on success
39 */
fnTag(Header h,rpmTag tagN,int withstate,rpmtd td)40 static int fnTag(Header h, rpmTag tagN, int withstate, rpmtd td)
41 {
42 const char **baseNames, **dirNames;
43 const char *fileStates = NULL;
44 uint32_t *dirIndexes;
45 rpm_count_t count, retcount, dncount;
46 size_t size = 0;
47 rpmTag dirNameTag = RPMTAG_DIRNAMES;
48 rpmTag dirIndexesTag = RPMTAG_DIRINDEXES;
49 int i, j;
50 int rc = 0; /* assume failure */
51 struct rpmtd_s bnames, dnames, dixs, fstates;
52
53 if (tagN == RPMTAG_ORIGBASENAMES) {
54 dirNameTag = RPMTAG_ORIGDIRNAMES;
55 dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
56 }
57
58 if (!headerGet(h, tagN, &bnames, HEADERGET_MINMEM)) {
59 return 0; /* no file list */
60 }
61
62 (void) headerGet(h, dirNameTag, &dnames, HEADERGET_MINMEM);
63 (void) headerGet(h, dirIndexesTag, &dixs, HEADERGET_MINMEM);
64
65 retcount = count = rpmtdCount(&bnames);
66 dncount = rpmtdCount(&dnames);
67
68 /* Basic sanity checking for our interrelated tags */
69 if (rpmtdCount(&dixs) != count || dncount < 1 || dncount > count)
70 td->flags |= RPMTD_INVALID;
71
72 if (withstate) {
73 /* no recorded states means no installed files */
74 if (!headerGet(h, RPMTAG_FILESTATES, &fstates, HEADERGET_MINMEM))
75 goto exit;
76 if (rpmtdCount(&fstates) != count)
77 td->flags |= RPMTD_INVALID;
78 fileStates = fstates.data;
79 }
80
81 if (td->flags & RPMTD_INVALID)
82 goto exit;
83
84 baseNames = bnames.data;
85 dirNames = dnames.data;
86 dirIndexes = dixs.data;
87
88 /*
89 * fsm, psm and rpmfi assume the data is stored in a single allocation
90 * block, until those assumptions are removed we need to jump through
91 * a few hoops here and precalculate sizes etc
92 */
93 for (i = 0; i < count; i++) {
94 if (fileStates && !RPMFILE_IS_INSTALLED(fileStates[i])) {
95 retcount--;
96 continue;
97 }
98 /* Sanity check directory indexes are within bounds */
99 if (dirIndexes[i] >= dncount) {
100 td->flags |= RPMTD_INVALID;
101 break;
102 }
103 size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
104 }
105
106 if (!(td->flags & RPMTD_INVALID)) {
107 char **fileNames = xmalloc(size + (sizeof(*fileNames) * retcount));
108 char *t = ((char *) fileNames) + (sizeof(*fileNames) * retcount);
109 for (i = 0, j = 0; i < count; i++) {
110 if (fileStates && !RPMFILE_IS_INSTALLED(fileStates[i]))
111 continue;
112 fileNames[j++] = t;
113 t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
114 *t++ = '\0';
115 }
116
117 td->data = fileNames;
118 td->count = retcount;
119 td->type = RPM_STRING_ARRAY_TYPE;
120 td->flags |= RPMTD_ALLOCED;
121 rc = 1;
122 }
123
124 exit:
125 rpmtdFreeData(&bnames);
126 rpmtdFreeData(&dnames);
127 rpmtdFreeData(&dixs);
128 /* only safe if the headerGet() on file states was actually called */
129 if (fileStates)
130 rpmtdFreeData(&fstates);
131
132 return rc;
133 }
134
filedepTag(Header h,rpmTag tagN,rpmtd td,headerGetFlags hgflags)135 static int filedepTag(Header h, rpmTag tagN, rpmtd td, headerGetFlags hgflags)
136 {
137 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
138 rpmds ds = NULL;
139 char **fdeps = NULL;
140 int numfiles;
141 char deptype = 'R';
142 int fileix;
143 int rc = 0;
144
145 numfiles = rpmfiFC(fi);
146 if (numfiles <= 0) {
147 goto exit;
148 }
149
150 if (tagN == RPMTAG_PROVIDENAME)
151 deptype = 'P';
152 else if (tagN == RPMTAG_REQUIRENAME)
153 deptype = 'R';
154
155 ds = rpmdsNew(h, tagN, 0);
156 fdeps = xmalloc(numfiles * sizeof(*fdeps));
157
158 while ((fileix = rpmfiNext(fi)) >= 0) {
159 ARGV_t deps = NULL;
160 const uint32_t * ddict = NULL;
161 int ndx = rpmfiFDepends(fi, &ddict);
162 if (ddict != NULL) {
163 while (ndx-- > 0) {
164 const char * DNEVR;
165 unsigned dix = *ddict++;
166 char mydt = ((dix >> 24) & 0xff);
167 if (mydt != deptype)
168 continue;
169 dix &= 0x00ffffff;
170 (void) rpmdsSetIx(ds, dix-1);
171 if (rpmdsNext(ds) < 0)
172 continue;
173 DNEVR = rpmdsDNEVR(ds);
174 if (DNEVR != NULL) {
175 argvAdd(&deps, DNEVR + 2);
176 }
177 }
178 }
179 fdeps[fileix] = deps ? argvJoin(deps, " ") : xstrdup("");
180 argvFree(deps);
181 }
182 td->data = fdeps;
183 td->count = numfiles;
184 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
185 td->type = RPM_STRING_ARRAY_TYPE;
186 rc = 1;
187
188 exit:
189 rpmfiFree(fi);
190 rpmdsFree(ds);
191 return rc;
192 }
193
194 typedef enum tMode_e {
195 NORMALTRIGGER = 0,
196 FILETRIGGER = 1,
197 TRANSFILETRIGGER = 2,
198 } tMode;
199
200 /**
201 * Retrieve trigger info.
202 * @param mode type of trigger (see tMode_e)
203 * @param h header
204 * @retval td tag data container
205 * @param hgflags header get flags
206 * @return 1 on success
207 */
triggercondsTagFor(tMode mode,Header h,rpmtd td,headerGetFlags hgflags)208 static int triggercondsTagFor(tMode mode, Header h, rpmtd td,
209 headerGetFlags hgflags)
210 {
211 uint32_t * indices;
212 int i, j;
213 char ** conds;
214 struct rpmtd_s nametd, indextd, flagtd, versiontd, scripttd;
215 int hgeflags = HEADERGET_MINMEM;
216 rpmTagVal triggername, triggerindex, triggerflags;
217 rpmTagVal triggerversion, triggerscripts;
218
219 switch (mode) {
220 case NORMALTRIGGER:
221 triggername = RPMTAG_TRIGGERNAME;
222 triggerindex = RPMTAG_TRIGGERINDEX;
223 triggerflags = RPMTAG_TRIGGERFLAGS;
224 triggerversion = RPMTAG_TRIGGERVERSION;
225 triggerscripts = RPMTAG_TRIGGERSCRIPTS;
226 break;
227 case FILETRIGGER:
228 triggername = RPMTAG_FILETRIGGERNAME;
229 triggerindex = RPMTAG_FILETRIGGERINDEX;
230 triggerflags = RPMTAG_FILETRIGGERFLAGS;
231 triggerversion = RPMTAG_FILETRIGGERVERSION;
232 triggerscripts = RPMTAG_FILETRIGGERSCRIPTS;
233 break;
234 case TRANSFILETRIGGER:
235 triggername = RPMTAG_TRANSFILETRIGGERNAME;
236 triggerindex = RPMTAG_TRANSFILETRIGGERINDEX;
237 triggerflags = RPMTAG_TRANSFILETRIGGERFLAGS;
238 triggerversion = RPMTAG_TRANSFILETRIGGERVERSION;
239 triggerscripts = RPMTAG_TRANSFILETRIGGERSCRIPTS;
240 break;
241 default:
242 return 0;
243 }
244
245 if (!headerGet(h, triggername, &nametd, hgeflags)) {
246 return 0;
247 }
248
249 headerGet(h, triggerindex, &indextd, hgeflags);
250 headerGet(h, triggerflags, &flagtd, hgeflags);
251 headerGet(h, triggerversion, &versiontd, hgeflags);
252 headerGet(h, triggerscripts, &scripttd, hgeflags);
253
254 td->type = RPM_STRING_ARRAY_TYPE;
255 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
256 td->data = conds = xmalloc(sizeof(*conds) * rpmtdCount(&scripttd));
257 td->count = rpmtdCount(&scripttd);
258
259 indices = indextd.data;
260
261 while ((i = rpmtdNext(&scripttd)) >= 0) {
262 rpm_flag_t *flag;
263 char *flagStr, *item;
264 ARGV_t items = NULL;
265
266 rpmtdInit(&nametd); rpmtdInit(&flagtd); rpmtdInit(&versiontd);
267 while ((j = rpmtdNext(&nametd)) >= 0) {
268 /* flag and version arrays match name array size always */
269 rpmtdNext(&flagtd); rpmtdNext(&versiontd);
270
271 if (indices[j] != i)
272 continue;
273
274 flag = rpmtdGetUint32(&flagtd);
275 if (flag && *flag & RPMSENSE_SENSEMASK) {
276 flagStr = rpmtdFormat(&flagtd, RPMTD_FORMAT_DEPFLAGS, NULL);
277 rasprintf(&item, "%s %s %s", rpmtdGetString(&nametd),
278 flagStr,
279 rpmtdGetString(&versiontd));
280 free(flagStr);
281 } else {
282 item = xstrdup(rpmtdGetString(&nametd));
283 }
284
285 argvAdd(&items, item);
286 free(item);
287 }
288
289 conds[i] = argvJoin(items, ", ");
290 argvFree(items);
291 }
292
293 rpmtdFreeData(&nametd);
294 rpmtdFreeData(&versiontd);
295 rpmtdFreeData(&flagtd);
296 rpmtdFreeData(&indextd);
297 rpmtdFreeData(&scripttd);
298 return 1;
299 }
300
triggercondsTag(Header h,rpmtd td,headerGetFlags hgflags)301 static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
302 {
303 return triggercondsTagFor(NORMALTRIGGER, h, td, hgflags);
304 }
305
filetriggercondsTag(Header h,rpmtd td,headerGetFlags hgflags)306 static int filetriggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
307 {
308 return triggercondsTagFor(FILETRIGGER, h, td, hgflags);
309 }
310
transfiletriggercondsTag(Header h,rpmtd td,headerGetFlags hgflags)311 static int transfiletriggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
312 {
313 return triggercondsTagFor(TRANSFILETRIGGER, h, td, hgflags);
314 }
315
316 /**
317 * Retrieve trigger type info.
318 * @param mode type of trigger (see tMode_e)
319 * @param h header
320 * @retval td tag data container
321 * @param hgflags header get flags
322 * @return 1 on success
323 */
triggertypeTagFor(tMode mode,Header h,rpmtd td,headerGetFlags hgflags)324 static int triggertypeTagFor(tMode mode, Header h, rpmtd td,
325 headerGetFlags hgflags)
326 {
327 int i;
328 char ** conds;
329 struct rpmtd_s indices, flags, scripts;
330 rpmTagVal triggerindex, triggerflags, triggerscripts;
331
332 switch (mode) {
333 case NORMALTRIGGER:
334 triggerindex = RPMTAG_TRIGGERINDEX;
335 triggerflags = RPMTAG_TRIGGERFLAGS;
336 triggerscripts = RPMTAG_TRIGGERSCRIPTS;
337 break;
338 case FILETRIGGER:
339 triggerindex = RPMTAG_FILETRIGGERINDEX;
340 triggerflags = RPMTAG_FILETRIGGERFLAGS;
341 triggerscripts = RPMTAG_FILETRIGGERSCRIPTS;
342 break;
343 case TRANSFILETRIGGER:
344 triggerindex = RPMTAG_TRANSFILETRIGGERINDEX;
345 triggerflags = RPMTAG_TRANSFILETRIGGERFLAGS;
346 triggerscripts = RPMTAG_TRANSFILETRIGGERSCRIPTS;
347 break;
348 default:
349 return 0;
350 }
351
352 if (!headerGet(h, triggerindex, &indices, HEADERGET_MINMEM)) {
353 return 0;
354 }
355
356 headerGet(h, triggerflags, &flags, HEADERGET_MINMEM);
357 headerGet(h, triggerscripts, &scripts, HEADERGET_MINMEM);
358
359 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
360 td->count = rpmtdCount(&scripts);
361 td->data = conds = xmalloc(sizeof(*conds) * td->count);
362 td->type = RPM_STRING_ARRAY_TYPE;
363
364 while ((i = rpmtdNext(&scripts)) >= 0) {
365 rpm_flag_t *flag;
366 rpmtdInit(&indices); rpmtdInit(&flags);
367
368 while (rpmtdNext(&indices) >= 0 && rpmtdNext(&flags) >= 0) {
369 if (*rpmtdGetUint32(&indices) != i)
370 continue;
371
372 flag = rpmtdGetUint32(&flags);
373 if (*flag & RPMSENSE_TRIGGERPREIN)
374 conds[i] = xstrdup("prein");
375 else if (*flag & RPMSENSE_TRIGGERIN)
376 conds[i] = xstrdup("in");
377 else if (*flag & RPMSENSE_TRIGGERUN)
378 conds[i] = xstrdup("un");
379 else if (*flag & RPMSENSE_TRIGGERPOSTUN)
380 conds[i] = xstrdup("postun");
381 else
382 conds[i] = xstrdup("");
383 break;
384 }
385 }
386 rpmtdFreeData(&indices);
387 rpmtdFreeData(&flags);
388 rpmtdFreeData(&scripts);
389
390 return 1;
391 }
392
triggertypeTag(Header h,rpmtd td,headerGetFlags hgflags)393 static int triggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
394 {
395 return triggertypeTagFor(NORMALTRIGGER, h, td, hgflags);
396 }
397
filetriggertypeTag(Header h,rpmtd td,headerGetFlags hgflags)398 static int filetriggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
399 {
400 return triggertypeTagFor(FILETRIGGER, h, td, hgflags);
401 }
402
transfiletriggertypeTag(Header h,rpmtd td,headerGetFlags hgflags)403 static int transfiletriggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
404 {
405 return triggertypeTagFor(TRANSFILETRIGGER, h, td, hgflags);
406 }
407
408 /**
409 * Retrieve installed file paths.
410 * @param h header
411 * @retval td tag data container
412 * @param hgflags header get flags
413 * @return 1 on success
414 */
instfilenamesTag(Header h,rpmtd td,headerGetFlags hgflags)415 static int instfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
416 {
417 return fnTag(h, RPMTAG_BASENAMES, 1, td);
418 }
419
420 /**
421 * Retrieve file paths.
422 * @param h header
423 * @retval td tag data container
424 * @param hgflags header get flags
425 * @return 1 on success
426 */
filenamesTag(Header h,rpmtd td,headerGetFlags hgflags)427 static int filenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
428 {
429 return fnTag(h, RPMTAG_BASENAMES, 0, td);
430 }
431
432 /**
433 * Retrieve original file paths (wrt relocation).
434 * @param h header
435 * @retval td tag data container
436 * @param hgflags header get flags
437 * @return 1 on success
438 */
origfilenamesTag(Header h,rpmtd td,headerGetFlags hgflags)439 static int origfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
440 {
441 return fnTag(h, RPMTAG_ORIGBASENAMES, 0, td);
442 }
443
444 /*
445 * Attempt to generate libmagic-style file class if missing from header:
446 * we can easily generate this for symlinks and other special types.
447 * Always return malloced strings to simplify life in fileclassTag().
448 */
makeFClass(rpmfi fi)449 static char *makeFClass(rpmfi fi)
450 {
451 char *fclass = NULL;
452 const char *hc = rpmfiFClass(fi);
453
454 if (hc != NULL && hc[0] != '\0') {
455 fclass = xstrdup(hc);
456 } else {
457 switch (rpmfiFMode(fi) & S_IFMT) {
458 case S_IFBLK:
459 fclass = xstrdup("block special");
460 break;
461 case S_IFCHR:
462 fclass = xstrdup("character special");
463 break;
464 case S_IFDIR:
465 fclass = xstrdup("directory");
466 break;
467 case S_IFIFO:
468 fclass = xstrdup("fifo (named pipe)");
469 break;
470 case S_IFSOCK:
471 fclass = xstrdup("socket");
472 break;
473 case S_IFLNK:
474 fclass = rstrscat(NULL, "symbolic link to `",
475 rpmfiFLink(fi), "'", NULL);
476 break;
477 }
478 }
479
480 return (fclass != NULL) ? fclass : xstrdup("");
481 }
482
483 /**
484 * Retrieve/generate file classes.
485 * @param h header
486 * @retval td tag data container
487 * @param hgflags header get flags
488 * @return 1 on success
489 */
fileclassTag(Header h,rpmtd td,headerGetFlags hgflags)490 static int fileclassTag(Header h, rpmtd td, headerGetFlags hgflags)
491 {
492 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
493 int numfiles = rpmfiFC(fi);
494
495 if (numfiles > 0) {
496 char **fclasses = xmalloc(numfiles * sizeof(*fclasses));
497 int ix;
498
499 rpmfiInit(fi, 0);
500 while ((ix = rpmfiNext(fi)) >= 0) {
501 fclasses[ix] = makeFClass(fi);
502 }
503
504 td->data = fclasses;
505 td->count = numfiles;
506 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
507 td->type = RPM_STRING_ARRAY_TYPE;
508 }
509
510 rpmfiFree(fi);
511 return (numfiles > 0);
512 }
513
514 /**
515 * Retrieve file provides.
516 * @param h header
517 * @retval td tag data container
518 * @param hgflags header get flags
519 * @return 1 on success
520 */
fileprovideTag(Header h,rpmtd td,headerGetFlags hgflags)521 static int fileprovideTag(Header h, rpmtd td, headerGetFlags hgflags)
522 {
523 return filedepTag(h, RPMTAG_PROVIDENAME, td, hgflags);
524 }
525
526 /**
527 * Retrieve file requires.
528 * @param h header
529 * @retval td tag data container
530 * @param hgflags header get flags
531 * @return 1 on success
532 */
filerequireTag(Header h,rpmtd td,headerGetFlags hgflags)533 static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags)
534 {
535 return filedepTag(h, RPMTAG_REQUIRENAME, td, hgflags);
536 }
537
538 /* I18N look aside diversions */
539
540 #if defined(ENABLE_NLS)
541 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
542 #endif
543 static const char * const language = "LANGUAGE";
544
545 static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
546
547 /**
548 * Retrieve i18n text.
549 * @param h header
550 * @param tag tag
551 * @retval td tag data container
552 * @param hgflags header get flags
553 * @return 1 on success
554 */
i18nTag(Header h,rpmTag tag,rpmtd td,headerGetFlags hgflags)555 static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags)
556 {
557 int rc;
558 #if defined(ENABLE_NLS)
559 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
560
561 td->type = RPM_STRING_TYPE;
562 td->data = NULL;
563 td->count = 0;
564
565 if (dstring && *dstring) {
566 char *domain, *de;
567 const char * langval;
568 char * msgkey;
569 const char * msgid;
570
571 rasprintf(&msgkey, "%s(%s)", headerGetString(h, RPMTAG_NAME),
572 rpmTagGetName(tag));
573
574 /* change to en_US for msgkey -> msgid resolution */
575 langval = getenv(language);
576 (void) setenv(language, "en_US", 1);
577 ++_nl_msg_cat_cntr;
578
579 msgid = NULL;
580 for (domain = dstring; domain != NULL; domain = de) {
581 de = strchr(domain, ':');
582 if (de) *de++ = '\0';
583 msgid = dgettext(domain, msgkey);
584 if (msgid != msgkey) break;
585 }
586
587 /* restore previous environment for msgid -> msgstr resolution */
588 if (langval)
589 (void) setenv(language, langval, 1);
590 else
591 unsetenv(language);
592 ++_nl_msg_cat_cntr;
593
594 if (domain && msgid) {
595 td->data = dgettext(domain, msgid);
596 td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */
597 td->count = 1;
598 td->flags = RPMTD_ALLOCED;
599 }
600 dstring = _free(dstring);
601 free(msgkey);
602 if (td->data)
603 return 1;
604 }
605
606 free(dstring);
607 #endif
608
609 rc = headerGet(h, tag, td, HEADERGET_ALLOC);
610 return rc;
611 }
612
613 /**
614 * Retrieve summary text.
615 * @param h header
616 * @retval td tag data container
617 * @param hgflags header get flags
618 * @return 1 on success
619 */
summaryTag(Header h,rpmtd td,headerGetFlags hgflags)620 static int summaryTag(Header h, rpmtd td, headerGetFlags hgflags)
621 {
622 return i18nTag(h, RPMTAG_SUMMARY, td, hgflags);
623 }
624
625 /**
626 * Retrieve description text.
627 * @param h header
628 * @retval td tag data container
629 * @param hgflags header get flags
630 * @return 1 on success
631 */
descriptionTag(Header h,rpmtd td,headerGetFlags hgflags)632 static int descriptionTag(Header h, rpmtd td, headerGetFlags hgflags)
633 {
634 return i18nTag(h, RPMTAG_DESCRIPTION, td, hgflags);
635 }
636
637 /**
638 * Retrieve group text.
639 * @param h header
640 * @retval td tag data container
641 * @param hgflags header get flags
642 * @return 1 on success
643 */
groupTag(Header h,rpmtd td,headerGetFlags hgflags)644 static int groupTag(Header h, rpmtd td, headerGetFlags hgflags)
645 {
646 return i18nTag(h, RPMTAG_GROUP, td, hgflags);
647 }
648
649 /*
650 * Helper to convert 32bit tag to 64bit version.
651 * If header has new 64bit tag then just return the data,
652 * otherwise convert 32bit old tag data to 64bit values.
653 * For consistency, always return malloced data.
654 */
get64(Header h,rpmtd td,rpmTag newtag,rpmTag oldtag)655 static int get64(Header h, rpmtd td, rpmTag newtag, rpmTag oldtag)
656 {
657 int rc;
658
659 if (headerIsEntry(h, newtag)) {
660 rc = headerGet(h, newtag, td, HEADERGET_ALLOC);
661 } else {
662 struct rpmtd_s olddata;
663 uint32_t *d32 = NULL;
664 uint64_t *d64 = NULL;
665
666 headerGet(h, oldtag, &olddata, HEADERGET_MINMEM);
667 if (rpmtdType(&olddata) == RPM_INT32_TYPE) {
668 td->type = RPM_INT64_TYPE;
669 td->count = olddata.count;
670 td->flags = RPMTD_ALLOCED;
671 td->data = xmalloc(sizeof(*d64) * td->count);
672 d64 = td->data;
673 while ((d32 = rpmtdNextUint32(&olddata))) {
674 *d64++ = *d32;
675 }
676 }
677 rpmtdFreeData(&olddata);
678 rc = d64 ? 1 : 0;
679 }
680
681 return rc;
682 }
683
684 /**
685 * Retrieve file sizes as 64bit regardless of how they're stored.
686 * @param h header
687 * @retval td tag data container
688 * @param hgflags header get flags
689 * @return 1 on success
690 */
longfilesizesTag(Header h,rpmtd td,headerGetFlags hgflags)691 static int longfilesizesTag(Header h, rpmtd td, headerGetFlags hgflags)
692 {
693 return get64(h, td, RPMTAG_LONGFILESIZES, RPMTAG_FILESIZES);
694 }
695
longarchivesizeTag(Header h,rpmtd td,headerGetFlags hgflags)696 static int longarchivesizeTag(Header h, rpmtd td, headerGetFlags hgflags)
697 {
698 return get64(h, td, RPMTAG_LONGARCHIVESIZE, RPMTAG_ARCHIVESIZE);
699 }
700
longsizeTag(Header h,rpmtd td,headerGetFlags hgflags)701 static int longsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
702 {
703 return get64(h, td, RPMTAG_LONGSIZE, RPMTAG_SIZE);
704 }
705
longsigsizeTag(Header h,rpmtd td,headerGetFlags hgflags)706 static int longsigsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
707 {
708 return get64(h, td, RPMTAG_LONGSIGSIZE, RPMTAG_SIGSIZE);
709 }
710
numberTag(rpmtd td,uint32_t val)711 static int numberTag(rpmtd td, uint32_t val)
712 {
713 uint32_t *tval = xmalloc(sizeof(*tval));
714
715 tval[0] = val;
716 td->type = RPM_INT32_TYPE;
717 td->count = 1;
718 td->data = tval;
719 td->flags = RPMTD_ALLOCED;
720 return 1; /* this cannot fail */
721 }
722
dbinstanceTag(Header h,rpmtd td,headerGetFlags hgflags)723 static int dbinstanceTag(Header h, rpmtd td, headerGetFlags hgflags)
724 {
725 return numberTag(td, headerGetInstance(h));
726 }
727
headercolorTag(Header h,rpmtd td,headerGetFlags hgflags)728 static int headercolorTag(Header h, rpmtd td, headerGetFlags hgflags)
729 {
730 rpm_color_t *fcolor, hcolor = 0;
731 struct rpmtd_s fcolors;
732
733 headerGet(h, RPMTAG_FILECOLORS, &fcolors, HEADERGET_MINMEM);
734 while ((fcolor = rpmtdNextUint32(&fcolors)) != NULL) {
735 hcolor |= *fcolor;
736 }
737 rpmtdFreeData(&fcolors);
738 hcolor &= 0x0f;
739
740 return numberTag(td, hcolor);
741 }
742
743 enum nevraFlags_e {
744 NEVRA_NAME = (1 << 0),
745 NEVRA_EPOCH = (1 << 1),
746 NEVRA_VERSION = (1 << 2),
747 NEVRA_RELEASE = (1 << 3),
748 NEVRA_ARCH = (1 << 4)
749 };
750 typedef rpmFlags nevraFlags;
751
getNEVRA(Header h,rpmtd td,nevraFlags flags)752 static int getNEVRA(Header h, rpmtd td, nevraFlags flags)
753 {
754 const char *val = NULL;
755 char *res = xstrdup("");
756
757 if ((flags & NEVRA_NAME)) {
758 val = headerGetString(h, RPMTAG_NAME);
759 if (val) rstrscat(&res, val, "-", NULL);
760 }
761 if ((flags & NEVRA_EPOCH)) {
762 char *e = headerGetAsString(h, RPMTAG_EPOCH);
763 if (e) rstrscat(&res, e, ":", NULL);
764 free(e);
765 }
766 if ((flags & NEVRA_VERSION)) {
767 val = headerGetString(h, RPMTAG_VERSION);
768 if (val) rstrscat(&res, val, "-", NULL);
769 }
770 if ((flags & NEVRA_RELEASE)) {
771 val = headerGetString(h, RPMTAG_RELEASE);
772 if (val) rstrscat(&res, val, NULL);
773 }
774 if ((flags & NEVRA_ARCH)) {
775 val = headerGetString(h, RPMTAG_ARCH);
776 if (headerIsSource(h) && val == NULL) val = "src";
777 if (val) rstrscat(&res, ".", val, NULL);
778 }
779
780 td->type = RPM_STRING_TYPE;
781 td->data = res;
782 td->count = 1;
783 td->flags = RPMTD_ALLOCED;
784
785 return 1;
786 }
787
evrTag(Header h,rpmtd td,headerGetFlags hgflags)788 static int evrTag(Header h, rpmtd td, headerGetFlags hgflags)
789 {
790 return getNEVRA(h, td, NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
791 }
792
nvrTag(Header h,rpmtd td,headerGetFlags hgflags)793 static int nvrTag(Header h, rpmtd td, headerGetFlags hgflags)
794 {
795 return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE);
796 }
797
nvraTag(Header h,rpmtd td,headerGetFlags hgflags)798 static int nvraTag(Header h, rpmtd td, headerGetFlags hgflags)
799 {
800 return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
801 }
802
nevrTag(Header h,rpmtd td,headerGetFlags hgflags)803 static int nevrTag(Header h, rpmtd td, headerGetFlags hgflags)
804 {
805 return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
806 }
807
nevraTag(Header h,rpmtd td,headerGetFlags hgflags)808 static int nevraTag(Header h, rpmtd td, headerGetFlags hgflags)
809 {
810 return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
811 }
812
verboseTag(Header h,rpmtd td,headerGetFlags hgflags)813 static int verboseTag(Header h, rpmtd td, headerGetFlags hgflags)
814 {
815 if (rpmIsVerbose()) {
816 td->type = RPM_INT32_TYPE;
817 td->count = 1;
818 td->data = &(td->count);
819 td->flags = RPMTD_NONE;
820 return 1;
821 } else {
822 return 0;
823 }
824 }
825
epochnumTag(Header h,rpmtd td,headerGetFlags hgflags)826 static int epochnumTag(Header h, rpmtd td, headerGetFlags hgflags)
827 {
828 /* For consistency, always return malloced data */
829 if (!headerGet(h, RPMTAG_EPOCH, td, HEADERGET_ALLOC)) {
830 uint32_t *e = malloc(sizeof(*e));
831 *e = 0;
832 td->data = e;
833 td->type = RPM_INT32_TYPE;
834 td->count = 1;
835 td->flags = RPMTD_ALLOCED;
836 }
837 td->tag = RPMTAG_EPOCHNUM;
838 return 1;
839 }
840
depnevrsTag(Header h,rpmtd td,headerGetFlags hgflags,rpmTagVal tag)841 static int depnevrsTag(Header h, rpmtd td, headerGetFlags hgflags,
842 rpmTagVal tag)
843 {
844 rpmds ds = rpmdsNew(h, tag, 0);
845 int ndeps = rpmdsCount(ds);
846
847 if (ndeps > 0) {
848 char **deps = xmalloc(sizeof(*deps) * ndeps);
849 int i;
850 while ((i = rpmdsNext(ds)) >= 0) {
851 deps[i] = rpmdsNewDNEVR(NULL, ds);
852 }
853 td->data = deps;
854 td->type = RPM_STRING_ARRAY_TYPE;
855 td->count = ndeps;
856 td->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
857 }
858 rpmdsFree(ds);
859 return (ndeps > 0);
860 }
861
862 #define RPMSENSE_STRONG (1 << 27)
863
depnevrsTagFiltered(Header h,rpmtd td,headerGetFlags hgflags,rpmTagVal tag,int strong)864 static int depnevrsTagFiltered(Header h, rpmtd td, headerGetFlags hgflags,
865 rpmTagVal tag, int strong)
866 {
867 rpmds ds = rpmdsNew(h, tag, 0);
868 int ndeps = rpmdsCount(ds);
869
870 if (ndeps > 0) {
871 char **deps = xmalloc(sizeof(*deps) * ndeps);
872 ndeps = 0;
873 while (rpmdsNext(ds) >= 0) {
874 if ((rpmdsFlags(ds) & RPMSENSE_STRONG) == (strong ? RPMSENSE_STRONG : 0))
875 deps[ndeps++] = rpmdsNewDNEVR(NULL, ds);
876 }
877 if (ndeps) {
878 td->data = deps;
879 td->type = RPM_STRING_ARRAY_TYPE;
880 td->count = ndeps;
881 td->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
882 } else {
883 _free(deps);
884 }
885 }
886 rpmdsFree(ds);
887 return (ndeps > 0);
888 }
889
requirenevrsTag(Header h,rpmtd td,headerGetFlags hgflags)890 static int requirenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
891 {
892 return depnevrsTag(h, td, hgflags, RPMTAG_REQUIRENAME);
893 }
894
recommendnevrsTag(Header h,rpmtd td,headerGetFlags hgflags)895 static int recommendnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
896 {
897 return depnevrsTag(h, td, hgflags, RPMTAG_RECOMMENDNAME) ||
898 depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDSUGGESTSNAME, 1);
899 }
900
suggestnevrsTag(Header h,rpmtd td,headerGetFlags hgflags)901 static int suggestnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
902 {
903 return depnevrsTag(h, td, hgflags, RPMTAG_SUGGESTNAME) ||
904 depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDSUGGESTSNAME, 0);
905 }
906
supplementnevrsTag(Header h,rpmtd td,headerGetFlags hgflags)907 static int supplementnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
908 {
909 return depnevrsTag(h, td, hgflags, RPMTAG_SUPPLEMENTNAME) ||
910 depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDENHANCESNAME, 1);
911 }
912
enhancenevrsTag(Header h,rpmtd td,headerGetFlags hgflags)913 static int enhancenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
914 {
915 return depnevrsTag(h, td, hgflags, RPMTAG_ENHANCENAME) ||
916 depnevrsTagFiltered(h, td, hgflags, RPMTAG_OLDENHANCESNAME, 0);
917 }
918
providenevrsTag(Header h,rpmtd td,headerGetFlags hgflags)919 static int providenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
920 {
921 return depnevrsTag(h, td, hgflags, RPMTAG_PROVIDENAME);
922 }
923
obsoletenevrsTag(Header h,rpmtd td,headerGetFlags hgflags)924 static int obsoletenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
925 {
926 return depnevrsTag(h, td, hgflags, RPMTAG_OBSOLETENAME);
927 }
928
conflictnevrsTag(Header h,rpmtd td,headerGetFlags hgflags)929 static int conflictnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
930 {
931 return depnevrsTag(h, td, hgflags, RPMTAG_CONFLICTNAME);
932 }
933
filenlinksTag(Header h,rpmtd td,headerGetFlags hgflags)934 static int filenlinksTag(Header h, rpmtd td, headerGetFlags hgflags)
935 {
936 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
937 rpm_count_t fc = rpmfiFC(fi);
938
939 if (fc > 0) {
940 uint32_t *nlinks = xmalloc(fc * sizeof(*nlinks));
941 int ix;
942 while ((ix = rpmfiNext(fi)) >= 0) {
943 nlinks[ix] = rpmfiFNlink(fi);
944 }
945 td->data = nlinks;
946 td->type = RPM_INT32_TYPE;
947 td->count = fc;
948 td->flags = RPMTD_ALLOCED;
949 }
950
951 rpmfiFree(fi);
952 return (fc > 0);
953 }
954
955 static const struct headerTagFunc_s rpmHeaderTagExtensions[] = {
956 { RPMTAG_GROUP, groupTag },
957 { RPMTAG_DESCRIPTION, descriptionTag },
958 { RPMTAG_SUMMARY, summaryTag },
959 { RPMTAG_FILECLASS, fileclassTag },
960 { RPMTAG_FILENAMES, filenamesTag },
961 { RPMTAG_ORIGFILENAMES, origfilenamesTag },
962 { RPMTAG_FILEPROVIDE, fileprovideTag },
963 { RPMTAG_FILEREQUIRE, filerequireTag },
964 { RPMTAG_TRIGGERCONDS, triggercondsTag },
965 { RPMTAG_FILETRIGGERCONDS, filetriggercondsTag },
966 { RPMTAG_TRANSFILETRIGGERCONDS, transfiletriggercondsTag },
967 { RPMTAG_TRIGGERTYPE, triggertypeTag },
968 { RPMTAG_FILETRIGGERTYPE, filetriggertypeTag },
969 { RPMTAG_TRANSFILETRIGGERTYPE, transfiletriggertypeTag },
970 { RPMTAG_LONGFILESIZES, longfilesizesTag },
971 { RPMTAG_LONGARCHIVESIZE, longarchivesizeTag },
972 { RPMTAG_LONGSIZE, longsizeTag },
973 { RPMTAG_LONGSIGSIZE, longsigsizeTag },
974 { RPMTAG_DBINSTANCE, dbinstanceTag },
975 { RPMTAG_EVR, evrTag },
976 { RPMTAG_NVR, nvrTag },
977 { RPMTAG_NEVR, nevrTag },
978 { RPMTAG_NVRA, nvraTag },
979 { RPMTAG_NEVRA, nevraTag },
980 { RPMTAG_HEADERCOLOR, headercolorTag },
981 { RPMTAG_VERBOSE, verboseTag },
982 { RPMTAG_EPOCHNUM, epochnumTag },
983 { RPMTAG_INSTFILENAMES, instfilenamesTag },
984 { RPMTAG_REQUIRENEVRS, requirenevrsTag },
985 { RPMTAG_RECOMMENDNEVRS, recommendnevrsTag},
986 { RPMTAG_SUGGESTNEVRS, suggestnevrsTag},
987 { RPMTAG_SUPPLEMENTNEVRS, supplementnevrsTag},
988 { RPMTAG_ENHANCENEVRS, enhancenevrsTag},
989 { RPMTAG_PROVIDENEVRS, providenevrsTag },
990 { RPMTAG_OBSOLETENEVRS, obsoletenevrsTag },
991 { RPMTAG_CONFLICTNEVRS, conflictnevrsTag },
992 { RPMTAG_FILENLINKS, filenlinksTag },
993 { 0, NULL }
994 };
995
rpmHeaderTagFunc(rpmTagVal tag)996 headerTagTagFunction rpmHeaderTagFunc(rpmTagVal tag)
997 {
998 const struct headerTagFunc_s * ext;
999 headerTagTagFunction func = NULL;
1000
1001 for (ext = rpmHeaderTagExtensions; ext->func != NULL; ext++) {
1002 if (ext->tag == tag) {
1003 func = ext->func;
1004 break;
1005 }
1006 }
1007 return func;
1008 }
1009
1010