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