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 */
21 static rpmfi rpmfiUnlink(rpmfi fi)
28 rpmfi rpmfiLink(rpmfi fi)
35 rpm_count_t rpmfiFC(rpmfi fi)
37 return (fi != NULL ? fi->fc : 0);
40 rpm_count_t rpmfiDC(rpmfi fi)
42 return (fi != NULL ? fi->dc : 0);
53 return (fi != NULL ? fi->i : -1);
56 int rpmfiSetFX(rpmfi fi, int fx)
60 if (fi != NULL && fx >= 0 && fx < fi->fc) {
63 fi->j = fi->dil[fi->i];
70 return (fi != NULL ? fi->j : -1);
73 int rpmfiSetDX(rpmfi fi, int dx)
77 if (fi != NULL && dx >= 0 && dx < fi->dc) {
84 int rpmfiDIIndex(rpmfi fi, int dx)
87 if (fi != NULL && dx >= 0 && dx < fi->fc) {
94 rpmsid rpmfiBNIdIndex(rpmfi fi, int ix)
97 if (fi != NULL && ix >= 0 && ix < fi->fc) {
104 rpmsid rpmfiDNIdIndex(rpmfi fi, int jx)
107 if (fi != NULL && jx >= 0 && jx < fi->fc) {
108 if (fi->dnid != NULL)
114 const char * rpmfiBNIndex(rpmfi fi, int ix)
116 const char * BN = NULL;
118 if (fi != NULL && ix >= 0 && ix < fi->fc) {
119 if (fi->bnid != NULL)
120 BN = rpmstrPoolStr(fi->pool, fi->bnid[ix]);
125 const char * rpmfiDNIndex(rpmfi fi, int jx)
127 const char * DN = NULL;
129 if (fi != NULL && jx >= 0 && jx < fi->dc) {
130 if (fi->dnid != NULL)
131 DN = rpmstrPoolStr(fi->pool, fi->dnid[jx]);
136 char * rpmfiFNIndex(rpmfi fi, int ix)
139 if (fi != NULL && ix >= 0 && ix < fi->fc) {
140 fn = rstrscat(NULL, rpmstrPoolStr(fi->pool, fi->dnid[fi->dil[ix]]),
141 rpmstrPoolStr(fi->pool, fi->bnid[ix]), NULL);
146 rpmfileAttrs rpmfiFFlagsIndex(rpmfi fi, int ix)
148 rpmfileAttrs FFlags = 0;
150 if (fi != NULL && ix >= 0 && ix < fi->fc) {
151 if (fi->fflags != NULL)
152 FFlags = fi->fflags[ix];
157 rpmVerifyAttrs rpmfiVFlagsIndex(rpmfi fi, int ix)
159 rpmVerifyAttrs VFlags = 0;
161 if (fi != NULL && ix >= 0 && ix < fi->fc) {
162 if (fi->vflags != NULL)
163 VFlags = fi->vflags[ix];
168 rpm_mode_t rpmfiFModeIndex(rpmfi fi, int ix)
170 rpm_mode_t fmode = 0;
172 if (fi != NULL && ix >= 0 && ix < fi->fc) {
173 if (fi->fmodes != NULL)
174 fmode = fi->fmodes[ix];
179 rpmfileState rpmfiFStateIndex(rpmfi fi, int ix)
181 rpmfileState fstate = RPMFILE_STATE_MISSING;
183 if (fi != NULL && ix >= 0 && ix < fi->fc) {
184 if (fi->fstates != NULL)
185 fstate = fi->fstates[ix];
190 const unsigned char * rpmfiMD5(rpmfi fi)
192 const unsigned char *digest;
195 digest = rpmfiFDigest(fi, &algo, NULL);
196 return (algo == PGPHASHALGO_MD5) ? digest : NULL;
199 int rpmfiDigestAlgo(rpmfi fi)
201 return fi ? fi->digestalgo : 0;
204 const unsigned char * rpmfiFDigestIndex(rpmfi fi, int ix, int *algo, size_t *len)
206 const unsigned char *digest = NULL;
208 if (fi != NULL && ix >= 0 && ix < fi->fc) {
209 size_t diglen = rpmDigestLength(fi->digestalgo);
210 if (fi->digests != NULL)
211 digest = fi->digests + (diglen * ix);
215 *algo = fi->digestalgo;
220 char * rpmfiFDigestHex(rpmfi fi, int *algo)
223 char *fdigest = NULL;
224 const unsigned char *digest = rpmfiFDigest(fi, algo, &diglen);
226 fdigest = pgpHexStr(digest, diglen);
231 const char * rpmfiFLinkIndex(rpmfi fi, int ix)
233 const char * flink = NULL;
235 if (fi != NULL && ix >= 0 && ix < fi->fc) {
236 if (fi->flinks != NULL)
237 flink = rpmstrPoolStr(fi->pool, fi->flinks[ix]);
242 rpm_loff_t rpmfiFSizeIndex(rpmfi fi, int ix)
244 rpm_loff_t fsize = 0;
246 if (fi != NULL && ix >= 0 && ix < fi->fc) {
247 if (fi->fsizes != NULL)
248 fsize = fi->fsizes[ix];
253 rpm_rdev_t rpmfiFRdevIndex(rpmfi fi, int ix)
255 rpm_rdev_t frdev = 0;
257 if (fi != NULL && ix >= 0 && ix < fi->fc) {
258 if (fi->frdevs != NULL)
259 frdev = fi->frdevs[ix];
264 rpm_ino_t rpmfiFInodeIndex(rpmfi fi, int ix)
266 rpm_ino_t finode = 0;
268 if (fi != NULL && ix >= 0 && ix < fi->fc) {
269 if (fi->finodes != NULL)
270 finode = fi->finodes[ix];
275 rpm_color_t rpmfiColor(rpmfi fi)
277 rpm_color_t color = 0;
279 if (fi != NULL && fi->fcolors != NULL) {
280 for (int i = 0; i < fi->fc; i++)
281 color |= fi->fcolors[i];
282 /* XXX ignore all but lsnibble for now. */
288 rpm_color_t rpmfiFColorIndex(rpmfi fi, int ix)
290 rpm_color_t fcolor = 0;
292 if (fi != NULL && ix >= 0 && ix < fi->fc) {
293 if (fi->fcolors != NULL)
294 /* XXX ignore all but lsnibble for now. */
295 fcolor = (fi->fcolors[ix] & 0x0f);
300 const char * rpmfiFClassIndex(rpmfi fi, int ix)
302 const char * fclass = NULL;
305 if (fi != NULL && fi->fcdictx != NULL && ix >= 0 && ix < fi->fc) {
306 cdictx = fi->fcdictx[ix];
307 if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
308 fclass = fi->cdict[cdictx];
313 uint32_t rpmfiFDependsIndex(rpmfi fi, int ix, const uint32_t ** fddictp)
317 const uint32_t * fddict = NULL;
319 if (fi != NULL && ix >= 0 && ix < fi->fc) {
320 if (fi->fddictn != NULL)
321 fddictn = fi->fddictn[ix];
322 if (fddictn > 0 && fi->fddictx != NULL)
323 fddictx = fi->fddictx[ix];
324 if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
325 fddict = fi->ddict + fddictx;
332 uint32_t rpmfiFNlinkIndex(rpmfi fi, int ix)
336 if (fi != NULL && ix >= 0 && ix < 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[ix];
340 rpm_rdev_t frdev = fi->frdevs[ix];
343 for (j = 0; j < fi->fc; j++) {
344 if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
352 rpm_time_t rpmfiFMtimeIndex(rpmfi fi, int ix)
354 rpm_time_t fmtime = 0;
356 if (fi != NULL && ix >= 0 && ix < fi->fc) {
357 if (fi->fmtimes != NULL)
358 fmtime = fi->fmtimes[ix];
363 const char * rpmfiFUserIndex(rpmfi fi, int ix)
365 const char * fuser = NULL;
367 if (fi != NULL && ix >= 0 && ix < fi->fc) {
368 if (fi->fuser != NULL)
369 fuser = rpmstrPoolStr(fi->pool, fi->fuser[ix]);
374 const char * rpmfiFGroupIndex(rpmfi fi, int ix)
376 const char * fgroup = NULL;
378 if (fi != NULL && ix >= 0 && ix < fi->fc) {
379 if (fi->fgroup != NULL)
380 fgroup = rpmstrPoolStr(fi->pool, fi->fgroup[ix]);
385 const char * rpmfiFCapsIndex(rpmfi fi, int ix)
387 const char *fcaps = NULL;
388 if (fi != NULL && ix >= 0 && ix < fi->fc) {
389 fcaps = fi->fcaps ? fi->fcaps[ix] : "";
394 const char * rpmfiFLangsIndex(rpmfi fi, int ix)
396 const char *flangs = NULL;
397 if (fi != NULL && fi->flangs != NULL && ix >= 0 && ix < fi->fc) {
398 flangs = rpmstrPoolStr(fi->pool, fi->flangs[ix]);
403 struct fingerPrint_s *rpmfiFps(rpmfi fi)
405 return (fi != NULL) ? fi->fps : NULL;
408 int rpmfiNext(rpmfi fi)
412 if (fi != NULL && ++fi->i >= 0) {
413 if (fi->i < fi->fc) {
416 fi->j = fi->dil[fi->i];
424 rpmfi rpmfiInit(rpmfi fi, int fx)
427 if (fx >= 0 && fx < fi->fc) {
436 int rpmfiNextD(rpmfi fi)
440 if (fi != NULL && ++fi->j >= 0) {
450 rpmfi rpmfiInitD(rpmfi fi, int dx)
453 if (dx >= 0 && dx < fi->fc)
463 * Identify a file type.
464 * @param ft file type
465 * @return string to identify a file type
468 const char * ftstring (rpmFileTypes ft)
471 case XDIR: return "directory";
472 case CDEV: return "char dev";
473 case BDEV: return "block dev";
474 case LINK: return "link";
475 case SOCK: return "sock";
476 case PIPE: return "fifo/pipe";
477 case REG: return "file";
478 default: return "unknown file type";
482 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
484 if (S_ISDIR(mode)) return XDIR;
485 if (S_ISCHR(mode)) return CDEV;
486 if (S_ISBLK(mode)) return BDEV;
487 if (S_ISLNK(mode)) return LINK;
488 if (S_ISSOCK(mode)) return SOCK;
489 if (S_ISFIFO(mode)) return PIPE;
493 int rpmfiCompareIndex(rpmfi afi, int aix, rpmfi bfi, int bix)
495 mode_t amode = rpmfiFModeIndex(afi, aix);
496 mode_t bmode = rpmfiFModeIndex(bfi, bix);
497 rpmFileTypes awhat = rpmfiWhatis(amode);
499 if ((rpmfiFFlagsIndex(afi, aix) & RPMFILE_GHOST) ||
500 (rpmfiFFlagsIndex(bfi, bix) & RPMFILE_GHOST)) return 0;
502 if (amode != bmode) return 1;
504 if (awhat == LINK || awhat == REG) {
505 if (rpmfiFSizeIndex(afi, aix) != rpmfiFSizeIndex(bfi, bix))
509 if (!rstreq(rpmfiFUserIndex(afi, aix), rpmfiFUserIndex(bfi, bix)))
511 if (!rstreq(rpmfiFGroupIndex(afi, aix), rpmfiFGroupIndex(bfi, bix)))
515 const char * alink = rpmfiFLinkIndex(afi, aix);
516 const char * blink = rpmfiFLinkIndex(bfi, bix);
517 if (alink == blink) return 0;
518 if (alink == NULL) return 1;
519 if (blink == NULL) return -1;
520 return strcmp(alink, blink);
521 } else if (awhat == REG) {
522 size_t adiglen, bdiglen;
524 const unsigned char * adigest, * bdigest;
525 adigest = rpmfiFDigestIndex(afi, aix, &aalgo, &adiglen);
526 bdigest = rpmfiFDigestIndex(bfi, bix, &balgo, &bdiglen);
527 if (adigest == bdigest) return 0;
528 if (adigest == NULL) return 1;
529 if (bdigest == NULL) return -1;
530 /* can't meaningfully compare different hash types */
531 if (aalgo != balgo || adiglen != bdiglen) return -1;
532 return memcmp(adigest, bdigest, adiglen);
533 } else if (awhat == CDEV || awhat == BDEV) {
534 if (rpmfiFRdevIndex(afi, aix) != rpmfiFRdevIndex(bfi, bix))
541 rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix,
544 char * fn = rpmfiFNIndex(nfi, nix);
545 rpmfileAttrs newFlags = rpmfiFFlagsIndex(nfi, nix);
547 rpmFileTypes dbWhat, newWhat, diskWhat;
549 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
550 int action = FA_CREATE; /* assume we can create */
552 /* If the new file is a ghost, leave whatever might be on disk alone. */
553 if (newFlags & RPMFILE_GHOST) {
558 if (lstat(fn, &sb)) {
560 * The file doesn't exist on the disk. Create it unless the new
561 * package has marked it as missingok, or allfiles is requested.
563 if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
564 rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
573 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
574 dbWhat = rpmfiWhatis(rpmfiFModeIndex(ofi, oix));
575 newWhat = rpmfiWhatis(rpmfiFModeIndex(nfi, nix));
578 * This order matters - we'd prefer to CREATE the file if at all
579 * possible in case something else (like the timestamp) has changed.
580 * Only regular files and symlinks might need a backup, everything
581 * else falls through here with FA_CREATE.
583 memset(buffer, 0, sizeof(buffer));
586 size_t odiglen, ndiglen;
587 const unsigned char * odigest, * ndigest;
589 /* See if the file on disk is identical to the one in old pkg */
590 odigest = rpmfiFDigestIndex(ofi, oix, &oalgo, &odiglen);
591 if (diskWhat == REG) {
592 if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL))
593 goto exit; /* assume file has been removed */
594 if (odigest && memcmp(odigest, buffer, odiglen) == 0)
595 goto exit; /* unmodified config file, replace. */
598 /* See if the file on disk is identical to the one in new pkg */
599 ndigest = rpmfiFDigestIndex(nfi, nix, &nalgo, &ndiglen);
600 if (diskWhat == REG && newWhat == REG) {
601 /* hash algo changed in new, recalculate digest */
603 if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL))
604 goto exit; /* assume file has been removed */
605 if (ndigest && memcmp(ndigest, buffer, ndiglen) == 0)
606 goto exit; /* file identical in new, replace. */
609 /* If file can be determined identical in old and new pkg, let it be */
610 if (newWhat == REG && oalgo == nalgo && odiglen == ndiglen) {
611 if (odigest && ndigest && memcmp(odigest, ndigest, odiglen) == 0) {
612 action = FA_SKIP; /* identical file, dont bother */
617 /* ...but otherwise a backup will be needed */
619 } else if (dbWhat == LINK) {
620 const char * oFLink, * nFLink;
622 /* See if the link on disk is identical to the one in old pkg */
623 oFLink = rpmfiFLinkIndex(ofi, oix);
624 if (diskWhat == LINK) {
625 ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
627 goto exit; /* assume file has been removed */
628 buffer[link_len] = '\0';
629 if (oFLink && rstreq(oFLink, buffer))
630 goto exit; /* unmodified config file, replace. */
633 /* See if the link on disk is identical to the one in new pkg */
634 nFLink = rpmfiFLinkIndex(nfi, nix);
635 if (diskWhat == LINK && newWhat == LINK) {
636 if (nFLink && rstreq(nFLink, buffer))
637 goto exit; /* unmodified config file, replace. */
640 /* If link is identical in old and new pkg, let it be */
641 if (newWhat == LINK && oFLink && nFLink && rstreq(oFLink, nFLink)) {
642 action = FA_SKIP; /* identical file, don't bother. */
646 /* ...but otherwise a backup will be needed */
655 int rpmfiConfigConflictIndex(rpmfi fi, int ix)
658 rpmfileAttrs flags = rpmfiFFlagsIndex(fi, ix);
660 rpmFileTypes newWhat, diskWhat;
664 /* Non-configs are not config conflicts. */
665 if (!(flags & RPMFILE_CONFIG))
668 /* Only links and regular files can be %config, this is kinda moot */
669 /* XXX: Why are we returning 1 here? */
670 newWhat = rpmfiWhatis(rpmfiFModeIndex(fi, ix));
671 if (newWhat != LINK && newWhat != REG)
674 /* If it's not on disk, there's nothing to be saved */
675 fn = rpmfiFNIndex(fi, ix);
680 * Preserve legacy behavior: an existing %ghost %config is considered
681 * "modified" but unlike regular %config, its never removed and
682 * never backed up. Whether this actually makes sense is a whole
683 * another question, but this is very long-standing behavior that
684 * people might be depending on. The resulting FA_ALTNAME etc action
685 * is special-cased in FSM to avoid actually creating backups on ghosts.
687 if (flags & RPMFILE_GHOST) {
692 /* Files of different types obviously are not identical */
693 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
694 if (diskWhat != newWhat) {
699 /* Files of different sizes obviously are not identical */
700 if (rpmfiFSizeIndex(fi, ix) != sb.st_size) {
705 memset(buffer, 0, sizeof(buffer));
706 if (newWhat == REG) {
709 const unsigned char *ndigest = rpmfiFDigestIndex(fi,ix, &algo, &diglen);
710 if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL))
711 goto exit; /* assume file has been removed */
712 if (ndigest && memcmp(ndigest, buffer, diglen) == 0)
713 goto exit; /* unmodified config file */
714 } else /* newWhat == LINK */ {
716 ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
718 goto exit; /* assume file has been removed */
719 buffer[link_len] = '\0';
720 nFLink = rpmfiFLinkIndex(fi, ix);
721 if (nFLink && rstreq(nFLink, buffer))
722 goto exit; /* unmodified config file */
732 static char **duparray(char ** src, int size)
734 char **dest = xmalloc((size+1) * sizeof(*dest));
735 for (int i = 0; i < size; i++) {
736 dest[i] = xstrdup(src[i]);
742 static int addPrefixes(Header h, rpmRelocation *relocations, int numRelocations)
744 struct rpmtd_s validRelocs;
745 const char *validprefix;
746 const char ** actualRelocations;
749 headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM);
751 * If no relocations are specified (usually the case), then return the
752 * original header. If there are prefixes, however, then INSTPREFIXES
753 * should be added for RPM_INSTALL_PREFIX environ variables in scriptlets,
754 * but, since relocateFileList() can be called more than once for
755 * the same header, don't bother if already present.
757 if (relocations == NULL || numRelocations == 0) {
758 if (rpmtdCount(&validRelocs) > 0) {
759 if (!headerIsEntry(h, RPMTAG_INSTPREFIXES)) {
760 rpmtdSetTag(&validRelocs, RPMTAG_INSTPREFIXES);
761 headerPut(h, &validRelocs, HEADERPUT_DEFAULT);
763 rpmtdFreeData(&validRelocs);
768 actualRelocations = xmalloc(rpmtdCount(&validRelocs) * sizeof(*actualRelocations));
769 rpmtdInit(&validRelocs);
770 while ((validprefix = rpmtdNextString(&validRelocs))) {
772 for (j = 0; j < numRelocations; j++) {
773 if (relocations[j].oldPath == NULL || /* XXX can't happen */
774 !rstreq(validprefix, relocations[j].oldPath))
776 /* On install, a relocate to NULL means skip the path. */
777 if (relocations[j].newPath) {
778 actualRelocations[numActual] = relocations[j].newPath;
783 if (j == numRelocations) {
784 actualRelocations[numActual] = validprefix;
788 rpmtdFreeData(&validRelocs);
791 headerPutStringArray(h, RPMTAG_INSTPREFIXES, actualRelocations, numActual);
793 free(actualRelocations);
797 static void saveRelocs(Header h, rpmtd bnames, rpmtd dnames, rpmtd dindexes)
800 headerGet(h, RPMTAG_BASENAMES, &td, HEADERGET_MINMEM);
801 rpmtdSetTag(&td, RPMTAG_ORIGBASENAMES);
802 headerPut(h, &td, HEADERPUT_DEFAULT);
805 headerGet(h, RPMTAG_DIRNAMES, &td, HEADERGET_MINMEM);
806 rpmtdSetTag(&td, RPMTAG_ORIGDIRNAMES);
807 headerPut(h, &td, HEADERPUT_DEFAULT);
810 headerGet(h, RPMTAG_DIRINDEXES, &td, HEADERGET_MINMEM);
811 rpmtdSetTag(&td, RPMTAG_ORIGDIRINDEXES);
812 headerPut(h, &td, HEADERPUT_DEFAULT);
815 headerMod(h, bnames);
816 headerMod(h, dnames);
817 headerMod(h, dindexes);
820 void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations,
823 static int _printed = 0;
826 uint32_t * dirIndexes;
827 rpm_count_t fileCount, dirCount;
831 int haveRelocatedBase = 0;
834 struct rpmtd_s bnames, dnames, dindexes, fmodes;
836 addPrefixes(h, relocations, numRelocations);
840 rpmlog(RPMLOG_DEBUG, "========== relocations\n");
841 for (i = 0; i < numRelocations; i++) {
842 if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
843 if (relocations[i].newPath == NULL)
844 rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n",
845 i, relocations[i].oldPath);
847 rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
848 i, relocations[i].oldPath, relocations[i].newPath);
852 for (i = 0; i < numRelocations; i++) {
853 if (relocations[i].newPath == NULL) continue;
854 size_t len = strlen(relocations[i].newPath);
855 if (len > maxlen) maxlen = len;
858 headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM);
859 headerGet(h, RPMTAG_DIRINDEXES, &dindexes, HEADERGET_ALLOC);
860 headerGet(h, RPMTAG_DIRNAMES, &dnames, HEADERGET_MINMEM);
861 headerGet(h, RPMTAG_FILEMODES, &fmodes, HEADERGET_MINMEM);
862 /* TODO XXX ugh.. use rpmtd iterators & friends instead */
863 baseNames = bnames.data;
864 dirIndexes = dindexes.data;
865 fileCount = rpmtdCount(&bnames);
866 dirCount = rpmtdCount(&dnames);
867 /* XXX TODO: use rpmtdDup() instead */
868 dirNames = dnames.data = duparray(dnames.data, dirCount);
869 dnames.flags |= RPMTD_PTR_ALLOCED;
872 * For all relocations, we go through sorted file/relocation lists
873 * backwards so that /usr/local relocations take precedence over /usr
877 /* Relocate individual paths. */
879 for (i = fileCount - 1; i >= 0; i--) {
883 size_t len = maxlen +
884 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
885 if (len >= fileAlloced) {
886 fileAlloced = len * 2;
887 fn = xrealloc(fn, fileAlloced);
890 assert(fn != NULL); /* XXX can't happen */
892 fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
895 * See if this file path needs relocating.
898 * XXX FIXME: Would a bsearch of the (already sorted)
899 * relocation list be a good idea?
901 for (j = numRelocations - 1; j >= 0; j--) {
902 if (relocations[j].oldPath == NULL) /* XXX can't happen */
904 len = !rstreq(relocations[j].oldPath, "/")
905 ? strlen(relocations[j].oldPath)
911 * Only subdirectories or complete file paths may be relocated. We
912 * don't check for '\0' as our directory names all end in '/'.
914 if (!(fn[len] == '/' || fnlen == len))
917 if (!rstreqn(relocations[j].oldPath, fn, len))
923 rpmtdSetIndex(&fmodes, i);
924 ft = rpmfiWhatis(rpmtdGetNumber(&fmodes));
926 /* On install, a relocate to NULL means skip the path. */
927 if (relocations[j].newPath == NULL) {
929 /* Start with the parent, looking for directory to exclude. */
930 for (j = dirIndexes[i]; j < dirCount; j++) {
931 len = strlen(dirNames[j]) - 1;
932 while (len > 0 && dirNames[j][len-1] == '/') len--;
935 if (!rstreqn(fn, dirNames[j], fnlen))
940 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
941 rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
946 /* Relocation on full paths only, please. */
947 if (fnlen != len) continue;
949 rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
950 fn, relocations[j].newPath);
953 strcpy(fn, relocations[j].newPath);
954 { char * te = strrchr(fn, '/');
956 if (te > fn) te++; /* root is special */
959 te = fn + strlen(fn);
960 if (!rstreq(baseNames[i], te)) { /* basename changed too? */
961 if (!haveRelocatedBase) {
962 /* XXX TODO: use rpmtdDup() instead */
963 bnames.data = baseNames = duparray(baseNames, fileCount);
964 bnames.flags |= RPMTD_PTR_ALLOCED;
965 haveRelocatedBase = 1;
968 baseNames[i] = xstrdup(te);
970 *te = '\0'; /* terminate new directory name */
973 /* Does this directory already exist in the directory list? */
974 for (j = 0; j < dirCount; j++) {
975 if (fnlen != strlen(dirNames[j]))
977 if (!rstreqn(fn, dirNames[j], fnlen))
987 /* Creating new paths is a pita */
988 dirNames = dnames.data = xrealloc(dnames.data,
989 sizeof(*dirNames) * (dirCount + 1));
991 dirNames[dirCount] = xstrdup(fn);
992 dirIndexes[i] = dirCount;
997 /* Finish off by relocating directories. */
998 for (i = dirCount - 1; i >= 0; i--) {
999 for (j = numRelocations - 1; j >= 0; j--) {
1001 if (relocations[j].oldPath == NULL) /* XXX can't happen */
1003 size_t len = !rstreq(relocations[j].oldPath, "/")
1004 ? strlen(relocations[j].oldPath)
1007 if (len && !rstreqn(relocations[j].oldPath, dirNames[i], len))
1011 * Only subdirectories or complete file paths may be relocated. We
1012 * don't check for '\0' as our directory names all end in '/'.
1014 if (dirNames[i][len] != '/')
1017 if (relocations[j].newPath) { /* Relocate the path */
1019 rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
1020 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
1021 (void) rpmCleanPath(t);
1024 rpmlog(RPMLOG_DEBUG,
1025 "relocating directory %s to %s\n", dirNames[i], t);
1033 /* Save original filenames in header and replace (relocated) filenames. */
1035 saveRelocs(h, &bnames, &dnames, &dindexes);
1038 rpmtdFreeData(&bnames);
1039 rpmtdFreeData(&dnames);
1040 rpmtdFreeData(&dindexes);
1041 rpmtdFreeData(&fmodes);
1045 rpmfi rpmfiFree(rpmfi fi)
1047 if (fi == NULL) return NULL;
1050 return rpmfiUnlink(fi);
1053 fi->bnid = _free(fi->bnid);
1054 fi->dnid = _free(fi->dnid);
1055 fi->dil = _free(fi->dil);
1057 fi->flinks = _free(fi->flinks);
1058 fi->flangs = _free(fi->flangs);
1059 fi->digests = _free(fi->digests);
1060 fi->fcaps = _free(fi->fcaps);
1062 fi->cdict = _free(fi->cdict);
1064 fi->fuser = _free(fi->fuser);
1065 fi->fgroup = _free(fi->fgroup);
1067 fi->fstates = _free(fi->fstates);
1068 fi->fps = _free(fi->fps);
1070 fi->pool = rpmstrPoolFree(fi->pool);
1072 /* these point to header memory if KEEPHEADER is used, dont free */
1073 if (!(fi->fiflags & RPMFI_KEEPHEADER) && fi->h == NULL) {
1074 fi->fmtimes = _free(fi->fmtimes);
1075 fi->fmodes = _free(fi->fmodes);
1076 fi->fflags = _free(fi->fflags);
1077 fi->vflags = _free(fi->vflags);
1078 fi->fsizes = _free(fi->fsizes);
1079 fi->frdevs = _free(fi->frdevs);
1080 fi->finodes = _free(fi->finodes);
1082 fi->fcolors = _free(fi->fcolors);
1083 fi->fcdictx = _free(fi->fcdictx);
1084 fi->ddict = _free(fi->ddict);
1085 fi->fddictx = _free(fi->fddictx);
1086 fi->fddictn = _free(fi->fddictn);
1091 fi->fn = _free(fi->fn);
1092 fi->apath = _free(fi->apath);
1094 fi->replacedSizes = _free(fi->replacedSizes);
1096 fi->h = headerFree(fi->h);
1098 (void) rpmfiUnlink(fi);
1099 memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
1105 static rpmsid * tag2pool(rpmstrPool pool, Header h, rpmTag tag)
1107 rpmsid *sids = NULL;
1109 if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
1110 sids = rpmtdToPool(&td, pool);
1116 /* validate a indexed tag data triplet (such as file bn/dn/dx) */
1117 static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd)
1120 uint32_t xc = rpmtdCount(xd);
1121 uint32_t yc = rpmtdCount(yd);
1122 uint32_t zc = rpmtdCount(zd);
1124 /* check that the amount of data in each is sane */
1125 if (xc > 0 && yc > 0 && yc <= xc && zc == xc) {
1127 /* ...and that the indexes are within bounds */
1128 while ((i = rpmtdNextUint32(zd))) {
1132 /* unless the loop runs to finish, the data is broken */
1138 #define _hgfi(_h, _tag, _td, _flags, _data) \
1139 if (headerGet((_h), (_tag), (_td), (_flags))) \
1142 static int rpmfiPopulate(rpmfi fi, Header h, rpmfiFlags flags)
1144 headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ?
1145 HEADERGET_MINMEM : HEADERGET_ALLOC;
1146 headerGetFlags defFlags = HEADERGET_ALLOC;
1147 struct rpmtd_s fdigests, digalgo, td;
1150 /* XXX TODO: all these should be sanity checked, ugh... */
1151 if (!(flags & RPMFI_NOFILEMODES))
1152 _hgfi(h, RPMTAG_FILEMODES, &td, scareFlags, fi->fmodes);
1153 if (!(flags & RPMFI_NOFILEFLAGS))
1154 _hgfi(h, RPMTAG_FILEFLAGS, &td, scareFlags, fi->fflags);
1155 if (!(flags & RPMFI_NOFILEVERIFYFLAGS))
1156 _hgfi(h, RPMTAG_FILEVERIFYFLAGS, &td, scareFlags, fi->vflags);
1157 if (!(flags & RPMFI_NOFILESIZES))
1158 _hgfi(h, RPMTAG_FILESIZES, &td, scareFlags, fi->fsizes);
1160 if (!(flags & RPMFI_NOFILECOLORS))
1161 _hgfi(h, RPMTAG_FILECOLORS, &td, scareFlags, fi->fcolors);
1163 if (!(flags & RPMFI_NOFILECLASS)) {
1164 _hgfi(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
1165 fi->ncdict = rpmtdCount(&td);
1166 _hgfi(h, RPMTAG_FILECLASS, &td, scareFlags, fi->fcdictx);
1168 if (!(flags & RPMFI_NOFILEDEPS)) {
1169 _hgfi(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
1170 fi->nddict = rpmtdCount(&td);
1171 _hgfi(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
1172 _hgfi(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
1175 if (!(flags & RPMFI_NOFILESTATES))
1176 _hgfi(h, RPMTAG_FILESTATES, &td, defFlags, fi->fstates);
1178 if (!(flags & RPMFI_NOFILECAPS))
1179 _hgfi(h, RPMTAG_FILECAPS, &td, defFlags, fi->fcaps);
1181 if (!(flags & RPMFI_NOFILELINKTOS))
1182 fi->flinks = tag2pool(fi->pool, h, RPMTAG_FILELINKTOS);
1183 /* FILELANGS are only interesting when installing */
1184 if ((headerGetInstance(h) == 0) && !(flags & RPMFI_NOFILELANGS))
1185 fi->flangs = tag2pool(fi->pool, h, RPMTAG_FILELANGS);
1187 /* See if the package has non-md5 file digests */
1188 fi->digestalgo = PGPHASHALGO_MD5;
1189 if (headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM)) {
1190 uint32_t *algo = rpmtdGetUint32(&digalgo);
1191 /* Hmm, what to do with unknown digest algorithms? */
1192 if (algo && rpmDigestLength(*algo) != 0) {
1193 fi->digestalgo = *algo;
1198 /* grab hex digests from header and store in binary format */
1199 if (!(flags & RPMFI_NOFILEDIGESTS) &&
1200 headerGet(h, RPMTAG_FILEDIGESTS, &fdigests, HEADERGET_MINMEM)) {
1201 const char *fdigest;
1202 size_t diglen = rpmDigestLength(fi->digestalgo);
1203 fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
1205 while ((fdigest = rpmtdNextString(&fdigests))) {
1206 if (!(fdigest && *fdigest != '\0')) {
1207 memset(t, 0, diglen);
1211 for (int j = 0; j < diglen; j++, t++, fdigest += 2)
1212 *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
1214 rpmtdFreeData(&fdigests);
1217 /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
1218 if (!(flags & RPMFI_NOFILEMTIMES))
1219 _hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
1220 if (!(flags & RPMFI_NOFILERDEVS))
1221 _hgfi(h, RPMTAG_FILERDEVS, &td, scareFlags, fi->frdevs);
1222 if (!(flags & RPMFI_NOFILEINODES))
1223 _hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
1225 if (!(flags & RPMFI_NOFILEUSER))
1226 fi->fuser = tag2pool(fi->pool, h, RPMTAG_FILEUSERNAME);
1227 if (!(flags & RPMFI_NOFILEGROUP))
1228 fi->fgroup = tag2pool(fi->pool, h, RPMTAG_FILEGROUPNAME);
1230 /* TODO: validate and return a real error */
1234 rpmfi rpmfiNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
1236 rpmfi fi = xcalloc(1, sizeof(*fi));
1237 struct rpmtd_s bn, dn, dx;
1239 fi->magic = RPMFIMAGIC;
1241 fi->fiflags = flags;
1244 * Grab and validate file triplet data. Headers with no files simply
1245 * fall through here and an empty file set is returned.
1247 if (headerGet(h, RPMTAG_BASENAMES, &bn, HEADERGET_MINMEM)) {
1248 headerGet(h, RPMTAG_DIRNAMES, &dn, HEADERGET_MINMEM);
1249 headerGet(h, RPMTAG_DIRINDEXES, &dx, HEADERGET_ALLOC);
1251 if (indexSane(&bn, &dn, &dx)) {
1252 /* private or shared pool? */
1253 fi->pool = (pool != NULL) ? rpmstrPoolLink(pool) :
1256 /* init the file triplet data */
1257 fi->fc = rpmtdCount(&bn);
1258 fi->dc = rpmtdCount(&dn);
1259 fi->bnid = rpmtdToPool(&bn, fi->pool);
1260 fi->dnid = rpmtdToPool(&dn, fi->pool);
1261 /* steal index data from the td (pooh...) */
1265 /* populate the rest of the stuff */
1266 rpmfiPopulate(fi, h, flags);
1268 /* freeze the pool to save memory, but only if private pool */
1269 if (fi->pool != pool)
1270 rpmstrPoolFreeze(fi->pool, 0);
1272 fi->h = (fi->fiflags & RPMFI_KEEPHEADER) ? headerLink(h) : NULL;
1274 /* broken data, free and return NULL */
1282 return rpmfiLink(fi);
1285 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTagVal tagN, rpmfiFlags flags)
1287 return rpmfiNewPool(NULL, h, tagN, flags);
1290 void rpmfiSetFReplacedSizeIndex(rpmfi fi, int ix, rpm_loff_t newsize)
1292 if (fi != NULL && ix >= 0 && ix < fi->fc) {
1293 if (fi->replacedSizes == NULL) {
1294 fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
1296 /* XXX watch out, replacedSizes is not rpm_loff_t (yet) */
1297 fi->replacedSizes[ix] = (rpm_off_t) newsize;
1301 rpm_loff_t rpmfiFReplacedSizeIndex(rpmfi fi, int ix)
1303 rpm_loff_t rsize = 0;
1304 if (fi != NULL && ix >= 0 && ix < fi->fc) {
1305 if (fi->replacedSizes) {
1306 rsize = fi->replacedSizes[ix];
1312 void rpmfiFpLookup(rpmfi fi, fingerPrintCache fpc)
1314 /* This can get called twice (eg yum), scratch former results and redo */
1318 fi->fps = fpLookupList(fpc, fi->pool,
1319 fi->dnid, fi->bnid, fi->dil, fi->fc);
1324 * Generate iterator accessors function wrappers, these do nothing but
1325 * call the corresponding rpmfiFooIndex(fi, fi->[ij])
1328 #define RPMFI_ITERFUNC(TYPE, NAME, IXV) \
1329 TYPE rpmfi ## NAME(rpmfi fi) { return rpmfi ## NAME ## Index(fi, fi ? fi->IXV : -1); }
1331 RPMFI_ITERFUNC(rpmsid, BNId, i)
1332 RPMFI_ITERFUNC(rpmsid, DNId, j)
1333 RPMFI_ITERFUNC(const char *, BN, i)
1334 RPMFI_ITERFUNC(const char *, DN, j)
1335 RPMFI_ITERFUNC(const char *, FLink, i)
1336 RPMFI_ITERFUNC(const char *, FUser, i)
1337 RPMFI_ITERFUNC(const char *, FGroup, i)
1338 RPMFI_ITERFUNC(const char *, FCaps, i)
1339 RPMFI_ITERFUNC(const char *, FLangs, i)
1340 RPMFI_ITERFUNC(const char *, FClass, i)
1341 RPMFI_ITERFUNC(rpmfileState, FState, i)
1342 RPMFI_ITERFUNC(rpmfileAttrs, FFlags, i)
1343 RPMFI_ITERFUNC(rpmVerifyAttrs, VFlags, i)
1344 RPMFI_ITERFUNC(rpm_mode_t, FMode, i)
1345 RPMFI_ITERFUNC(rpm_rdev_t, FRdev, i)
1346 RPMFI_ITERFUNC(rpm_time_t, FMtime, i)
1347 RPMFI_ITERFUNC(rpm_ino_t, FInode, i)
1348 RPMFI_ITERFUNC(rpm_loff_t, FSize, i)
1349 RPMFI_ITERFUNC(rpm_color_t, FColor, i)
1350 RPMFI_ITERFUNC(uint32_t, FNlink, i)
1352 const char * rpmfiFN(rpmfi fi)
1354 const char *fn = ""; /* preserve behavior on errors */
1357 fi->fn = rpmfiFNIndex(fi, fi->i);
1364 const unsigned char * rpmfiFDigest(rpmfi fi, int *algo, size_t *len)
1366 return rpmfiFDigestIndex(fi, fi ? fi->i : -1, algo, len);
1369 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
1371 return rpmfiFDependsIndex(fi, fi ? fi->i : -1, fddictp);
1374 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
1376 return rpmfiCompareIndex(afi, afi ? afi->i : -1, bfi, bfi ? bfi->i : -1);
1379 rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
1381 return rpmfiDecideFateIndex(ofi, ofi ? ofi->i : -1,
1382 nfi, nfi ? nfi->i : -1,
1386 int rpmfiConfigConflict(const rpmfi fi)
1388 return rpmfiConfigConflictIndex(fi, fi ? fi->i : -1);
1391 rpmstrPool rpmfiPool(rpmfi fi)
1393 return (fi != NULL) ? fi->pool : NULL;