3 * Routines to handle file info tag sets.
8 #include <rpm/rpmlog.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>
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() */
25 rpmfi rpmfiUnlink(rpmfi fi, const char * msg)
27 if (fi == NULL) return NULL;
28 if (_rpmfi_debug && msg != NULL)
29 fprintf(stderr, "--> fi %p -- %d %s\n", fi, fi->nrefs, msg);
34 rpmfi rpmfiLink(rpmfi fi, const char * msg)
36 if (fi == NULL) return NULL;
38 if (_rpmfi_debug && msg != NULL)
39 fprintf(stderr, "--> fi %p ++ %d %s\n", fi, fi->nrefs, msg);
43 rpm_count_t rpmfiFC(rpmfi fi)
45 return (fi != NULL ? fi->fc : 0);
48 rpm_count_t rpmfiDC(rpmfi fi)
50 return (fi != NULL ? fi->dc : 0);
61 return (fi != NULL ? fi->i : -1);
64 int rpmfiSetFX(rpmfi fi, int fx)
68 if (fi != NULL && fx >= 0 && fx < fi->fc) {
71 fi->j = fi->dil[fi->i];
78 return (fi != NULL ? fi->j : -1);
81 int rpmfiSetDX(rpmfi fi, int dx)
85 if (fi != NULL && dx >= 0 && dx < fi->dc) {
92 const char * rpmfiBN(rpmfi fi)
94 const char * BN = NULL;
96 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
103 const char * rpmfiDN(rpmfi fi)
105 const char * DN = NULL;
107 if (fi != NULL && fi->j >= 0 && fi->j < fi->dc) {
114 const char * rpmfiFN(rpmfi fi)
116 const char * FN = "";
118 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
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)
126 for (int i = 0; i < fi->fc; i++) {
127 if ((len = strlen(fi->bnl[i])) > bnlmax)
130 fi->fn = xmalloc(dnlmax + bnlmax + 1);
134 t = stpcpy(t, fi->dnl[fi->dil[fi->i]]);
135 t = stpcpy(t, fi->bnl[fi->i]);
140 rpmfileAttrs rpmfiFFlags(rpmfi fi)
142 rpmfileAttrs FFlags = 0;
144 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
145 if (fi->fflags != NULL)
146 FFlags = fi->fflags[fi->i];
151 rpmVerifyAttrs rpmfiVFlags(rpmfi fi)
153 rpmVerifyAttrs VFlags = 0;
155 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
156 if (fi->vflags != NULL)
157 VFlags = fi->vflags[fi->i];
162 rpm_mode_t rpmfiFMode(rpmfi fi)
164 rpm_mode_t fmode = 0;
166 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
167 if (fi->fmodes != NULL)
168 fmode = fi->fmodes[fi->i];
173 rpmfileState rpmfiFState(rpmfi fi)
175 rpmfileState fstate = RPMFILE_STATE_MISSING;
177 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
178 if (fi->fstates != NULL)
179 fstate = fi->fstates[fi->i];
184 const unsigned char * rpmfiMD5(rpmfi fi)
186 const unsigned char *digest;
187 pgpHashAlgo algo = 0;
189 digest = rpmfiFDigest(fi, &algo, NULL);
190 return (algo == PGPHASHALGO_MD5) ? digest : NULL;
193 const unsigned char * rpmfiFDigest(rpmfi fi, pgpHashAlgo *algo, size_t *len)
195 const unsigned char *digest = NULL;
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);
204 *algo = fi->digestalgo;
209 char * rpmfiFDigestHex(rpmfi fi, pgpHashAlgo *algo)
212 char *fdigest = NULL;
213 const unsigned char *digest = rpmfiFDigest(fi, algo, &diglen);
215 fdigest = pgpHexStr(digest, diglen);
220 const char * rpmfiFLink(rpmfi fi)
222 const char * flink = NULL;
224 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
225 if (fi->flinks != NULL)
226 flink = fi->flinks[fi->i];
231 rpm_loff_t rpmfiFSize(rpmfi fi)
233 rpm_loff_t fsize = 0;
235 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
236 if (fi->fsizes != NULL)
237 fsize = fi->fsizes[fi->i];
242 rpm_rdev_t rpmfiFRdev(rpmfi fi)
244 rpm_rdev_t frdev = 0;
246 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
247 if (fi->frdevs != NULL)
248 frdev = fi->frdevs[fi->i];
253 rpm_ino_t rpmfiFInode(rpmfi fi)
255 rpm_ino_t finode = 0;
257 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
258 if (fi->finodes != NULL)
259 finode = fi->finodes[fi->i];
264 rpm_color_t rpmfiColor(rpmfi fi)
266 rpm_color_t color = 0;
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. */
277 rpm_color_t rpmfiFColor(rpmfi fi)
279 rpm_color_t fcolor = 0;
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);
289 const char * rpmfiFClass(rpmfi fi)
291 const char * fclass = NULL;
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];
302 const char * rpmfiFContext(rpmfi fi)
304 const char * fcontext = NULL;
306 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
307 if (fi->fcontexts != NULL)
308 fcontext = fi->fcontexts[fi->i];
313 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
317 const uint32_t * fddict = NULL;
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;
332 uint32_t rpmfiFNlink(rpmfi fi)
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];
343 for (j = 0; j < fi->fc; j++) {
344 if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
352 rpm_time_t rpmfiFMtime(rpmfi fi)
354 rpm_time_t fmtime = 0;
356 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
357 if (fi->fmtimes != NULL)
358 fmtime = fi->fmtimes[fi->i];
363 const char * rpmfiFUser(rpmfi fi)
365 const char * fuser = NULL;
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];
375 const char * rpmfiFGroup(rpmfi fi)
377 const char * fgroup = NULL;
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];
387 const char * rpmfiFCaps(rpmfi fi)
389 const char *fcaps = NULL;
390 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
391 fcaps = fi->fcaps ? fi->fcaps[fi->i] : "";
396 int rpmfiNext(rpmfi fi)
400 if (fi != NULL && ++fi->i >= 0) {
401 if (fi->i < fi->fc) {
404 fi->j = fi->dil[fi->i];
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] : ""));
416 rpmfi rpmfiInit(rpmfi fi, int fx)
419 if (fx >= 0 && fx < fi->fc) {
428 int rpmfiNextD(rpmfi fi)
432 if (fi != NULL && ++fi->j >= 0) {
438 if (_rpmfi_debug < 0 && j != -1)
439 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, (fi->Type ? fi->Type : "?Type?"), j);
446 rpmfi rpmfiInitD(rpmfi fi, int dx)
449 if (dx >= 0 && dx < fi->fc)
459 * Identify a file type.
460 * @param ft file type
461 * @return string to identify a file type
464 const char * ftstring (rpmFileTypes 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";
478 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
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;
489 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
491 rpmFileTypes awhat = rpmfiWhatis(rpmfiFMode(afi));
492 rpmFileTypes bwhat = rpmfiWhatis(rpmfiFMode(bfi));
494 if ((rpmfiFFlags(afi) & RPMFILE_GHOST) ||
495 (rpmfiFFlags(bfi) & RPMFILE_GHOST)) return 0;
497 if (awhat != bwhat) return 1;
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);
522 rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
524 const char * fn = rpmfiFN(nfi);
525 rpmfileAttrs newFlags = rpmfiFFlags(nfi);
527 rpmFileTypes dbWhat, newWhat, diskWhat;
529 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
531 if (lstat(fn, &sb)) {
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.
536 if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
537 rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
545 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
546 dbWhat = rpmfiWhatis(rpmfiFMode(ofi));
547 newWhat = rpmfiWhatis(rpmfiFMode(nfi));
550 * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
551 * them in older packages as well.
556 if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK)
558 else if (newWhat != dbWhat && diskWhat != dbWhat)
560 else if (dbWhat != newWhat)
562 else if (dbWhat != LINK && dbWhat != REG)
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.
569 memset(buffer, 0, sizeof(buffer));
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. */
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)
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. */
597 nFLink = rpmfiFLink(nfi);
598 if (oFLink && nFLink && !strcmp(oFLink, nFLink))
599 return FA_SKIP; /* identical file, don't bother. */
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...
611 int rpmfiConfigConflict(const rpmfi fi)
613 const char * fn = rpmfiFN(fi);
614 rpmfileAttrs flags = rpmfiFFlags(fi);
616 rpmFileTypes newWhat, diskWhat;
619 if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) {
623 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
624 newWhat = rpmfiWhatis(rpmfiFMode(fi));
626 if (newWhat != LINK && newWhat != REG)
629 if (diskWhat != newWhat)
632 memset(buffer, 0, sizeof(buffer));
633 if (newWhat == REG) {
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 */ {
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 */
653 const char * rpmfiTypeString(rpmfi fi)
655 switch(rpmteType(fi->te)) {
656 case TR_ADDED: return " install";
657 case TR_REMOVED: return " erase";
658 default: return "???";
662 static char **duparray(char ** src, int size)
664 char **dest = xmalloc((size+1) * sizeof(*dest));
665 for (int i = 0; i < size; i++) {
666 dest[i] = xstrdup(src[i]);
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
682 Header relocateFileList(const rpmts ts, rpmfi fi,
683 Header origH, rpmFileAction * actions)
685 rpmte p = rpmtsRelocateElement(ts);
686 static int _printed = 0;
687 int allowBadRelocate = (rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE);
688 rpmRelocation * relocations = NULL;
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;
702 int haveRelocatedBase = 0;
706 struct rpmtd_s validRelocs;
707 struct rpmtd_s bnames, dnames, dindexes, fcolors, fmodes;
710 if (headerGet(origH, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM))
711 numValid = rpmtdCount(&validRelocs);
716 while (p->relocs[numRelocations].newPath ||
717 p->relocs[numRelocations].oldPath)
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.
726 if (p->relocs == NULL || numRelocations == 0) {
728 if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES)) {
729 rpmtdSetTag(&validRelocs, RPMTAG_INSTPREFIXES);
730 headerPut(origH, &validRelocs, HEADERPUT_DEFAULT);
732 rpmtdFreeData(&validRelocs);
734 /* XXX FIXME multilib file actions need to be checked. */
735 return headerLink(origH);
738 h = headerLink(origH);
740 relocations = xmalloc(sizeof(*relocations) * numRelocations);
742 /* Build sorted relocation list from raw relocations. */
743 for (i = 0; i < numRelocations; i++) {
747 * Default relocations (oldPath == NULL) are handled in the UI,
750 if (p->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
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')
757 : stripTrailingChar(t, '/');
759 /* An old path w/o a new path is valid, and indicates exclusion */
760 if (p->relocs[i].newPath) {
763 const char *validprefix;
765 t = xstrdup(p->relocs[i].newPath);
766 relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
768 : stripTrailingChar(t, '/');
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) {
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);
789 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
794 relocations[i].newPath = NULL;
798 /* stupid bubble sort, but it's probably faster here */
799 for (i = 0; i < numRelocations; i++) {
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)
809 tmpReloc = relocations[j - 1];
810 relocations[j - 1] = relocations[j];
811 relocations[j] = tmpReloc;
814 if (!madeSwap) break;
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);
826 rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
827 i, relocations[i].oldPath, relocations[i].newPath);
831 /* Add relocation values to the header */
833 const char *validprefix;
834 const char ** actualRelocations;
835 rpm_count_t numActual;
837 actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
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))
845 /* On install, a relocate to NULL means skip the path. */
846 if (relocations[j].newPath) {
847 actualRelocations[numActual] = relocations[j].newPath;
852 if (j == numRelocations) {
853 actualRelocations[numActual] = validprefix;
859 headerPutStringArray(h, RPMTAG_INSTPREFIXES,
860 actualRelocations, numActual);
863 actualRelocations = _free(actualRelocations);
864 rpmtdFreeData(&validRelocs);
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;
883 dColors = xcalloc(dirCount, sizeof(*dColors));
885 newDirIndexes = xmalloc(sizeof(*newDirIndexes) * fileCount);
886 memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
887 dirIndexes = newDirIndexes;
890 * For all relocations, we go through sorted file/relocation lists
891 * backwards so that /usr/local relocations take precedence over /usr
895 /* Relocate individual paths. */
897 for (i = fileCount - 1; i >= 0; i--) {
902 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
903 if (len >= fileAlloced) {
904 fileAlloced = len * 2;
905 fn = xrealloc(fn, fileAlloced);
908 assert(fn != NULL); /* XXX can't happen */
910 fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
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];
921 * See if this file path needs relocating.
924 * XXX FIXME: Would a bsearch of the (already sorted)
925 * relocation list be a good idea?
927 for (j = numRelocations - 1; j >= 0; j--) {
928 if (relocations[j].oldPath == NULL) /* XXX can't happen */
930 len = strcmp(relocations[j].oldPath, "/")
931 ? strlen(relocations[j].oldPath)
937 * Only subdirectories or complete file paths may be relocated. We
938 * don't check for '\0' as our directory names all end in '/'.
940 if (!(fn[len] == '/' || fnlen == len))
943 if (strncmp(relocations[j].oldPath, fn, len))
949 /* FIX: fModes may be NULL */
950 ft = rpmfiWhatis(fModes[i]);
952 /* On install, a relocate to NULL means skip the path. */
953 if (relocations[j].newPath == NULL) {
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--;
961 if (strncmp(fn, dirNames[j], fnlen))
967 actions[i] = FA_SKIPNSTATE;
968 rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
974 /* Relocation on full paths only, please. */
975 if (fnlen != len) continue;
978 rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
979 fn, relocations[j].newPath);
982 strcpy(fn, relocations[j].newPath);
983 { char * te = strrchr(fn, '/');
985 if (te > fn) te++; /* root is special */
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;
997 baseNames[i] = xstrdup(te);
999 *te = '\0'; /* terminate new directory name */
1002 /* Does this directory already exist in the directory list? */
1003 for (j = 0; j < dirCount; j++) {
1004 if (fnlen != strlen(dirNames[j]))
1006 if (strncmp(fn, dirNames[j], fnlen))
1016 /* Creating new paths is a pita */
1017 dirNames = dnames.data = xrealloc(dnames.data,
1018 sizeof(*dirNames) * (dirCount + 1));
1020 dirNames[dirCount] = xstrdup(fn);
1021 dirIndexes[i] = dirCount;
1026 /* Finish off by relocating directories. */
1027 for (i = dirCount - 1; i >= 0; i--) {
1028 for (j = numRelocations - 1; j >= 0; j--) {
1030 if (relocations[j].oldPath == NULL) /* XXX can't happen */
1032 len = strcmp(relocations[j].oldPath, "/")
1033 ? strlen(relocations[j].oldPath)
1036 if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
1040 * Only subdirectories or complete file paths may be relocated. We
1041 * don't check for '\0' as our directory names all end in '/'.
1043 if (dirNames[i][len] != '/')
1046 if (relocations[j].newPath) { /* Relocate the path */
1048 rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
1049 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
1050 (void) rpmCleanPath(t);
1054 rpmlog(RPMLOG_DEBUG,
1055 "relocating directory %s to %s\n", dirNames[i], t);
1063 /* Save original filenames in header and replace (relocated) filenames. */
1067 headerGet(h, RPMTAG_BASENAMES, &td, HEADERGET_MINMEM);
1068 rpmtdSetTag(&td, RPMTAG_ORIGBASENAMES);
1069 headerPut(h, &td, HEADERPUT_DEFAULT);
1072 headerGet(h, RPMTAG_DIRNAMES, &td, HEADERGET_MINMEM);
1073 rpmtdSetTag(&td, RPMTAG_ORIGDIRNAMES);
1074 headerPut(h, &td, HEADERPUT_DEFAULT);
1077 headerGet(h, RPMTAG_DIRINDEXES, &td, HEADERGET_MINMEM);
1078 rpmtdSetTag(&td, RPMTAG_ORIGDIRINDEXES);
1079 headerPut(h, &td, HEADERPUT_DEFAULT);
1082 if (rpmtdFromStringArray(&td, RPMTAG_BASENAMES, (const char**) baseNames, fileCount)) {
1086 headerGet(h, RPMTAG_BASENAMES, &td, fi->scareFlags);
1087 fi->fc = rpmtdCount(&td);
1090 if (rpmtdFromStringArray(&td, RPMTAG_DIRNAMES, (const char**) dirNames, dirCount)) {
1094 headerGet(h, RPMTAG_DIRNAMES, &td, fi->scareFlags);
1095 fi->dc = rpmtdCount(&td);
1098 if (rpmtdFromUint32(&td, RPMTAG_DIRINDEXES, dirIndexes, fileCount)) {
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)
1108 rpmtdFreeData(&bnames);
1109 rpmtdFreeData(&dnames);
1110 rpmtdFreeData(&dindexes);
1111 rpmtdFreeData(&fcolors);
1112 rpmtdFreeData(&fmodes);
1114 for (i = 0; i < numRelocations; i++) {
1115 free(relocations[i].oldPath);
1116 free(relocations[i].newPath);
1119 free(newDirIndexes);
1125 rpmfi rpmfiFree(rpmfi fi)
1127 if (fi == NULL) return NULL;
1130 return rpmfiUnlink(fi, fi->Type);
1132 if (_rpmfi_debug < 0)
1133 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
1136 fi->bnl = _free(fi->bnl);
1137 fi->dnl = _free(fi->dnl);
1139 fi->flinks = _free(fi->flinks);
1140 fi->flangs = _free(fi->flangs);
1141 fi->digests = _free(fi->digests);
1142 fi->fcaps = _free(fi->fcaps);
1144 fi->cdict = _free(fi->cdict);
1146 fi->fuser = _free(fi->fuser);
1147 fi->fgroup = _free(fi->fgroup);
1149 fi->fstates = _free(fi->fstates);
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);
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);
1170 fi->fsm = freeFSM(fi->fsm);
1172 fi->fn = _free(fi->fn);
1173 fi->apath = _free(fi->apath);
1175 fi->actions = _free(fi->actions);
1176 fi->replacedSizes = _free(fi->replacedSizes);
1177 fi->replaced = _free(fi->replaced);
1179 fi->h = headerFree(fi->h);
1181 (void) rpmfiUnlink(fi, fi->Type);
1182 memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
1188 #define _hgfi(_h, _tag, _td, _flags, _data) \
1189 if (headerGet((_h), (_tag), (_td), (_flags))) \
1192 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, rpmfiFlags flags)
1197 rpm_loff_t *asize = NULL;
1199 struct rpmtd_s fdigests, digalgo;
1201 headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ?
1202 HEADERGET_MINMEM : HEADERGET_ALLOC;
1203 headerGetFlags defFlags = HEADERGET_ALLOC;
1205 if (tagN == RPMTAG_BASENAMES) {
1212 fi = xcalloc(1, sizeof(*fi));
1213 if (fi == NULL) /* XXX can't happen */
1216 fi->magic = RPMFIMAGIC;
1221 fi->scareFlags = scareFlags;
1223 fi->keep_header = (flags & RPMFI_KEEPHEADER);
1224 fi->h = fi->keep_header ? headerLink(h) : NULL;
1226 if (fi->fsm == NULL)
1229 if (headerGet(h, RPMTAG_LONGARCHIVESIZE, &td, HEADERGET_EXT)) {
1230 asize = rpmtdGetUint64(&td);
1232 /* 0 means unknown */
1233 fi->archiveSize = asize ? *asize : 0;
1236 /* See if we have pre/posttrans scripts. */
1237 fi->transscripts |= (headerIsEntry(h, RPMTAG_PRETRANS) &&
1238 headerIsEntry(h, RPMTAG_PRETRANSPROG)) ?
1239 RPMFI_HAVE_PRETRANS : 0;
1240 fi->transscripts |= (headerIsEntry(h, RPMTAG_POSTTRANS) &&
1241 headerIsEntry(h, RPMTAG_POSTTRANSPROG)) ?
1242 RPMFI_HAVE_POSTTRANS : 0;
1244 _hgfi(h, RPMTAG_BASENAMES, &td, defFlags, fi->bnl);
1245 fi->fc = rpmtdCount(&td);
1250 _hgfi(h, RPMTAG_DIRNAMES, &td, defFlags, fi->dnl);
1251 fi->dc = rpmtdCount(&td);
1252 _hgfi(h, RPMTAG_DIRINDEXES, &td, scareFlags, fi->dil);
1253 _hgfi(h, RPMTAG_FILEMODES, &td, scareFlags, fi->fmodes);
1254 _hgfi(h, RPMTAG_FILEFLAGS, &td, scareFlags, fi->fflags);
1255 _hgfi(h, RPMTAG_FILEVERIFYFLAGS, &td, scareFlags, fi->vflags);
1256 _hgfi(h, RPMTAG_FILESIZES, &td, scareFlags, fi->fsizes);
1258 _hgfi(h, RPMTAG_FILECOLORS, &td, scareFlags, fi->fcolors);
1260 if (!(flags & RPMFI_NOFILECLASS)) {
1261 _hgfi(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
1262 fi->ncdict = rpmtdCount(&td);
1263 _hgfi(h, RPMTAG_FILECLASS, &td, scareFlags, fi->fcdictx);
1265 if (!(flags & RPMFI_NOFILEDEPS)) {
1266 _hgfi(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
1267 fi->nddict = rpmtdCount(&td);
1268 _hgfi(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
1269 _hgfi(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
1272 /* XXX States not needed by TR_REMOVED */
1273 _hgfi(h, RPMTAG_FILESTATES, &td, defFlags, fi->fstates);
1274 if (fi->fstates == NULL) {
1275 fi->fstates = xmalloc(sizeof(*fi->fstates) * fi->fc);
1276 /* XXX means we show state "normal" when package not even installed */
1277 memset(fi->fstates, RPMFILE_STATE_NORMAL, fi->fc);
1280 _hgfi(h, RPMTAG_FILECAPS, &td, defFlags, fi->fcaps);
1282 fi->action = FA_UNKNOWN;
1285 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1287 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1289 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1291 _hgfi(h, RPMTAG_FILELINKTOS, &td, defFlags, fi->flinks);
1292 _hgfi(h, RPMTAG_FILELANGS, &td, defFlags, fi->flangs);
1294 /* See if the package has non-md5 file digests */
1295 fi->digestalgo = PGPHASHALGO_MD5;
1296 if (headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM)) {
1297 pgpHashAlgo *algo = rpmtdGetUint32(&digalgo);
1298 /* Hmm, what to do with unknown digest algorithms? */
1299 if (algo && rpmDigestLength(*algo) != 0) {
1300 fi->digestalgo = *algo;
1305 /* grab hex digests from header and store in binary format */
1306 if (headerGet(h, RPMTAG_FILEDIGESTS, &fdigests, HEADERGET_MINMEM)) {
1307 const char *fdigest;
1308 size_t diglen = rpmDigestLength(fi->digestalgo);
1309 fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
1311 while ((fdigest = rpmtdNextString(&fdigests))) {
1312 if (!(fdigest && *fdigest != '\0')) {
1313 memset(t, 0, diglen);
1317 for (int j = 0; j < diglen; j++, t++, fdigest += 2)
1318 *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
1320 rpmtdFreeData(&fdigests);
1323 /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
1324 _hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
1325 _hgfi(h, RPMTAG_FILERDEVS, &td, scareFlags, fi->frdevs);
1326 _hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
1328 fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
1330 _hgfi(h, RPMTAG_FILEUSERNAME, &td, defFlags, fi->fuser);
1331 _hgfi(h, RPMTAG_FILEGROUPNAME, &td, defFlags, fi->fgroup);
1335 if ((p = rpmtsRelocateElement(ts)) != NULL && rpmteType(p) == TR_ADDED
1336 && !headerIsSource(h)
1337 && !headerIsEntry(h, RPMTAG_ORIGBASENAMES))
1341 /* FIX: fi-digests undefined */
1342 foo = relocateFileList(ts, fi, h, fi->actions);
1343 fi->h = headerFree(fi->h);
1344 fi->h = headerLink(foo);
1345 foo = headerFree(foo);
1348 if (!fi->keep_header) {
1349 fi->h = headerFree(fi->h);
1352 /* lazily alloced from rpmfiFN() */
1356 if (_rpmfi_debug < 0)
1357 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, Type, (fi ? fi->fc : 0));
1359 /* FIX: rpmfi null annotations */
1360 return rpmfiLink(fi, (fi ? fi->Type : NULL));