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() */
23 * Simple and stupid user + groupname "cache."
24 * Store each unique user and group name string just once, retrieve
25 * by index value. As the number of unique names is typically very low,
26 * the dumb linear lookup appears to be fast enough and hash table seems
32 } ugcache = { NULL, 0 };
34 static ugidx_t ugcachePut(const char *str)
39 for (ugidx_t i = 0; i < ugcache.num; i++) {
40 if (strcmp(str, ugcache.uniq[i]) == 0) {
47 /* blow up on index wraparound */
48 assert((ugidx_t)(ugcache.num + 1) > ugcache.num);
49 ugcache.uniq = xrealloc(ugcache.uniq,
50 sizeof(ugcache.uniq) * (ugcache.num+1));
51 ugcache.uniq[ugcache.num] = xstrdup(str);
58 static const char *ugcacheGet(ugidx_t idx)
60 const char *name = NULL;
61 if (idx >= 0 && idx < ugcache.num && ugcache.uniq != NULL)
62 name = ugcache.uniq[idx];
68 rpmfi rpmfiUnlink(rpmfi fi, const char * msg)
70 if (fi == NULL) return NULL;
71 if (_rpmfi_debug && msg != NULL)
72 fprintf(stderr, "--> fi %p -- %d %s\n", fi, fi->nrefs, msg);
77 rpmfi rpmfiLink(rpmfi fi, const char * msg)
79 if (fi == NULL) return NULL;
81 if (_rpmfi_debug && msg != NULL)
82 fprintf(stderr, "--> fi %p ++ %d %s\n", fi, fi->nrefs, msg);
86 rpm_count_t rpmfiFC(rpmfi fi)
88 return (fi != NULL ? fi->fc : 0);
91 rpm_count_t rpmfiDC(rpmfi fi)
93 return (fi != NULL ? fi->dc : 0);
102 int rpmfiFX(rpmfi fi)
104 return (fi != NULL ? fi->i : -1);
107 int rpmfiSetFX(rpmfi fi, int fx)
111 if (fi != NULL && fx >= 0 && fx < fi->fc) {
114 fi->j = fi->dil[fi->i];
119 int rpmfiDX(rpmfi fi)
121 return (fi != NULL ? fi->j : -1);
124 int rpmfiSetDX(rpmfi fi, int dx)
128 if (fi != NULL && dx >= 0 && dx < fi->dc) {
135 const char * rpmfiBN(rpmfi fi)
137 const char * BN = NULL;
139 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
146 const char * rpmfiDN(rpmfi fi)
148 const char * DN = NULL;
150 if (fi != NULL && fi->j >= 0 && fi->j < fi->dc) {
157 const char * rpmfiFN(rpmfi fi)
159 const char * FN = "";
161 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
163 if (fi->fn == NULL) {
164 size_t dnlmax = 0, bnlmax = 0, len;
165 for (int i = 0; i < fi->dc; i++) {
166 if ((len = strlen(fi->dnl[i])) > dnlmax)
169 for (int i = 0; i < fi->fc; i++) {
170 if ((len = strlen(fi->bnl[i])) > bnlmax)
173 fi->fn = xmalloc(dnlmax + bnlmax + 1);
177 t = stpcpy(t, fi->dnl[fi->dil[fi->i]]);
178 t = stpcpy(t, fi->bnl[fi->i]);
183 rpmfileAttrs rpmfiFFlags(rpmfi fi)
185 rpmfileAttrs FFlags = 0;
187 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
188 if (fi->fflags != NULL)
189 FFlags = fi->fflags[fi->i];
194 rpmVerifyAttrs rpmfiVFlags(rpmfi fi)
196 rpmVerifyAttrs VFlags = 0;
198 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
199 if (fi->vflags != NULL)
200 VFlags = fi->vflags[fi->i];
205 rpm_mode_t rpmfiFMode(rpmfi fi)
207 rpm_mode_t fmode = 0;
209 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
210 if (fi->fmodes != NULL)
211 fmode = fi->fmodes[fi->i];
216 rpmfileState rpmfiFState(rpmfi fi)
218 rpmfileState fstate = RPMFILE_STATE_MISSING;
220 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
221 if (fi->fstates != NULL)
222 fstate = fi->fstates[fi->i];
227 const unsigned char * rpmfiMD5(rpmfi fi)
229 const unsigned char *digest;
230 pgpHashAlgo algo = 0;
232 digest = rpmfiFDigest(fi, &algo, NULL);
233 return (algo == PGPHASHALGO_MD5) ? digest : NULL;
236 const unsigned char * rpmfiFDigest(rpmfi fi, pgpHashAlgo *algo, size_t *len)
238 const unsigned char *digest = NULL;
240 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
241 size_t diglen = rpmDigestLength(fi->digestalgo);
242 if (fi->digests != NULL)
243 digest = fi->digests + (diglen * fi->i);
247 *algo = fi->digestalgo;
252 char * rpmfiFDigestHex(rpmfi fi, pgpHashAlgo *algo)
255 char *fdigest = NULL;
256 const unsigned char *digest = rpmfiFDigest(fi, algo, &diglen);
258 fdigest = pgpHexStr(digest, diglen);
263 const char * rpmfiFLink(rpmfi fi)
265 const char * flink = NULL;
267 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
268 if (fi->flinks != NULL)
269 flink = fi->flinks[fi->i];
274 rpm_loff_t rpmfiFSize(rpmfi fi)
276 rpm_loff_t fsize = 0;
278 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
279 if (fi->fsizes != NULL)
280 fsize = fi->fsizes[fi->i];
285 rpm_rdev_t rpmfiFRdev(rpmfi fi)
287 rpm_rdev_t frdev = 0;
289 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
290 if (fi->frdevs != NULL)
291 frdev = fi->frdevs[fi->i];
296 rpm_ino_t rpmfiFInode(rpmfi fi)
298 rpm_ino_t finode = 0;
300 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
301 if (fi->finodes != NULL)
302 finode = fi->finodes[fi->i];
307 rpm_color_t rpmfiColor(rpmfi fi)
309 rpm_color_t color = 0;
311 if (fi != NULL && fi->fcolors != NULL) {
312 for (int i = 0; i < fi->fc; i++)
313 color |= fi->fcolors[i];
314 /* XXX ignore all but lsnibble for now. */
320 rpm_color_t rpmfiFColor(rpmfi fi)
322 rpm_color_t fcolor = 0;
324 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
325 if (fi->fcolors != NULL)
326 /* XXX ignore all but lsnibble for now. */
327 fcolor = (fi->fcolors[fi->i] & 0x0f);
332 const char * rpmfiFClass(rpmfi fi)
334 const char * fclass = NULL;
337 if (fi != NULL && fi->fcdictx != NULL && fi->i >= 0 && fi->i < fi->fc) {
338 cdictx = fi->fcdictx[fi->i];
339 if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
340 fclass = fi->cdict[cdictx];
345 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
349 const uint32_t * fddict = NULL;
351 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
352 if (fi->fddictn != NULL)
353 fddictn = fi->fddictn[fi->i];
354 if (fddictn > 0 && fi->fddictx != NULL)
355 fddictx = fi->fddictx[fi->i];
356 if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
357 fddict = fi->ddict + fddictx;
364 uint32_t rpmfiFNlink(rpmfi fi)
368 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
369 /* XXX rpm-2.3.12 has not RPMTAG_FILEINODES */
370 if (fi->finodes && fi->frdevs) {
371 rpm_ino_t finode = fi->finodes[fi->i];
372 rpm_rdev_t frdev = fi->frdevs[fi->i];
375 for (j = 0; j < fi->fc; j++) {
376 if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
384 rpm_time_t rpmfiFMtime(rpmfi fi)
386 rpm_time_t fmtime = 0;
388 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
389 if (fi->fmtimes != NULL)
390 fmtime = fi->fmtimes[fi->i];
395 const char * rpmfiFUser(rpmfi fi)
397 const char * fuser = NULL;
399 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
400 if (fi->fuser != NULL)
401 fuser = ugcacheGet(fi->fuser[fi->i]);
406 const char * rpmfiFGroup(rpmfi fi)
408 const char * fgroup = NULL;
410 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
411 if (fi->fgroup != NULL)
412 fgroup = ugcacheGet(fi->fgroup[fi->i]);
417 const char * rpmfiFCaps(rpmfi fi)
419 const char *fcaps = NULL;
420 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
421 fcaps = fi->fcaps ? fi->fcaps[fi->i] : "";
426 rpmFileAction rpmfiFAction(rpmfi fi)
428 rpmFileAction action;
429 if (fi != NULL && fi->actions != NULL && fi->i >= 0 && fi->i < fi->fc) {
430 action = fi->actions[fi->i];
437 void rpmfiSetFAction(rpmfi fi, rpmFileAction action)
439 if (fi != NULL && fi->actions != NULL && fi->i >= 0 && fi->i < fi->fc) {
440 fi->actions[fi->i] = action;
444 int rpmfiNext(rpmfi fi)
448 if (fi != NULL && ++fi->i >= 0) {
449 if (fi->i < fi->fc) {
452 fi->j = fi->dil[fi->i];
456 if (_rpmfi_debug < 0 && i != -1)
457 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] : ""));
464 rpmfi rpmfiInit(rpmfi fi, int fx)
467 if (fx >= 0 && fx < fi->fc) {
476 int rpmfiNextD(rpmfi fi)
480 if (fi != NULL && ++fi->j >= 0) {
486 if (_rpmfi_debug < 0 && j != -1)
487 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, (fi->Type ? fi->Type : "?Type?"), j);
494 rpmfi rpmfiInitD(rpmfi fi, int dx)
497 if (dx >= 0 && dx < fi->fc)
507 * Identify a file type.
508 * @param ft file type
509 * @return string to identify a file type
512 const char * ftstring (rpmFileTypes ft)
515 case XDIR: return "directory";
516 case CDEV: return "char dev";
517 case BDEV: return "block dev";
518 case LINK: return "link";
519 case SOCK: return "sock";
520 case PIPE: return "fifo/pipe";
521 case REG: return "file";
522 default: return "unknown file type";
526 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
528 if (S_ISDIR(mode)) return XDIR;
529 if (S_ISCHR(mode)) return CDEV;
530 if (S_ISBLK(mode)) return BDEV;
531 if (S_ISLNK(mode)) return LINK;
532 if (S_ISSOCK(mode)) return SOCK;
533 if (S_ISFIFO(mode)) return PIPE;
537 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
539 rpmFileTypes awhat = rpmfiWhatis(rpmfiFMode(afi));
540 rpmFileTypes bwhat = rpmfiWhatis(rpmfiFMode(bfi));
542 if ((rpmfiFFlags(afi) & RPMFILE_GHOST) ||
543 (rpmfiFFlags(bfi) & RPMFILE_GHOST)) return 0;
545 if (awhat != bwhat) return 1;
548 const char * alink = rpmfiFLink(afi);
549 const char * blink = rpmfiFLink(bfi);
550 if (alink == blink) return 0;
551 if (alink == NULL) return 1;
552 if (blink == NULL) return -1;
553 return strcmp(alink, blink);
554 } else if (awhat == REG) {
555 size_t adiglen, bdiglen;
556 pgpHashAlgo aalgo, balgo;
557 const unsigned char * adigest = rpmfiFDigest(afi, &aalgo, &adiglen);
558 const unsigned char * bdigest = rpmfiFDigest(bfi, &balgo, &bdiglen);
559 if (adigest == bdigest) return 0;
560 if (adigest == NULL) return 1;
561 if (bdigest == NULL) return -1;
562 /* can't meaningfully compare different hash types */
563 if (aalgo != balgo || adiglen != bdiglen) return -1;
564 return memcmp(adigest, bdigest, adiglen);
570 rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
572 const char * fn = rpmfiFN(nfi);
573 rpmfileAttrs newFlags = rpmfiFFlags(nfi);
575 rpmFileTypes dbWhat, newWhat, diskWhat;
577 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
579 if (lstat(fn, &sb)) {
581 * The file doesn't exist on the disk. Create it unless the new
582 * package has marked it as missingok, or allfiles is requested.
584 if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
585 rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
593 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
594 dbWhat = rpmfiWhatis(rpmfiFMode(ofi));
595 newWhat = rpmfiWhatis(rpmfiFMode(nfi));
598 * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
599 * them in older packages as well.
604 if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK)
606 else if (newWhat != dbWhat && diskWhat != dbWhat)
608 else if (dbWhat != newWhat)
610 else if (dbWhat != LINK && dbWhat != REG)
614 * This order matters - we'd prefer to CREATE the file if at all
615 * possible in case something else (like the timestamp) has changed.
617 memset(buffer, 0, sizeof(buffer));
619 pgpHashAlgo oalgo, nalgo;
620 size_t odiglen, ndiglen;
621 const unsigned char * odigest, * ndigest;
622 odigest = rpmfiFDigest(ofi, &oalgo, &odiglen);
623 if (diskWhat == REG) {
624 if (rpmDoDigest(oalgo, fn, 0,
625 (unsigned char *)buffer, NULL))
626 return FA_CREATE; /* assume file has been removed */
627 if (odigest && !memcmp(odigest, buffer, odiglen))
628 return FA_CREATE; /* unmodified config file, replace. */
630 ndigest = rpmfiFDigest(nfi, &nalgo, &ndiglen);
631 /* XXX can't compare different hash types, what should we do here? */
632 if (oalgo != nalgo || odiglen != ndiglen)
634 if (odigest && ndigest && !memcmp(odigest, ndigest, odiglen))
635 return FA_SKIP; /* identical file, don't bother. */
636 } else /* dbWhat == LINK */ {
637 const char * oFLink, * nFLink;
638 oFLink = rpmfiFLink(ofi);
639 if (diskWhat == LINK) {
640 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
641 return FA_CREATE; /* assume file has been removed */
642 if (oFLink && !strcmp(oFLink, buffer))
643 return FA_CREATE; /* unmodified config file, replace. */
645 nFLink = rpmfiFLink(nfi);
646 if (oFLink && nFLink && !strcmp(oFLink, nFLink))
647 return FA_SKIP; /* identical file, don't bother. */
651 * The config file on the disk has been modified, but
652 * the ones in the two packages are different. It would
653 * be nice if RPM was smart enough to at least try and
654 * merge the difference ala CVS, but...
659 int rpmfiConfigConflict(const rpmfi fi)
661 const char * fn = rpmfiFN(fi);
662 rpmfileAttrs flags = rpmfiFFlags(fi);
664 rpmFileTypes newWhat, diskWhat;
667 if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) {
671 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
672 newWhat = rpmfiWhatis(rpmfiFMode(fi));
674 if (newWhat != LINK && newWhat != REG)
677 if (diskWhat != newWhat)
680 memset(buffer, 0, sizeof(buffer));
681 if (newWhat == REG) {
684 const unsigned char *ndigest = rpmfiFDigest(fi, &algo, &diglen);
685 if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL))
686 return 0; /* assume file has been removed */
687 if (ndigest && !memcmp(ndigest, buffer, diglen))
688 return 0; /* unmodified config file */
689 } else /* newWhat == LINK */ {
691 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
692 return 0; /* assume file has been removed */
693 nFLink = rpmfiFLink(fi);
694 if (nFLink && !strcmp(nFLink, buffer))
695 return 0; /* unmodified config file */
701 const char * rpmfiTypeString(rpmfi fi)
703 switch(rpmteType(fi->te)) {
704 case TR_ADDED: return " install";
705 case TR_REMOVED: return " erase";
706 default: return "???";
710 static char **duparray(char ** src, int size)
712 char **dest = xmalloc((size+1) * sizeof(*dest));
713 for (int i = 0; i < size; i++) {
714 dest[i] = xstrdup(src[i]);
721 * Relocate files in header.
722 * @todo multilib file dispositions need to be checked.
723 * @param ts transaction set
724 * @param fi transaction element file info
725 * @param origH package header
726 * @param actions file dispositions
727 * @return header with relocated files
730 Header relocateFileList(const rpmts ts, rpmfi fi,
731 Header origH, rpmFileAction * actions)
733 rpmte p = rpmtsRelocateElement(ts);
734 static int _printed = 0;
735 int allowBadRelocate = (rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE);
736 rpmRelocation * relocations = NULL;
740 uint32_t * dirIndexes;
741 uint32_t * newDirIndexes;
742 rpm_count_t fileCount, dirCount, numValid = 0;
743 rpm_color_t * fColors = NULL;
744 rpm_color_t * dColors = NULL;
745 rpm_mode_t * fModes = NULL;
750 int haveRelocatedBase = 0;
754 struct rpmtd_s validRelocs;
755 struct rpmtd_s bnames, dnames, dindexes, fcolors, fmodes;
758 if (headerGet(origH, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM))
759 numValid = rpmtdCount(&validRelocs);
764 while (p->relocs[numRelocations].newPath ||
765 p->relocs[numRelocations].oldPath)
769 * If no relocations are specified (usually the case), then return the
770 * original header. If there are prefixes, however, then INSTPREFIXES
771 * should be added, but, since relocateFileList() can be called more
772 * than once for the same header, don't bother if already present.
774 if (p->relocs == NULL || numRelocations == 0) {
776 if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES)) {
777 rpmtdSetTag(&validRelocs, RPMTAG_INSTPREFIXES);
778 headerPut(origH, &validRelocs, HEADERPUT_DEFAULT);
780 rpmtdFreeData(&validRelocs);
782 /* XXX FIXME multilib file actions need to be checked. */
783 return headerLink(origH);
786 h = headerLink(origH);
788 relocations = xmalloc(sizeof(*relocations) * numRelocations);
790 /* Build sorted relocation list from raw relocations. */
791 for (i = 0; i < numRelocations; i++) {
795 * Default relocations (oldPath == NULL) are handled in the UI,
798 if (p->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
800 /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
801 too, but those are more trouble to fix up. :-( */
802 t = xstrdup(p->relocs[i].oldPath);
803 relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
805 : stripTrailingChar(t, '/');
807 /* An old path w/o a new path is valid, and indicates exclusion */
808 if (p->relocs[i].newPath) {
811 const char *validprefix;
813 t = xstrdup(p->relocs[i].newPath);
814 relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
816 : stripTrailingChar(t, '/');
818 /* FIX: relocations[i].oldPath == NULL */
819 /* Verify that the relocation's old path is in the header. */
820 rpmtdInit(&validRelocs);
821 while ((validprefix = rpmtdNextString(&validRelocs))) {
822 if (strcmp(validprefix, relocations[i].oldPath) == 0) {
828 /* XXX actions check prevents problem from being appended twice. */
829 if (!valid && !allowBadRelocate && actions) {
830 rpmps ps = rpmtsProblems(ts);
831 rpmpsAppend(ps, RPMPROB_BADRELOCATE,
832 rpmteNEVRA(p), rpmteKey(p),
833 relocations[i].oldPath, NULL, NULL, 0);
837 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
842 relocations[i].newPath = NULL;
846 /* stupid bubble sort, but it's probably faster here */
847 for (i = 0; i < numRelocations; i++) {
850 for (j = 1; j < numRelocations; j++) {
851 rpmRelocation tmpReloc;
852 if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
853 relocations[j ].oldPath == NULL || /* XXX can't happen */
854 strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
857 tmpReloc = relocations[j - 1];
858 relocations[j - 1] = relocations[j];
859 relocations[j] = tmpReloc;
862 if (!madeSwap) break;
867 rpmlog(RPMLOG_DEBUG, "========== relocations\n");
868 for (i = 0; i < numRelocations; i++) {
869 if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
870 if (relocations[i].newPath == NULL)
871 rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n",
872 i, relocations[i].oldPath);
874 rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
875 i, relocations[i].oldPath, relocations[i].newPath);
879 /* Add relocation values to the header */
881 const char *validprefix;
882 const char ** actualRelocations;
883 rpm_count_t numActual;
885 actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
887 rpmtdInit(&validRelocs);
888 while ((validprefix = rpmtdNextString(&validRelocs))) {
889 for (j = 0; j < numRelocations; j++) {
890 if (relocations[j].oldPath == NULL || /* XXX can't happen */
891 strcmp(validprefix, relocations[j].oldPath))
893 /* On install, a relocate to NULL means skip the path. */
894 if (relocations[j].newPath) {
895 actualRelocations[numActual] = relocations[j].newPath;
900 if (j == numRelocations) {
901 actualRelocations[numActual] = validprefix;
907 headerPutStringArray(h, RPMTAG_INSTPREFIXES,
908 actualRelocations, numActual);
911 actualRelocations = _free(actualRelocations);
912 rpmtdFreeData(&validRelocs);
915 headerGet(h, RPMTAG_BASENAMES, &bnames, fi->scareFlags);
916 headerGet(h, RPMTAG_DIRINDEXES, &dindexes, fi->scareFlags);
917 headerGet(h, RPMTAG_DIRNAMES, &dnames, fi->scareFlags);
918 headerGet(h, RPMTAG_FILECOLORS, &fcolors, fi->scareFlags);
919 headerGet(h, RPMTAG_FILEMODES, &fmodes, fi->scareFlags);
920 /* TODO XXX ugh.. use rpmtd iterators & friends instead */
921 baseNames = bnames.data;
922 dirIndexes = dindexes.data;
923 fColors = fcolors.data;
924 fModes = fmodes.data;
925 fileCount = rpmtdCount(&bnames);
926 dirCount = rpmtdCount(&dnames);
927 /* XXX TODO: use rpmtdDup() instead */
928 dirNames = dnames.data = duparray(dnames.data, dirCount);
929 dnames.flags |= RPMTD_PTR_ALLOCED;
931 dColors = xcalloc(dirCount, sizeof(*dColors));
933 newDirIndexes = xmalloc(sizeof(*newDirIndexes) * fileCount);
934 memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
935 dirIndexes = newDirIndexes;
938 * For all relocations, we go through sorted file/relocation lists
939 * backwards so that /usr/local relocations take precedence over /usr
943 /* Relocate individual paths. */
945 for (i = fileCount - 1; i >= 0; i--) {
950 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
951 if (len >= fileAlloced) {
952 fileAlloced = len * 2;
953 fn = xrealloc(fn, fileAlloced);
956 assert(fn != NULL); /* XXX can't happen */
958 fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
960 if (fColors != NULL) {
961 /* XXX pkgs may not have unique dirNames, so color all dirNames that match. */
962 for (j = 0; j < dirCount; j++) {
963 if (strcmp(dirNames[dirIndexes[i]], dirNames[j])) continue;
964 dColors[j] |= fColors[i];
969 * See if this file path needs relocating.
972 * XXX FIXME: Would a bsearch of the (already sorted)
973 * relocation list be a good idea?
975 for (j = numRelocations - 1; j >= 0; j--) {
976 if (relocations[j].oldPath == NULL) /* XXX can't happen */
978 len = strcmp(relocations[j].oldPath, "/")
979 ? strlen(relocations[j].oldPath)
985 * Only subdirectories or complete file paths may be relocated. We
986 * don't check for '\0' as our directory names all end in '/'.
988 if (!(fn[len] == '/' || fnlen == len))
991 if (strncmp(relocations[j].oldPath, fn, len))
997 /* FIX: fModes may be NULL */
998 ft = rpmfiWhatis(fModes[i]);
1000 /* On install, a relocate to NULL means skip the path. */
1001 if (relocations[j].newPath == NULL) {
1003 /* Start with the parent, looking for directory to exclude. */
1004 for (j = dirIndexes[i]; j < dirCount; j++) {
1005 len = strlen(dirNames[j]) - 1;
1006 while (len > 0 && dirNames[j][len-1] == '/') len--;
1009 if (strncmp(fn, dirNames[j], fnlen))
1015 actions[i] = FA_SKIPNSTATE;
1016 rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
1022 /* Relocation on full paths only, please. */
1023 if (fnlen != len) continue;
1026 rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
1027 fn, relocations[j].newPath);
1030 strcpy(fn, relocations[j].newPath);
1031 { char * te = strrchr(fn, '/');
1033 if (te > fn) te++; /* root is special */
1036 te = fn + strlen(fn);
1037 if (strcmp(baseNames[i], te)) { /* basename changed too? */
1038 if (!haveRelocatedBase) {
1039 /* XXX TODO: use rpmtdDup() instead */
1040 bnames.data = baseNames = duparray(baseNames, fileCount);
1041 bnames.flags |= RPMTD_PTR_ALLOCED;
1042 haveRelocatedBase = 1;
1045 baseNames[i] = xstrdup(te);
1047 *te = '\0'; /* terminate new directory name */
1050 /* Does this directory already exist in the directory list? */
1051 for (j = 0; j < dirCount; j++) {
1052 if (fnlen != strlen(dirNames[j]))
1054 if (strncmp(fn, dirNames[j], fnlen))
1064 /* Creating new paths is a pita */
1065 dirNames = dnames.data = xrealloc(dnames.data,
1066 sizeof(*dirNames) * (dirCount + 1));
1068 dirNames[dirCount] = xstrdup(fn);
1069 dirIndexes[i] = dirCount;
1074 /* Finish off by relocating directories. */
1075 for (i = dirCount - 1; i >= 0; i--) {
1076 for (j = numRelocations - 1; j >= 0; j--) {
1078 if (relocations[j].oldPath == NULL) /* XXX can't happen */
1080 len = strcmp(relocations[j].oldPath, "/")
1081 ? strlen(relocations[j].oldPath)
1084 if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
1088 * Only subdirectories or complete file paths may be relocated. We
1089 * don't check for '\0' as our directory names all end in '/'.
1091 if (dirNames[i][len] != '/')
1094 if (relocations[j].newPath) { /* Relocate the path */
1096 rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
1097 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
1098 (void) rpmCleanPath(t);
1102 rpmlog(RPMLOG_DEBUG,
1103 "relocating directory %s to %s\n", dirNames[i], t);
1111 /* Save original filenames in header and replace (relocated) filenames. */
1115 headerGet(h, RPMTAG_BASENAMES, &td, HEADERGET_MINMEM);
1116 rpmtdSetTag(&td, RPMTAG_ORIGBASENAMES);
1117 headerPut(h, &td, HEADERPUT_DEFAULT);
1120 headerGet(h, RPMTAG_DIRNAMES, &td, HEADERGET_MINMEM);
1121 rpmtdSetTag(&td, RPMTAG_ORIGDIRNAMES);
1122 headerPut(h, &td, HEADERPUT_DEFAULT);
1125 headerGet(h, RPMTAG_DIRINDEXES, &td, HEADERGET_MINMEM);
1126 rpmtdSetTag(&td, RPMTAG_ORIGDIRINDEXES);
1127 headerPut(h, &td, HEADERPUT_DEFAULT);
1130 if (rpmtdFromStringArray(&td, RPMTAG_BASENAMES, (const char**) baseNames, fileCount)) {
1134 headerGet(h, RPMTAG_BASENAMES, &td, fi->scareFlags);
1135 fi->fc = rpmtdCount(&td);
1138 if (rpmtdFromStringArray(&td, RPMTAG_DIRNAMES, (const char**) dirNames, dirCount)) {
1142 headerGet(h, RPMTAG_DIRNAMES, &td, fi->scareFlags);
1143 fi->dc = rpmtdCount(&td);
1146 if (rpmtdFromUint32(&td, RPMTAG_DIRINDEXES, dirIndexes, fileCount)) {
1149 headerGet(h, RPMTAG_DIRINDEXES, &td, fi->scareFlags);
1150 /* Ugh, nasty games with how dil is alloced depending on scareMem */
1151 if (fi->scareFlags & HEADERGET_ALLOC)
1156 rpmtdFreeData(&bnames);
1157 rpmtdFreeData(&dnames);
1158 rpmtdFreeData(&dindexes);
1159 rpmtdFreeData(&fcolors);
1160 rpmtdFreeData(&fmodes);
1162 for (i = 0; i < numRelocations; i++) {
1163 free(relocations[i].oldPath);
1164 free(relocations[i].newPath);
1167 free(newDirIndexes);
1173 rpmfi rpmfiFree(rpmfi fi)
1175 if (fi == NULL) return NULL;
1178 return rpmfiUnlink(fi, fi->Type);
1180 if (_rpmfi_debug < 0)
1181 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
1184 fi->bnl = _free(fi->bnl);
1185 fi->dnl = _free(fi->dnl);
1187 fi->flinks = _free(fi->flinks);
1188 fi->flangs = _free(fi->flangs);
1189 fi->digests = _free(fi->digests);
1190 fi->fcaps = _free(fi->fcaps);
1192 fi->cdict = _free(fi->cdict);
1194 fi->fuser = _free(fi->fuser);
1195 fi->fgroup = _free(fi->fgroup);
1197 fi->fstates = _free(fi->fstates);
1199 if (!(fi->fiflags & RPMFI_KEEPHEADER) && fi->h == NULL) {
1200 fi->fmtimes = _constfree(fi->fmtimes);
1201 fi->fmodes = _free(fi->fmodes);
1202 fi->fflags = _constfree(fi->fflags);
1203 fi->vflags = _constfree(fi->vflags);
1204 fi->fsizes = _constfree(fi->fsizes);
1205 fi->frdevs = _constfree(fi->frdevs);
1206 fi->finodes = _constfree(fi->finodes);
1207 fi->dil = _free(fi->dil);
1209 fi->fcolors = _constfree(fi->fcolors);
1210 fi->fcdictx = _constfree(fi->fcdictx);
1211 fi->ddict = _constfree(fi->ddict);
1212 fi->fddictx = _constfree(fi->fddictx);
1213 fi->fddictn = _constfree(fi->fddictn);
1218 fi->fsm = freeFSM(fi->fsm);
1220 fi->fn = _free(fi->fn);
1221 fi->apath = _free(fi->apath);
1223 fi->actions = _free(fi->actions);
1224 fi->replacedSizes = _free(fi->replacedSizes);
1225 fi->replaced = _free(fi->replaced);
1227 fi->h = headerFree(fi->h);
1229 (void) rpmfiUnlink(fi, fi->Type);
1230 memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
1236 /* Helper to convert user+group names into indexes to name cache */
1237 static ugidx_t *cacheNames(Header h, rpmTag tag)
1239 ugidx_t *idx = NULL;
1241 if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
1242 idx = xmalloc(sizeof(*idx) * rpmtdCount(&td));
1245 while ((str = rpmtdNextString(&td))) {
1246 idx[i++] = ugcachePut(str);
1253 #define _hgfi(_h, _tag, _td, _flags, _data) \
1254 if (headerGet((_h), (_tag), (_td), (_flags))) \
1257 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, rpmfiFlags flags)
1262 rpm_loff_t *asize = NULL;
1264 int isBuild, isSource;
1265 struct rpmtd_s fdigests, digalgo;
1267 headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ?
1268 HEADERGET_MINMEM : HEADERGET_ALLOC;
1269 headerGetFlags defFlags = HEADERGET_ALLOC;
1271 if (tagN == RPMTAG_BASENAMES) {
1278 fi = xcalloc(1, sizeof(*fi));
1279 if (fi == NULL) /* XXX can't happen */
1282 fi->magic = RPMFIMAGIC;
1287 fi->fiflags = flags;
1288 fi->scareFlags = scareFlags;
1290 fi->h = (fi->fiflags & RPMFI_KEEPHEADER) ? headerLink(h) : NULL;
1292 if (headerGet(h, RPMTAG_LONGARCHIVESIZE, &td, HEADERGET_EXT)) {
1293 asize = rpmtdGetUint64(&td);
1295 /* 0 means unknown */
1296 fi->archiveSize = asize ? *asize : 0;
1299 /* Archive size is not set when this gets called from build */
1300 isBuild = (asize == NULL);
1301 isSource = headerIsSource(h);
1302 if (isBuild) fi->fiflags |= RPMFI_ISBUILD;
1303 if (isSource) fi->fiflags |= RPMFI_ISSOURCE;
1305 /* See if we have pre/posttrans scripts. */
1306 fi->transscripts |= (headerIsEntry(h, RPMTAG_PRETRANS) &&
1307 headerIsEntry(h, RPMTAG_PRETRANSPROG)) ?
1308 RPMFI_HAVE_PRETRANS : 0;
1309 fi->transscripts |= (headerIsEntry(h, RPMTAG_POSTTRANS) &&
1310 headerIsEntry(h, RPMTAG_POSTTRANSPROG)) ?
1311 RPMFI_HAVE_POSTTRANS : 0;
1313 _hgfi(h, RPMTAG_BASENAMES, &td, defFlags, fi->bnl);
1314 fi->fc = rpmtdCount(&td);
1319 _hgfi(h, RPMTAG_DIRNAMES, &td, defFlags, fi->dnl);
1320 fi->dc = rpmtdCount(&td);
1321 _hgfi(h, RPMTAG_DIRINDEXES, &td, scareFlags, fi->dil);
1322 if (!(flags & RPMFI_NOFILEMODES))
1323 _hgfi(h, RPMTAG_FILEMODES, &td, scareFlags, fi->fmodes);
1324 if (!(flags & RPMFI_NOFILEFLAGS))
1325 _hgfi(h, RPMTAG_FILEFLAGS, &td, scareFlags, fi->fflags);
1326 if (!(flags & RPMFI_NOFILEVERIFYFLAGS))
1327 _hgfi(h, RPMTAG_FILEVERIFYFLAGS, &td, scareFlags, fi->vflags);
1328 if (!(flags & RPMFI_NOFILESIZES))
1329 _hgfi(h, RPMTAG_FILESIZES, &td, scareFlags, fi->fsizes);
1331 if (!(flags & RPMFI_NOFILECOLORS))
1332 _hgfi(h, RPMTAG_FILECOLORS, &td, scareFlags, fi->fcolors);
1334 if (!(flags & RPMFI_NOFILECLASS)) {
1335 _hgfi(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
1336 fi->ncdict = rpmtdCount(&td);
1337 _hgfi(h, RPMTAG_FILECLASS, &td, scareFlags, fi->fcdictx);
1339 if (!(flags & RPMFI_NOFILEDEPS)) {
1340 _hgfi(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
1341 fi->nddict = rpmtdCount(&td);
1342 _hgfi(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
1343 _hgfi(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
1347 * For installed packages, get the states here. For to-be-installed
1348 * packages fi->fstates is lazily created through rpmfiSetFState().
1349 * XXX file states not needed at all by TR_REMOVED.
1351 if (!(flags & RPMFI_NOFILESTATES))
1352 _hgfi(h, RPMTAG_FILESTATES, &td, defFlags, fi->fstates);
1354 if (!(flags & RPMFI_NOFILECAPS))
1355 _hgfi(h, RPMTAG_FILECAPS, &td, defFlags, fi->fcaps);
1357 /* For build and src.rpm's the file actions are known at this point */
1358 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1360 for (int i = 0; i < fi->fc; i++) {
1361 int ghost = fi->fflags[i] & RPMFILE_GHOST;
1362 fi->actions[i] = ghost ? FA_SKIP : FA_COPYOUT;
1364 } else if (isSource) {
1365 for (int i = 0; i < fi->fc; i++) {
1366 fi->actions[i] = FA_CREATE;
1370 if (!(flags & RPMFI_NOFILELINKTOS))
1371 _hgfi(h, RPMTAG_FILELINKTOS, &td, defFlags, fi->flinks);
1372 /* FILELANGS are only interesting when installing */
1373 if ((headerGetInstance(h) == 0) && !(flags & RPMFI_NOFILELANGS))
1374 _hgfi(h, RPMTAG_FILELANGS, &td, defFlags, fi->flangs);
1376 /* See if the package has non-md5 file digests */
1377 fi->digestalgo = PGPHASHALGO_MD5;
1378 if (headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM)) {
1379 pgpHashAlgo *algo = rpmtdGetUint32(&digalgo);
1380 /* Hmm, what to do with unknown digest algorithms? */
1381 if (algo && rpmDigestLength(*algo) != 0) {
1382 fi->digestalgo = *algo;
1387 /* grab hex digests from header and store in binary format */
1388 if (!(flags & RPMFI_NOFILEDIGESTS) &&
1389 headerGet(h, RPMTAG_FILEDIGESTS, &fdigests, HEADERGET_MINMEM)) {
1390 const char *fdigest;
1391 size_t diglen = rpmDigestLength(fi->digestalgo);
1392 fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
1394 while ((fdigest = rpmtdNextString(&fdigests))) {
1395 if (!(fdigest && *fdigest != '\0')) {
1396 memset(t, 0, diglen);
1400 for (int j = 0; j < diglen; j++, t++, fdigest += 2)
1401 *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
1403 rpmtdFreeData(&fdigests);
1406 /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
1407 if (!(flags & RPMFI_NOFILEMTIMES))
1408 _hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
1409 if (!(flags & RPMFI_NOFILERDEVS))
1410 _hgfi(h, RPMTAG_FILERDEVS, &td, scareFlags, fi->frdevs);
1411 if (!(flags & RPMFI_NOFILEINODES))
1412 _hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
1414 if (!(flags & RPMFI_NOFILEUSER))
1415 fi->fuser = cacheNames(h, RPMTAG_FILEUSERNAME);
1416 if (!(flags & RPMFI_NOFILEGROUP))
1417 fi->fgroup = cacheNames(h, RPMTAG_FILEGROUPNAME);
1421 if ((p = rpmtsRelocateElement(ts)) != NULL && rpmteType(p) == TR_ADDED
1422 && !headerIsSource(h)
1423 && !headerIsEntry(h, RPMTAG_ORIGBASENAMES))
1427 /* FIX: fi-digests undefined */
1428 foo = relocateFileList(ts, fi, h, fi->actions);
1429 fi->h = headerFree(fi->h);
1430 fi->h = headerLink(foo);
1431 foo = headerFree(foo);
1434 if (!(fi->fiflags & RPMFI_KEEPHEADER)) {
1435 fi->h = headerFree(fi->h);
1438 /* lazily alloced from rpmfiFN() */
1442 if (_rpmfi_debug < 0)
1443 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, Type, (fi ? fi->fc : 0));
1445 /* FIX: rpmfi null annotations */
1446 return rpmfiLink(fi, (fi ? fi->Type : NULL));
1449 rpmfi rpmfiUpdateState(rpmfi fi, rpmts ts, rpmte p)
1451 char * fstates = fi->fstates;
1452 rpmFileAction * actions = fi->actions;
1453 sharedFileInfo replaced = fi->replaced;
1457 if (replaced != NULL) {
1458 for (; replaced->otherPkg; replaced++) {
1461 if (numShared > 0) {
1462 replaced = xcalloc(numShared + 1, sizeof(*fi->replaced));
1463 memcpy(replaced, fi->replaced,
1464 sizeof(*fi->replaced) * (numShared + 1));
1470 fi->replaced = NULL;
1471 /* FIX: fi->actions is NULL */
1474 savep = rpmtsSetRelocateElement(ts, p);
1475 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
1476 (void) rpmtsSetRelocateElement(ts, savep);
1478 if (fi != NULL) { /* XXX can't happen */
1481 fi->fstates = fstates;
1483 fi->actions = actions;
1484 if (replaced != NULL)
1485 fi->replaced = replaced;
1491 void rpmfiSetFState(rpmfi fi, int ix, rpmfileState state)
1493 if (fi != NULL && ix >= 0 && ix < fi->fc) {
1494 if (fi->fstates == NULL) {
1495 fi->fstates = xmalloc(sizeof(*fi->fstates) * fi->fc);
1496 memset(fi->fstates, RPMFILE_STATE_MISSING, fi->fc);
1498 fi->fstates[ix] = state;
1502 void rpmfiSetFReplacedSize(rpmfi fi, rpm_loff_t newsize)
1504 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
1505 if (fi->replacedSizes == NULL) {
1506 fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
1508 /* XXX watch out, replacedSizes is not rpm_loff_t (yet) */
1509 fi->replacedSizes[fi->i] = (rpm_off_t) newsize;
1513 rpm_loff_t rpmfiFReplacedSize(rpmfi fi)
1515 rpm_loff_t rsize = 0;
1516 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
1517 if (fi->replacedSizes) {
1518 rsize = fi->replacedSizes[fi->i];
1524 FSM_t rpmfiFSM(rpmfi fi)
1526 if (fi != NULL && fi->fsm == NULL) {
1527 cpioMapFlags mapflags;
1528 /* Figure out mapflags:
1529 * - path, mode, uid and gid are used by everything
1530 * - all binary packages get SBIT_CHECK set
1531 * - if archive size is not known, we're only building this package,
1532 * different rules apply
1534 mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1535 if (fi->fiflags & RPMFI_ISBUILD) {
1536 mapflags |= CPIO_MAP_TYPE;
1537 if (fi->fiflags & RPMFI_ISSOURCE) mapflags |= CPIO_FOLLOW_SYMLINKS;
1539 if (!(fi->fiflags & RPMFI_ISSOURCE)) mapflags |= CPIO_SBIT_CHECK;
1541 fi->fsm = newFSM(mapflags);
1543 return (fi != NULL) ? fi->fsm : NULL;