On a second thought, rename rpmfiDigest() to rpmfiFDigest() for consistency
[platform/upstream/rpm.git] / lib / rpmfi.c
1 /** \ingroup rpmdep
2  * \file lib/rpmfi.c
3  * Routines to handle file info tag sets.
4  */
5
6 #include "system.h"
7
8 #include <rpm/rpmlog.h>
9 #include <rpm/rpmts.h>
10 #include <rpm/rpmfileutil.h>    /* XXX rpmDoDigest */
11 #include <rpm/rpmstring.h>
12 #include <rpm/rpmmacro.h>       /* XXX rpmCleanPath */
13 #include <rpm/rpmds.h>
14
15 #include "lib/rpmfi_internal.h"
16 #include "lib/rpmte_internal.h" /* relocations */
17 #include "lib/cpio.h"   /* XXX CPIO_FOO */
18 #include "lib/fsm.h"    /* XXX newFSM() */
19
20 #include "debug.h"
21
22
23 int _rpmfi_debug = 0;
24
25 rpmfi rpmfiUnlink(rpmfi fi, const char * msg)
26 {
27     if (fi == NULL) return NULL;
28 if (_rpmfi_debug && msg != NULL)
29 fprintf(stderr, "--> fi %p -- %d %s\n", fi, fi->nrefs, msg);
30     fi->nrefs--;
31     return NULL;
32 }
33
34 rpmfi rpmfiLink(rpmfi fi, const char * msg)
35 {
36     if (fi == NULL) return NULL;
37     fi->nrefs++;
38 if (_rpmfi_debug && msg != NULL)
39 fprintf(stderr, "--> fi %p ++ %d %s\n", fi, fi->nrefs, msg);
40     return fi;
41 }
42
43 rpm_count_t rpmfiFC(rpmfi fi)
44 {
45     return (fi != NULL ? fi->fc : 0);
46 }
47
48 rpm_count_t rpmfiDC(rpmfi fi)
49 {
50     return (fi != NULL ? fi->dc : 0);
51 }
52
53 #ifdef  NOTYET
54 int rpmfiDI(rpmfi fi)
55 {
56 }
57 #endif
58
59 int rpmfiFX(rpmfi fi)
60 {
61     return (fi != NULL ? fi->i : -1);
62 }
63
64 int rpmfiSetFX(rpmfi fi, int fx)
65 {
66     int i = -1;
67
68     if (fi != NULL && fx >= 0 && fx < fi->fc) {
69         i = fi->i;
70         fi->i = fx;
71         fi->j = fi->dil[fi->i];
72     }
73     return i;
74 }
75
76 int rpmfiDX(rpmfi fi)
77 {
78     return (fi != NULL ? fi->j : -1);
79 }
80
81 int rpmfiSetDX(rpmfi fi, int dx)
82 {
83     int j = -1;
84
85     if (fi != NULL && dx >= 0 && dx < fi->dc) {
86         j = fi->j;
87         fi->j = dx;
88     }
89     return j;
90 }
91
92 const char * rpmfiBN(rpmfi fi)
93 {
94     const char * BN = NULL;
95
96     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
97         if (fi->bnl != NULL)
98             BN = fi->bnl[fi->i];
99     }
100     return BN;
101 }
102
103 const char * rpmfiDN(rpmfi fi)
104 {
105     const char * DN = NULL;
106
107     if (fi != NULL && fi->j >= 0 && fi->j < fi->dc) {
108         if (fi->dnl != NULL)
109             DN = fi->dnl[fi->j];
110     }
111     return DN;
112 }
113
114 const char * rpmfiFN(rpmfi fi)
115 {
116     const char * FN = "";
117
118     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
119         char * t;
120         if (fi->fn == NULL)
121             fi->fn = xmalloc(fi->fnlen);
122         FN = t = fi->fn;
123         *t = '\0';
124         t = stpcpy(t, fi->dnl[fi->dil[fi->i]]);
125         t = stpcpy(t, fi->bnl[fi->i]);
126     }
127     return FN;
128 }
129
130 rpmfileAttrs rpmfiFFlags(rpmfi fi)
131 {
132     rpmfileAttrs FFlags = 0;
133
134     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
135         if (fi->fflags != NULL)
136             FFlags = fi->fflags[fi->i];
137     }
138     return FFlags;
139 }
140
141 rpmVerifyAttrs rpmfiVFlags(rpmfi fi)
142 {
143     rpmVerifyAttrs VFlags = 0;
144
145     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
146         if (fi->vflags != NULL)
147             VFlags = fi->vflags[fi->i];
148     }
149     return VFlags;
150 }
151
152 rpm_mode_t rpmfiFMode(rpmfi fi)
153 {
154     rpm_mode_t fmode = 0;
155
156     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
157         if (fi->fmodes != NULL)
158             fmode = fi->fmodes[fi->i];
159     }
160     return fmode;
161 }
162
163 rpmfileState rpmfiFState(rpmfi fi)
164 {
165     rpmfileState fstate = RPMFILE_STATE_MISSING;
166
167     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
168         if (fi->fstates != NULL)
169             fstate = fi->fstates[fi->i];
170     }
171     return fstate;
172 }
173
174 const unsigned char * rpmfiMD5(rpmfi fi)
175 {
176     const unsigned char *digest;
177     pgpHashAlgo algo = 0;
178
179     digest = rpmfiFDigest(fi, &algo, NULL);
180     return (algo == PGPHASHALGO_MD5) ? digest : NULL;
181 }
182
183 const unsigned char * rpmfiFDigest(rpmfi fi, pgpHashAlgo *algo, size_t *len)
184 {
185     const unsigned char *digest = NULL;
186
187     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
188         size_t diglen = rpmDigestLength(fi->digestalgo);
189         if (fi->digests != NULL)
190             digest = fi->digests + (diglen * fi->i);
191         if (len) 
192             *len = diglen;
193         if (algo) 
194             *algo = fi->digestalgo;
195     }
196     return digest;
197 }
198
199 const char * rpmfiFLink(rpmfi fi)
200 {
201     const char * flink = NULL;
202
203     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
204         if (fi->flinks != NULL)
205             flink = fi->flinks[fi->i];
206     }
207     return flink;
208 }
209
210 rpm_off_t rpmfiFSize(rpmfi fi)
211 {
212     rpm_off_t fsize = 0;
213
214     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
215         if (fi->fsizes != NULL)
216             fsize = fi->fsizes[fi->i];
217     }
218     return fsize;
219 }
220
221 rpm_rdev_t rpmfiFRdev(rpmfi fi)
222 {
223     rpm_rdev_t frdev = 0;
224
225     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
226         if (fi->frdevs != NULL)
227             frdev = fi->frdevs[fi->i];
228     }
229     return frdev;
230 }
231
232 rpm_ino_t rpmfiFInode(rpmfi fi)
233 {
234     rpm_ino_t finode = 0;
235
236     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
237         if (fi->finodes != NULL)
238             finode = fi->finodes[fi->i];
239     }
240     return finode;
241 }
242
243 rpm_color_t rpmfiColor(rpmfi fi)
244 {
245     rpm_color_t color = 0;
246
247     if (fi != NULL)
248         /* XXX ignore all but lsnibble for now. */
249         color = fi->color & 0xf;
250     return color;
251 }
252
253 rpm_color_t rpmfiFColor(rpmfi fi)
254 {
255     rpm_color_t fcolor = 0;
256
257     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
258         if (fi->fcolors != NULL)
259             /* XXX ignore all but lsnibble for now. */
260             fcolor = (fi->fcolors[fi->i] & 0x0f);
261     }
262     return fcolor;
263 }
264
265 const char * rpmfiFClass(rpmfi fi)
266 {
267     const char * fclass = NULL;
268     int cdictx;
269
270     if (fi != NULL && fi->fcdictx != NULL && fi->i >= 0 && fi->i < fi->fc) {
271         cdictx = fi->fcdictx[fi->i];
272         if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
273             fclass = fi->cdict[cdictx];
274     }
275     return fclass;
276 }
277
278 const char * rpmfiFContext(rpmfi fi)
279 {
280     const char * fcontext = NULL;
281
282     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
283         if (fi->fcontexts != NULL)
284             fcontext = fi->fcontexts[fi->i];
285     }
286     return fcontext;
287 }
288
289 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
290 {
291     int fddictx = -1;
292     int fddictn = 0;
293     const uint32_t * fddict = NULL;
294
295     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
296         if (fi->fddictn != NULL)
297             fddictn = fi->fddictn[fi->i];
298         if (fddictn > 0 && fi->fddictx != NULL)
299             fddictx = fi->fddictx[fi->i];
300         if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
301             fddict = fi->ddict + fddictx;
302     }
303     if (fddictp)
304         *fddictp = fddict;
305     return fddictn;
306 }
307
308 uint32_t rpmfiFNlink(rpmfi fi)
309 {
310     uint32_t nlink = 0;
311
312     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
313         /* XXX rpm-2.3.12 has not RPMTAG_FILEINODES */
314         if (fi->finodes && fi->frdevs) {
315             rpm_ino_t finode = fi->finodes[fi->i];
316             rpm_rdev_t frdev = fi->frdevs[fi->i];
317             int j;
318
319             for (j = 0; j < fi->fc; j++) {
320                 if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
321                     nlink++;
322             }
323         }
324     }
325     return nlink;
326 }
327
328 rpm_time_t rpmfiFMtime(rpmfi fi)
329 {
330     rpm_time_t fmtime = 0;
331
332     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
333         if (fi->fmtimes != NULL)
334             fmtime = fi->fmtimes[fi->i];
335     }
336     return fmtime;
337 }
338
339 const char * rpmfiFUser(rpmfi fi)
340 {
341     const char * fuser = NULL;
342
343     /* XXX add support for ancient RPMTAG_FILEUIDS? */
344     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
345         if (fi->fuser != NULL)
346             fuser = fi->fuser[fi->i];
347     }
348     return fuser;
349 }
350
351 const char * rpmfiFGroup(rpmfi fi)
352 {
353     const char * fgroup = NULL;
354
355     /* XXX add support for ancient RPMTAG_FILEGIDS? */
356     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
357         if (fi->fgroup != NULL)
358             fgroup = fi->fgroup[fi->i];
359     }
360     return fgroup;
361 }
362
363 int rpmfiNext(rpmfi fi)
364 {
365     int i = -1;
366
367     if (fi != NULL && ++fi->i >= 0) {
368         if (fi->i < fi->fc) {
369             i = fi->i;
370             if (fi->dil != NULL)
371                 fi->j = fi->dil[fi->i];
372         } else
373             fi->i = -1;
374
375 if (_rpmfi_debug  < 0 && i != -1)
376 fprintf(stderr, "*** fi %p\t%s[%d] %s%s\n", fi, (fi->Type ? fi->Type : "?Type?"), i, (i >= 0 ? fi->dnl[fi->j] : ""), (i >= 0 ? fi->bnl[fi->i] : ""));
377
378     }
379
380     return i;
381 }
382
383 rpmfi rpmfiInit(rpmfi fi, int fx)
384 {
385     if (fi != NULL) {
386         if (fx >= 0 && fx < fi->fc) {
387             fi->i = fx - 1;
388             fi->j = -1;
389         }
390     }
391
392     return fi;
393 }
394
395 int rpmfiNextD(rpmfi fi)
396 {
397     int j = -1;
398
399     if (fi != NULL && ++fi->j >= 0) {
400         if (fi->j < fi->dc)
401             j = fi->j;
402         else
403             fi->j = -1;
404
405 if (_rpmfi_debug  < 0 && j != -1)
406 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, (fi->Type ? fi->Type : "?Type?"), j);
407
408     }
409
410     return j;
411 }
412
413 rpmfi rpmfiInitD(rpmfi fi, int dx)
414 {
415     if (fi != NULL) {
416         if (dx >= 0 && dx < fi->fc)
417             fi->j = dx - 1;
418         else
419             fi = NULL;
420     }
421
422     return fi;
423 }
424
425 /**
426  * Identify a file type.
427  * @param ft            file type
428  * @return              string to identify a file type
429  */
430 static
431 const char * ftstring (rpmFileTypes ft)
432 {
433     switch (ft) {
434     case XDIR:  return "directory";
435     case CDEV:  return "char dev";
436     case BDEV:  return "block dev";
437     case LINK:  return "link";
438     case SOCK:  return "sock";
439     case PIPE:  return "fifo/pipe";
440     case REG:   return "file";
441     default:    return "unknown file type";
442     }
443 }
444
445 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
446 {
447     if (S_ISDIR(mode))  return XDIR;
448     if (S_ISCHR(mode))  return CDEV;
449     if (S_ISBLK(mode))  return BDEV;
450     if (S_ISLNK(mode))  return LINK;
451     if (S_ISSOCK(mode)) return SOCK;
452     if (S_ISFIFO(mode)) return PIPE;
453     return REG;
454 }
455
456 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
457 {
458     rpmFileTypes awhat = rpmfiWhatis(rpmfiFMode(afi));
459     rpmFileTypes bwhat = rpmfiWhatis(rpmfiFMode(bfi));
460
461     if ((rpmfiFFlags(afi) & RPMFILE_GHOST) ||
462         (rpmfiFFlags(bfi) & RPMFILE_GHOST)) return 0;
463
464     if (awhat != bwhat) return 1;
465
466     if (awhat == LINK) {
467         const char * alink = rpmfiFLink(afi);
468         const char * blink = rpmfiFLink(bfi);
469         if (alink == blink) return 0;
470         if (alink == NULL) return 1;
471         if (blink == NULL) return -1;
472         return strcmp(alink, blink);
473     } else if (awhat == REG) {
474         size_t adiglen, bdiglen;
475         pgpHashAlgo aalgo, balgo;
476         const unsigned char * adigest = rpmfiFDigest(afi, &aalgo, &adiglen);
477         const unsigned char * bdigest = rpmfiFDigest(bfi, &balgo, &bdiglen);
478         if (adigest == bdigest) return 0;
479         if (adigest == NULL) return 1;
480         if (bdigest == NULL) return -1;
481         /* can't meaningfully compare different hash types */
482         if (aalgo != balgo || adiglen != bdiglen) return -1;
483         return memcmp(adigest, bdigest, adiglen);
484     }
485
486     return 0;
487 }
488
489 rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
490 {
491     const char * fn = rpmfiFN(nfi);
492     rpmfileAttrs newFlags = rpmfiFFlags(nfi);
493     char buffer[1024];
494     rpmFileTypes dbWhat, newWhat, diskWhat;
495     struct stat sb;
496     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
497
498     if (lstat(fn, &sb)) {
499         /*
500          * The file doesn't exist on the disk. Create it unless the new
501          * package has marked it as missingok, or allfiles is requested.
502          */
503         if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
504             rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
505                         fn);
506             return FA_SKIP;
507         } else {
508             return FA_CREATE;
509         }
510     }
511
512     diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
513     dbWhat = rpmfiWhatis(rpmfiFMode(ofi));
514     newWhat = rpmfiWhatis(rpmfiFMode(nfi));
515
516     /*
517      * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
518      * them in older packages as well.
519      */
520     if (newWhat == XDIR)
521         return FA_CREATE;
522
523     if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK)
524         return save;
525     else if (newWhat != dbWhat && diskWhat != dbWhat)
526         return save;
527     else if (dbWhat != newWhat)
528         return FA_CREATE;
529     else if (dbWhat != LINK && dbWhat != REG)
530         return FA_CREATE;
531
532     /*
533      * This order matters - we'd prefer to CREATE the file if at all
534      * possible in case something else (like the timestamp) has changed.
535      */
536     memset(buffer, 0, sizeof(buffer));
537     if (dbWhat == REG) {
538         pgpHashAlgo oalgo, nalgo;
539         size_t odiglen, ndiglen;
540         const unsigned char * odigest, * ndigest;
541         odigest = rpmfiFDigest(ofi, &oalgo, &odiglen);
542         if (diskWhat == REG) {
543             if (rpmDoDigest(oalgo, fn, 0, 
544                 (unsigned char *)buffer, NULL))
545                 return FA_CREATE;       /* assume file has been removed */
546             if (odigest && !memcmp(odigest, buffer, odiglen))
547                 return FA_CREATE;       /* unmodified config file, replace. */
548         }
549         ndigest = rpmfiFDigest(nfi, &nalgo, &ndiglen);
550         /* XXX can't compare different hash types, what should we do here? */
551         if (oalgo != nalgo || odiglen != ndiglen)
552             return FA_CREATE;
553         if (odigest && ndigest && !memcmp(odigest, ndigest, odiglen))
554             return FA_SKIP;     /* identical file, don't bother. */
555     } else /* dbWhat == LINK */ {
556         const char * oFLink, * nFLink;
557         oFLink = rpmfiFLink(ofi);
558         if (diskWhat == LINK) {
559         if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
560             return FA_CREATE;   /* assume file has been removed */
561         if (oFLink && !strcmp(oFLink, buffer))
562             return FA_CREATE;   /* unmodified config file, replace. */
563         }
564         nFLink = rpmfiFLink(nfi);
565         if (oFLink && nFLink && !strcmp(oFLink, nFLink))
566             return FA_SKIP;     /* identical file, don't bother. */
567     }
568
569     /*
570      * The config file on the disk has been modified, but
571      * the ones in the two packages are different. It would
572      * be nice if RPM was smart enough to at least try and
573      * merge the difference ala CVS, but...
574      */
575     return save;
576 }
577
578 int rpmfiConfigConflict(const rpmfi fi)
579 {
580     const char * fn = rpmfiFN(fi);
581     rpmfileAttrs flags = rpmfiFFlags(fi);
582     char buffer[1024];
583     rpmFileTypes newWhat, diskWhat;
584     struct stat sb;
585
586     if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) {
587         return 0;
588     }
589
590     diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
591     newWhat = rpmfiWhatis(rpmfiFMode(fi));
592
593     if (newWhat != LINK && newWhat != REG)
594         return 1;
595
596     if (diskWhat != newWhat)
597         return 1;
598     
599     memset(buffer, 0, sizeof(buffer));
600     if (newWhat == REG) {
601         pgpHashAlgo algo;
602         size_t diglen;
603         const unsigned char *ndigest = rpmfiFDigest(fi, &algo, &diglen);
604         if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL))
605             return 0;   /* assume file has been removed */
606         if (ndigest && !memcmp(ndigest, buffer, diglen))
607             return 0;   /* unmodified config file */
608     } else /* newWhat == LINK */ {
609         const char * nFLink;
610         if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
611             return 0;   /* assume file has been removed */
612         nFLink = rpmfiFLink(fi);
613         if (nFLink && !strcmp(nFLink, buffer))
614             return 0;   /* unmodified config file */
615     }
616
617     return 1;
618 }
619
620 const char * rpmfiTypeString(rpmfi fi)
621 {
622     switch(rpmteType(fi->te)) {
623     case TR_ADDED:      return " install";
624     case TR_REMOVED:    return "   erase";
625     default:            return "???";
626     }
627 }
628
629 static char **duparray(char ** src, int size)
630 {
631     char **dest = xmalloc((size+1) * sizeof(*dest));
632     for (int i = 0; i < size; i++) {
633         dest[i] = xstrdup(src[i]);
634     }
635     headerFreeData(src, RPM_STRING_ARRAY_TYPE);
636     return dest;
637 }
638
639 static void * freearray(char **array, int size)
640 {
641     for (int i = 0; i < size; i++) {
642         free(array[i]);
643     }
644     free(array);
645     return NULL;
646 }
647
648 /**
649  * Relocate files in header.
650  * @todo multilib file dispositions need to be checked.
651  * @param ts            transaction set
652  * @param fi            transaction element file info
653  * @param origH         package header
654  * @param actions       file dispositions
655  * @return              header with relocated files
656  */
657 static
658 Header relocateFileList(const rpmts ts, rpmfi fi,
659                 Header origH, rpmFileAction * actions)
660 {
661     rpmte p = rpmtsRelocateElement(ts);
662     HGE_t hge = fi->hge;
663     HAE_t hae = fi->hae;
664     HME_t hme = fi->hme;
665     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
666     static int _printed = 0;
667     int allowBadRelocate = (rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE);
668     rpmRelocation * relocations = NULL;
669     int numRelocations;
670     const char ** validRelocations;
671     rpmTagType validType;
672     char ** baseNames;
673     char ** dirNames;
674     uint32_t * dirIndexes;
675     uint32_t * newDirIndexes;
676     rpm_count_t fileCount, dirCount, numValid;
677     rpm_flag_t * fFlags = NULL;
678     rpm_color_t * fColors = NULL;
679     rpm_color_t * dColors = NULL;
680     rpm_mode_t * fModes = NULL;
681     Header h;
682     int nrelocated = 0;
683     int fileAlloced = 0;
684     char * fn = NULL;
685     int haveRelocatedBase = 0;
686     int haveRelocatedFile = 0;
687     int reldel = 0;
688     int len;
689     int i, j, xx;
690
691     if (!hge(origH, RPMTAG_PREFIXES, &validType,
692                         (rpm_data_t *) &validRelocations, &numValid))
693         numValid = 0;
694
695 assert(p != NULL);
696     numRelocations = 0;
697     if (p->relocs)
698         while (p->relocs[numRelocations].newPath ||
699                p->relocs[numRelocations].oldPath)
700             numRelocations++;
701
702     /*
703      * If no relocations are specified (usually the case), then return the
704      * original header. If there are prefixes, however, then INSTPREFIXES
705      * should be added, but, since relocateFileList() can be called more
706      * than once for the same header, don't bother if already present.
707      */
708     if (p->relocs == NULL || numRelocations == 0) {
709         if (numValid) {
710             if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
711                 xx = hae(origH, RPMTAG_INSTPREFIXES,
712                         validType, validRelocations, numValid);
713             validRelocations = hfd(validRelocations, validType);
714         }
715         /* XXX FIXME multilib file actions need to be checked. */
716         return headerLink(origH);
717     }
718
719     h = headerLink(origH);
720
721     relocations = xmalloc(sizeof(*relocations) * numRelocations);
722
723     /* Build sorted relocation list from raw relocations. */
724     for (i = 0; i < numRelocations; i++) {
725         char * t;
726
727         /*
728          * Default relocations (oldPath == NULL) are handled in the UI,
729          * not rpmlib.
730          */
731         if (p->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
732
733         /* FIXME: Trailing /'s will confuse us greatly. Internal ones will 
734            too, but those are more trouble to fix up. :-( */
735         t = xstrdup(p->relocs[i].oldPath);
736         relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
737             ? t
738             : stripTrailingChar(t, '/');
739
740         /* An old path w/o a new path is valid, and indicates exclusion */
741         if (p->relocs[i].newPath) {
742             int del;
743
744             t = xstrdup(p->relocs[i].newPath);
745             relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
746                 ? t
747                 : stripTrailingChar(t, '/');
748
749                 /* FIX:  relocations[i].oldPath == NULL */
750             /* Verify that the relocation's old path is in the header. */
751             for (j = 0; j < numValid; j++) {
752                 if (!strcmp(validRelocations[j], relocations[i].oldPath))
753                     break;
754             }
755
756             /* XXX actions check prevents problem from being appended twice. */
757             if (j == numValid && !allowBadRelocate && actions) {
758                 rpmps ps = rpmtsProblems(ts);
759                 rpmpsAppend(ps, RPMPROB_BADRELOCATE,
760                         rpmteNEVRA(p), rpmteKey(p),
761                         relocations[i].oldPath, NULL, NULL, 0);
762                 ps = rpmpsFree(ps);
763             }
764             del =
765                 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
766
767             if (del > reldel)
768                 reldel = del;
769         } else {
770             relocations[i].newPath = NULL;
771         }
772     }
773
774     /* stupid bubble sort, but it's probably faster here */
775     for (i = 0; i < numRelocations; i++) {
776         int madeSwap;
777         madeSwap = 0;
778         for (j = 1; j < numRelocations; j++) {
779             rpmRelocation tmpReloc;
780             if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
781                 relocations[j    ].oldPath == NULL || /* XXX can't happen */
782         strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
783                 continue;
784             /* LCL: ??? */
785             tmpReloc = relocations[j - 1];
786             relocations[j - 1] = relocations[j];
787             relocations[j] = tmpReloc;
788             madeSwap = 1;
789         }
790         if (!madeSwap) break;
791     }
792
793     if (!_printed) {
794         _printed = 1;
795         rpmlog(RPMLOG_DEBUG, "========== relocations\n");
796         for (i = 0; i < numRelocations; i++) {
797             if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
798             if (relocations[i].newPath == NULL)
799                 rpmlog(RPMLOG_DEBUG, "%5d exclude  %s\n",
800                         i, relocations[i].oldPath);
801             else
802                 rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
803                         i, relocations[i].oldPath, relocations[i].newPath);
804         }
805     }
806
807     /* Add relocation values to the header */
808     if (numValid) {
809         const char ** actualRelocations;
810         rpm_count_t numActual;
811
812         actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
813         numActual = 0;
814         for (i = 0; i < numValid; i++) {
815             for (j = 0; j < numRelocations; j++) {
816                 if (relocations[j].oldPath == NULL || /* XXX can't happen */
817                     strcmp(validRelocations[i], relocations[j].oldPath))
818                     continue;
819                 /* On install, a relocate to NULL means skip the path. */
820                 if (relocations[j].newPath) {
821                     actualRelocations[numActual] = relocations[j].newPath;
822                     numActual++;
823                 }
824                 break;
825             }
826             if (j == numRelocations) {
827                 actualRelocations[numActual] = validRelocations[i];
828                 numActual++;
829             }
830         }
831
832         if (numActual)
833             xx = hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
834                        (rpm_data_t *) actualRelocations, numActual);
835
836         actualRelocations = _free(actualRelocations);
837         validRelocations = hfd(validRelocations, validType);
838     }
839
840     xx = hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &baseNames, &fileCount);
841     xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &dirIndexes, NULL);
842     xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &dirNames, &dirCount);
843     xx = hge(h, RPMTAG_FILEFLAGS, NULL, (rpm_data_t *) &fFlags, NULL);
844     xx = hge(h, RPMTAG_FILECOLORS, NULL, (rpm_data_t *) &fColors, NULL);
845     xx = hge(h, RPMTAG_FILEMODES, NULL, (rpm_data_t *) &fModes, NULL);
846
847     dColors = xcalloc(dirCount, sizeof(*dColors));
848
849     newDirIndexes = xmalloc(sizeof(*newDirIndexes) * fileCount);
850     memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
851     dirIndexes = newDirIndexes;
852
853     /*
854      * For all relocations, we go through sorted file/relocation lists 
855      * backwards so that /usr/local relocations take precedence over /usr 
856      * ones.
857      */
858
859     /* Relocate individual paths. */
860
861     for (i = fileCount - 1; i >= 0; i--) {
862         rpmFileTypes ft;
863         int fnlen;
864
865         len = reldel +
866                 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
867         if (len >= fileAlloced) {
868             fileAlloced = len * 2;
869             fn = xrealloc(fn, fileAlloced);
870         }
871
872 assert(fn != NULL);             /* XXX can't happen */
873         *fn = '\0';
874         fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
875
876 if (fColors != NULL) {
877 /* XXX pkgs may not have unique dirNames, so color all dirNames that match. */
878 for (j = 0; j < dirCount; j++) {
879 if (strcmp(dirNames[dirIndexes[i]], dirNames[j])) continue;
880 dColors[j] |= fColors[i];
881 }
882 }
883
884         /*
885          * See if this file path needs relocating.
886          */
887         /*
888          * XXX FIXME: Would a bsearch of the (already sorted) 
889          * relocation list be a good idea?
890          */
891         for (j = numRelocations - 1; j >= 0; j--) {
892             if (relocations[j].oldPath == NULL) /* XXX can't happen */
893                 continue;
894             len = strcmp(relocations[j].oldPath, "/")
895                 ? strlen(relocations[j].oldPath)
896                 : 0;
897
898             if (fnlen < len)
899                 continue;
900             /*
901              * Only subdirectories or complete file paths may be relocated. We
902              * don't check for '\0' as our directory names all end in '/'.
903              */
904             if (!(fn[len] == '/' || fnlen == len))
905                 continue;
906
907             if (strncmp(relocations[j].oldPath, fn, len))
908                 continue;
909             break;
910         }
911         if (j < 0) continue;
912
913 /* FIX: fModes may be NULL */
914         ft = rpmfiWhatis(fModes[i]);
915
916         /* On install, a relocate to NULL means skip the path. */
917         if (relocations[j].newPath == NULL) {
918             if (ft == XDIR) {
919                 /* Start with the parent, looking for directory to exclude. */
920                 for (j = dirIndexes[i]; j < dirCount; j++) {
921                     len = strlen(dirNames[j]) - 1;
922                     while (len > 0 && dirNames[j][len-1] == '/') len--;
923                     if (fnlen != len)
924                         continue;
925                     if (strncmp(fn, dirNames[j], fnlen))
926                         continue;
927                     break;
928                 }
929             }
930             if (actions) {
931                 actions[i] = FA_SKIPNSTATE;
932                 rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
933                         ftstring(ft), fn);
934             }
935             continue;
936         }
937
938         /* Relocation on full paths only, please. */
939         if (fnlen != len) continue;
940
941         if (actions)
942             rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
943                     fn, relocations[j].newPath);
944         nrelocated++;
945
946         strcpy(fn, relocations[j].newPath);
947         {   char * te = strrchr(fn, '/');
948             if (te) {
949                 if (te > fn) te++;      /* root is special */
950                 fnlen = te - fn;
951             } else
952                 te = fn + strlen(fn);
953             if (strcmp(baseNames[i], te)) { /* basename changed too? */
954                 if (!haveRelocatedBase) {
955                     baseNames = duparray(baseNames, fileCount);
956                     haveRelocatedBase = 1;
957                 }
958                 free(baseNames[i]);
959                 baseNames[i] = xstrdup(te);
960             }
961             *te = '\0';                 /* terminate new directory name */
962         }
963
964         /* Does this directory already exist in the directory list? */
965         for (j = 0; j < dirCount; j++) {
966             if (fnlen != strlen(dirNames[j]))
967                 continue;
968             if (strncmp(fn, dirNames[j], fnlen))
969                 continue;
970             break;
971         }
972         
973         if (j < dirCount) {
974             dirIndexes[i] = j;
975             continue;
976         }
977
978         /* Creating new paths is a pita */
979         if (!haveRelocatedFile) {
980             dirNames = duparray(dirNames, dirCount);
981             haveRelocatedFile = 1;
982         } else {
983             dirNames = xrealloc(dirNames, 
984                                sizeof(*dirNames) * (dirCount + 1));
985         }
986
987         dirNames[dirCount] = xstrdup(fn);
988         dirIndexes[i] = dirCount;
989         dirCount++;
990     }
991
992     /* Finish off by relocating directories. */
993     for (i = dirCount - 1; i >= 0; i--) {
994         for (j = numRelocations - 1; j >= 0; j--) {
995
996             if (relocations[j].oldPath == NULL) /* XXX can't happen */
997                 continue;
998             len = strcmp(relocations[j].oldPath, "/")
999                 ? strlen(relocations[j].oldPath)
1000                 : 0;
1001
1002             if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
1003                 continue;
1004
1005             /*
1006              * Only subdirectories or complete file paths may be relocated. We
1007              * don't check for '\0' as our directory names all end in '/'.
1008              */
1009             if (dirNames[i][len] != '/')
1010                 continue;
1011
1012             if (relocations[j].newPath) { /* Relocate the path */
1013                 char *t = NULL;
1014                 rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
1015                 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
1016                 (void) rpmCleanPath(t);
1017                 rstrcat(&t, "/");
1018
1019                 if (actions)
1020                     rpmlog(RPMLOG_DEBUG,
1021                         "relocating directory %s to %s\n", dirNames[i], t);
1022                 dirNames[i] = t;
1023                 nrelocated++;
1024             }
1025         }
1026     }
1027
1028     /* Save original filenames in header and replace (relocated) filenames. */
1029     if (nrelocated) {
1030         rpm_count_t c;
1031         void * d;
1032         rpmTagType t;
1033
1034         d = NULL;
1035         xx = hge(h, RPMTAG_BASENAMES, &t, &d, &c);
1036         xx = hae(h, RPMTAG_ORIGBASENAMES, t, d, c);
1037         d = hfd(d, t);
1038
1039         d = NULL;
1040         xx = hge(h, RPMTAG_DIRNAMES, &t, &d, &c);
1041         xx = hae(h, RPMTAG_ORIGDIRNAMES, t, d, c);
1042         d = hfd(d, t);
1043
1044         d = NULL;
1045         xx = hge(h, RPMTAG_DIRINDEXES, &t, &d, &c);
1046         xx = hae(h, RPMTAG_ORIGDIRINDEXES, t, d, c);
1047         d = hfd(d, t);
1048
1049         xx = hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
1050                           baseNames, fileCount);
1051         if (haveRelocatedBase) {
1052             baseNames = freearray(baseNames, fileCount);
1053         }
1054         fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
1055         xx = hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &fi->bnl, &fi->fc);
1056
1057         xx = hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
1058                           dirNames, dirCount);
1059         dirNames = freearray(dirNames, dirCount);
1060
1061         fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
1062         xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &fi->dnl, &fi->dc);
1063
1064         xx = hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
1065                           dirIndexes, fileCount);
1066         xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &fi->dil, NULL);
1067     }
1068
1069     /* If we did relocations, baseNames and dirNames might be NULL by now */
1070     baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
1071     dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
1072     free(fn);
1073     for (i = 0; i < numRelocations; i++) {
1074         free(relocations[i].oldPath);
1075         free(relocations[i].newPath);
1076     }
1077     free(relocations);
1078     free(newDirIndexes);
1079     free(dColors);
1080
1081     return h;
1082 }
1083
1084 rpmfi rpmfiFree(rpmfi fi)
1085 {
1086     HFD_t hfd = headerFreeData;
1087
1088     if (fi == NULL) return NULL;
1089
1090     if (fi->nrefs > 1)
1091         return rpmfiUnlink(fi, fi->Type);
1092
1093 if (_rpmfi_debug < 0)
1094 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
1095
1096     /* Free pre- and post-transaction script and interpreter strings. */
1097     fi->pretrans = _free(fi->pretrans);
1098     fi->pretransprog = _free(fi->pretransprog);
1099     fi->posttrans = _free(fi->posttrans);
1100     fi->posttransprog = _free(fi->posttransprog);
1101
1102     if (fi->fc > 0) {
1103         fi->bnl = hfd(fi->bnl, RPM_FORCEFREE_TYPE);
1104         fi->dnl = hfd(fi->dnl, RPM_FORCEFREE_TYPE);
1105
1106         fi->flinks = hfd(fi->flinks, RPM_FORCEFREE_TYPE);
1107         fi->flangs = hfd(fi->flangs, RPM_FORCEFREE_TYPE);
1108         fi->digests = _free(fi->digests);
1109
1110         fi->cdict = hfd(fi->cdict, RPM_FORCEFREE_TYPE);
1111
1112         fi->fuser = hfd(fi->fuser, RPM_FORCEFREE_TYPE);
1113         fi->fgroup = hfd(fi->fgroup, RPM_FORCEFREE_TYPE);
1114
1115         fi->fstates = _free(fi->fstates);
1116
1117         if (!fi->keep_header && fi->h == NULL) {
1118             fi->fmtimes = _constfree(fi->fmtimes);
1119             fi->fmodes = _free(fi->fmodes);
1120             fi->fflags = _constfree(fi->fflags);
1121             fi->vflags = _constfree(fi->vflags);
1122             fi->fsizes = _constfree(fi->fsizes);
1123             fi->frdevs = _constfree(fi->frdevs);
1124             fi->finodes = _constfree(fi->finodes);
1125             fi->dil = _free(fi->dil);
1126
1127             fi->fcolors = _constfree(fi->fcolors);
1128             fi->fcdictx = _constfree(fi->fcdictx);
1129             fi->ddict = _constfree(fi->ddict);
1130             fi->fddictx = _constfree(fi->fddictx);
1131             fi->fddictn = _constfree(fi->fddictn);
1132
1133         }
1134     }
1135
1136     fi->fsm = freeFSM(fi->fsm);
1137
1138     fi->fn = _free(fi->fn);
1139     fi->apath = _free(fi->apath);
1140     fi->fmapflags = _free(fi->fmapflags);
1141
1142     fi->obnl = hfd(fi->obnl, RPM_FORCEFREE_TYPE);
1143     fi->odnl = hfd(fi->odnl, RPM_FORCEFREE_TYPE);
1144
1145     fi->fcontexts = hfd(fi->fcontexts, RPM_FORCEFREE_TYPE);
1146
1147     fi->actions = _free(fi->actions);
1148     fi->replacedSizes = _free(fi->replacedSizes);
1149     fi->replaced = _free(fi->replaced);
1150
1151     fi->h = headerFree(fi->h);
1152
1153     (void) rpmfiUnlink(fi, fi->Type);
1154     memset(fi, 0, sizeof(*fi));         /* XXX trash and burn */
1155     fi = _free(fi);
1156
1157     return NULL;
1158 }
1159
1160 #define _fdupe(_fi, _data)      \
1161     if ((_fi)->_data != NULL)   \
1162         (_fi)->_data = memcpy(xmalloc((_fi)->fc * sizeof(*(_fi)->_data)), \
1163                         (_fi)->_data, (_fi)->fc * sizeof(*(_fi)->_data))
1164
1165 /* XXX Ick, not SEF. */
1166 #define _fdupestring(_h, _tag, _data) \
1167     if (hge((_h), (_tag), NULL, (rpm_data_t *) &(_data), NULL)) \
1168         _data = xstrdup(_data)
1169
1170 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, int scareMem)
1171 {
1172     HGE_t hge =
1173         (scareMem ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry);
1174     HFD_t hfd = headerFreeData;
1175     rpmte p;
1176     rpmfi fi = NULL;
1177     const char * Type;
1178     uint32_t * uip;
1179     int dnlmax, bnlmax;
1180     unsigned char * t;
1181     struct rpmtd_s fdigests;
1182     int len;
1183     int xx;
1184     int i;
1185
1186     if (tagN == RPMTAG_BASENAMES) {
1187         Type = "Files";
1188     } else {
1189         Type = "?Type?";
1190         goto exit;
1191     }
1192
1193     fi = xcalloc(1, sizeof(*fi));
1194     if (fi == NULL)     /* XXX can't happen */
1195         goto exit;
1196
1197     fi->magic = RPMFIMAGIC;
1198     fi->Type = Type;
1199     fi->i = -1;
1200     fi->tagN = tagN;
1201
1202     fi->hge = hge;
1203     fi->hae = (HAE_t) headerAddEntry;
1204     fi->hme = (HME_t) headerModifyEntry;
1205     fi->hre = (HRE_t) headerRemoveEntry;
1206     fi->hfd = headerFreeData;
1207
1208     fi->h = (scareMem ? headerLink(h) : NULL);
1209
1210     if (fi->fsm == NULL)
1211         fi->fsm = newFSM();
1212
1213     /* 0 means unknown */
1214     xx = hge(h, RPMTAG_ARCHIVESIZE, NULL, (rpm_data_t *) &uip, NULL);
1215     fi->archivePos = 0;
1216     fi->archiveSize = (xx ? *uip : 0);
1217
1218     /* Extract pre- and post-transaction script and interpreter strings. */
1219     _fdupestring(h, RPMTAG_PRETRANS, fi->pretrans);
1220     _fdupestring(h, RPMTAG_PRETRANSPROG, fi->pretransprog);
1221     _fdupestring(h, RPMTAG_POSTTRANS, fi->posttrans);
1222     _fdupestring(h, RPMTAG_POSTTRANSPROG, fi->posttransprog);
1223
1224     if (!hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &fi->bnl, &fi->fc)) {
1225         fi->fc = 0;
1226         fi->dc = 0;
1227         goto exit;
1228     }
1229     xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &fi->dnl, &fi->dc);
1230     xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &fi->dil, NULL);
1231     xx = hge(h, RPMTAG_FILEMODES, NULL, (rpm_data_t *) &fi->fmodes, NULL);
1232     xx = hge(h, RPMTAG_FILEFLAGS, NULL, (rpm_data_t *) &fi->fflags, NULL);
1233     xx = hge(h, RPMTAG_FILEVERIFYFLAGS, NULL, (rpm_data_t *) &fi->vflags, NULL);
1234     xx = hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &fi->fsizes, NULL);
1235
1236     xx = hge(h, RPMTAG_FILECOLORS, NULL, (rpm_data_t *) &fi->fcolors, NULL);
1237     fi->color = 0;
1238     if (fi->fcolors != NULL)
1239     for (i = 0; i < fi->fc; i++)
1240         fi->color |= fi->fcolors[i];
1241     xx = hge(h, RPMTAG_CLASSDICT, NULL, (rpm_data_t *) &fi->cdict, &fi->ncdict);
1242     xx = hge(h, RPMTAG_FILECLASS, NULL, (rpm_data_t *) &fi->fcdictx, NULL);
1243
1244     xx = hge(h, RPMTAG_DEPENDSDICT, NULL, (rpm_data_t *) &fi->ddict, &fi->nddict);
1245     xx = hge(h, RPMTAG_FILEDEPENDSX, NULL, (rpm_data_t *) &fi->fddictx, NULL);
1246     xx = hge(h, RPMTAG_FILEDEPENDSN, NULL, (rpm_data_t *) &fi->fddictn, NULL);
1247
1248     xx = hge(h, RPMTAG_FILESTATES, NULL, (rpm_data_t *) &fi->fstates, NULL);
1249     if (xx == 0 || fi->fstates == NULL)
1250         fi->fstates = xcalloc(fi->fc, sizeof(*fi->fstates));
1251     else
1252         _fdupe(fi, fstates);
1253
1254     fi->action = FA_UNKNOWN;
1255     fi->flags = 0;
1256
1257 if (fi->actions == NULL)
1258         fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1259
1260     fi->keep_header = (scareMem ? 1 : 0);
1261
1262     /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1263     fi->mapflags =
1264                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1265
1266     xx = hge(h, RPMTAG_FILELINKTOS, NULL, (rpm_data_t *) &fi->flinks, NULL);
1267     xx = hge(h, RPMTAG_FILELANGS, NULL, (rpm_data_t *) &fi->flangs, NULL);
1268
1269     /* digest algorithm hardwired to MD5 for now */
1270     fi->digestalgo = PGPHASHALGO_MD5;
1271     fi->digests = NULL;
1272     /* grab hex digests from header and store in binary format */
1273     if (headerGet(h, RPMTAG_FILEMD5S, &fdigests, HEADERGET_MINMEM)) {
1274         const char *fdigest;
1275         size_t diglen = rpmDigestLength(fi->digestalgo);
1276         fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
1277
1278         while ((fdigest = rpmtdNextString(&fdigests))) {
1279             if (!(fdigest && *fdigest != '\0')) {
1280                 memset(t, 0, diglen);
1281                 t += diglen;
1282                 continue;
1283             }
1284             for (int j = 0; j < diglen; j++, t++, fdigest += 2)
1285                 *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
1286         }
1287         rpmtdFreeData(&fdigests);
1288     }
1289
1290     /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes, or fcontexts */
1291     xx = hge(h, RPMTAG_FILEMTIMES, NULL, (rpm_data_t *) &fi->fmtimes, NULL);
1292     xx = hge(h, RPMTAG_FILERDEVS, NULL, (rpm_data_t *) &fi->frdevs, NULL);
1293     xx = hge(h, RPMTAG_FILEINODES, NULL, (rpm_data_t *) &fi->finodes, NULL);
1294
1295     fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
1296
1297     xx = hge(h, RPMTAG_FILEUSERNAME, NULL, (rpm_data_t *) &fi->fuser, NULL);
1298     xx = hge(h, RPMTAG_FILEGROUPNAME, NULL, (rpm_data_t *) &fi->fgroup, NULL);
1299
1300     if (ts != NULL)
1301     if (fi != NULL)
1302     if ((p = rpmtsRelocateElement(ts)) != NULL && rpmteType(p) == TR_ADDED
1303      && !headerIsSource(h)
1304      && !headerIsEntry(h, RPMTAG_ORIGBASENAMES))
1305     {
1306         Header foo;
1307
1308 /* XXX DYING */
1309 if (fi->actions == NULL)
1310         fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1311         /* FIX: fi-digests undefined */
1312         foo = relocateFileList(ts, fi, h, fi->actions);
1313         fi->h = headerFree(fi->h);
1314         fi->h = headerLink(foo);
1315         foo = headerFree(foo);
1316     }
1317
1318     if (!scareMem) {
1319         _fdupe(fi, fmtimes);
1320         _fdupe(fi, frdevs);
1321         _fdupe(fi, finodes);
1322         _fdupe(fi, fsizes);
1323         _fdupe(fi, fflags);
1324         _fdupe(fi, vflags);
1325         _fdupe(fi, fmodes);
1326         _fdupe(fi, dil);
1327
1328         _fdupe(fi, fcolors);
1329         _fdupe(fi, fcdictx);
1330
1331         if (fi->ddict != NULL)
1332             fi->ddict = memcpy(xmalloc(fi->nddict * sizeof(*fi->ddict)),
1333                         fi->ddict, fi->nddict * sizeof(*fi->ddict));
1334
1335         _fdupe(fi, fddictx);
1336         _fdupe(fi, fddictn);
1337
1338         fi->h = headerFree(fi->h);
1339     }
1340
1341     dnlmax = -1;
1342     for (i = 0; i < fi->dc; i++) {
1343         if ((len = strlen(fi->dnl[i])) > dnlmax)
1344             dnlmax = len;
1345     }
1346     bnlmax = -1;
1347     for (i = 0; i < fi->fc; i++) {
1348         if ((len = strlen(fi->bnl[i])) > bnlmax)
1349             bnlmax = len;
1350     }
1351     fi->fnlen = dnlmax + bnlmax + 1;
1352     fi->fn = NULL;
1353
1354     fi->dperms = 0755;
1355     fi->fperms = 0644;
1356
1357 exit:
1358 if (_rpmfi_debug < 0)
1359 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, Type, (fi ? fi->fc : 0));
1360
1361     /* FIX: rpmfi null annotations */
1362     return rpmfiLink(fi, (fi ? fi->Type : NULL));
1363 }
1364
1365 void rpmfiBuildFNames(Header h, rpmTag tagN,
1366         const char *** fnp, rpm_count_t * fcp)
1367 {
1368     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
1369     HFD_t hfd = headerFreeData;
1370     const char ** baseNames;
1371     const char ** dirNames;
1372     uint32_t * dirIndexes;
1373     rpm_count_t count;
1374     const char ** fileNames;
1375     int size;
1376     rpmTag dirNameTag = 0;
1377     rpmTag dirIndexesTag = 0;
1378     rpmTagType bnt, dnt;
1379     char * t;
1380     int i, xx;
1381
1382     if (tagN == RPMTAG_BASENAMES) {
1383         dirNameTag = RPMTAG_DIRNAMES;
1384         dirIndexesTag = RPMTAG_DIRINDEXES;
1385     } else if (tagN == RPMTAG_ORIGBASENAMES) {
1386         dirNameTag = RPMTAG_ORIGDIRNAMES;
1387         dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
1388     }
1389
1390     if (!hge(h, tagN, &bnt, (rpm_data_t *) &baseNames, &count)) {
1391         if (fnp) *fnp = NULL;
1392         if (fcp) *fcp = 0;
1393         return;         /* no file list */
1394     }
1395
1396     xx = hge(h, dirNameTag, &dnt, (rpm_data_t *) &dirNames, NULL);
1397     xx = hge(h, dirIndexesTag, NULL, (rpm_data_t *) &dirIndexes, &count);
1398
1399     size = sizeof(*fileNames) * count;
1400     for (i = 0; i < count; i++)
1401         size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
1402
1403     fileNames = xmalloc(size);
1404     t = ((char *) fileNames) + (sizeof(*fileNames) * count);
1405     for (i = 0; i < count; i++) {
1406         fileNames[i] = t;
1407         t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
1408         *t++ = '\0';
1409     }
1410     baseNames = hfd(baseNames, bnt);
1411     dirNames = hfd(dirNames, dnt);
1412
1413     if (fnp)
1414         *fnp = fileNames;
1415     else
1416         fileNames = _free(fileNames);
1417     if (fcp) *fcp = count;
1418 }
1419