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