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) {
121 fi->fn = xmalloc(fi->fnlen);
124 t = stpcpy(t, fi->dnl[fi->dil[fi->i]]);
125 t = stpcpy(t, fi->bnl[fi->i]);
130 rpmfileAttrs rpmfiFFlags(rpmfi fi)
132 rpmfileAttrs FFlags = 0;
134 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
135 if (fi->fflags != NULL)
136 FFlags = fi->fflags[fi->i];
141 rpmVerifyAttrs rpmfiVFlags(rpmfi fi)
143 rpmVerifyAttrs VFlags = 0;
145 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
146 if (fi->vflags != NULL)
147 VFlags = fi->vflags[fi->i];
152 rpm_mode_t rpmfiFMode(rpmfi fi)
154 rpm_mode_t fmode = 0;
156 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
157 if (fi->fmodes != NULL)
158 fmode = fi->fmodes[fi->i];
163 rpmfileState rpmfiFState(rpmfi fi)
165 rpmfileState fstate = RPMFILE_STATE_MISSING;
167 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
168 if (fi->fstates != NULL)
169 fstate = fi->fstates[fi->i];
174 const unsigned char * rpmfiMD5(rpmfi fi)
176 const unsigned char *digest;
177 pgpHashAlgo algo = 0;
179 digest = rpmfiFDigest(fi, &algo, NULL);
180 return (algo == PGPHASHALGO_MD5) ? digest : NULL;
183 const unsigned char * rpmfiFDigest(rpmfi fi, pgpHashAlgo *algo, size_t *len)
185 const unsigned char *digest = NULL;
187 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
188 size_t diglen = rpmDigestLength(fi->digestalgo);
189 if (fi->digests != NULL)
190 digest = fi->digests + (diglen * fi->i);
194 *algo = fi->digestalgo;
199 char * rpmfiFDigestHex(rpmfi fi, pgpHashAlgo *algo)
202 char *fdigest = NULL;
203 const unsigned char *digest = rpmfiFDigest(fi, algo, &diglen);
205 fdigest = pgpHexStr(digest, diglen);
210 const char * rpmfiFLink(rpmfi fi)
212 const char * flink = NULL;
214 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
215 if (fi->flinks != NULL)
216 flink = fi->flinks[fi->i];
221 rpm_off_t rpmfiFSize(rpmfi fi)
225 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
226 if (fi->fsizes != NULL)
227 fsize = fi->fsizes[fi->i];
232 rpm_rdev_t rpmfiFRdev(rpmfi fi)
234 rpm_rdev_t frdev = 0;
236 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
237 if (fi->frdevs != NULL)
238 frdev = fi->frdevs[fi->i];
243 rpm_ino_t rpmfiFInode(rpmfi fi)
245 rpm_ino_t finode = 0;
247 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
248 if (fi->finodes != NULL)
249 finode = fi->finodes[fi->i];
254 rpm_color_t rpmfiColor(rpmfi fi)
256 rpm_color_t color = 0;
259 /* XXX ignore all but lsnibble for now. */
260 color = fi->color & 0xf;
264 rpm_color_t rpmfiFColor(rpmfi fi)
266 rpm_color_t fcolor = 0;
268 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
269 if (fi->fcolors != NULL)
270 /* XXX ignore all but lsnibble for now. */
271 fcolor = (fi->fcolors[fi->i] & 0x0f);
276 const char * rpmfiFClass(rpmfi fi)
278 const char * fclass = NULL;
281 if (fi != NULL && fi->fcdictx != NULL && fi->i >= 0 && fi->i < fi->fc) {
282 cdictx = fi->fcdictx[fi->i];
283 if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
284 fclass = fi->cdict[cdictx];
289 const char * rpmfiFContext(rpmfi fi)
291 const char * fcontext = NULL;
293 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
294 if (fi->fcontexts != NULL)
295 fcontext = fi->fcontexts[fi->i];
300 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
304 const uint32_t * fddict = NULL;
306 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
307 if (fi->fddictn != NULL)
308 fddictn = fi->fddictn[fi->i];
309 if (fddictn > 0 && fi->fddictx != NULL)
310 fddictx = fi->fddictx[fi->i];
311 if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
312 fddict = fi->ddict + fddictx;
319 uint32_t rpmfiFNlink(rpmfi fi)
323 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
324 /* XXX rpm-2.3.12 has not RPMTAG_FILEINODES */
325 if (fi->finodes && fi->frdevs) {
326 rpm_ino_t finode = fi->finodes[fi->i];
327 rpm_rdev_t frdev = fi->frdevs[fi->i];
330 for (j = 0; j < fi->fc; j++) {
331 if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
339 rpm_time_t rpmfiFMtime(rpmfi fi)
341 rpm_time_t fmtime = 0;
343 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
344 if (fi->fmtimes != NULL)
345 fmtime = fi->fmtimes[fi->i];
350 const char * rpmfiFUser(rpmfi fi)
352 const char * fuser = NULL;
354 /* XXX add support for ancient RPMTAG_FILEUIDS? */
355 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
356 if (fi->fuser != NULL)
357 fuser = fi->fuser[fi->i];
362 const char * rpmfiFGroup(rpmfi fi)
364 const char * fgroup = NULL;
366 /* XXX add support for ancient RPMTAG_FILEGIDS? */
367 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
368 if (fi->fgroup != NULL)
369 fgroup = fi->fgroup[fi->i];
374 int rpmfiNext(rpmfi fi)
378 if (fi != NULL && ++fi->i >= 0) {
379 if (fi->i < fi->fc) {
382 fi->j = fi->dil[fi->i];
386 if (_rpmfi_debug < 0 && i != -1)
387 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] : ""));
394 rpmfi rpmfiInit(rpmfi fi, int fx)
397 if (fx >= 0 && fx < fi->fc) {
406 int rpmfiNextD(rpmfi fi)
410 if (fi != NULL && ++fi->j >= 0) {
416 if (_rpmfi_debug < 0 && j != -1)
417 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, (fi->Type ? fi->Type : "?Type?"), j);
424 rpmfi rpmfiInitD(rpmfi fi, int dx)
427 if (dx >= 0 && dx < fi->fc)
437 * Identify a file type.
438 * @param ft file type
439 * @return string to identify a file type
442 const char * ftstring (rpmFileTypes ft)
445 case XDIR: return "directory";
446 case CDEV: return "char dev";
447 case BDEV: return "block dev";
448 case LINK: return "link";
449 case SOCK: return "sock";
450 case PIPE: return "fifo/pipe";
451 case REG: return "file";
452 default: return "unknown file type";
456 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
458 if (S_ISDIR(mode)) return XDIR;
459 if (S_ISCHR(mode)) return CDEV;
460 if (S_ISBLK(mode)) return BDEV;
461 if (S_ISLNK(mode)) return LINK;
462 if (S_ISSOCK(mode)) return SOCK;
463 if (S_ISFIFO(mode)) return PIPE;
467 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
469 rpmFileTypes awhat = rpmfiWhatis(rpmfiFMode(afi));
470 rpmFileTypes bwhat = rpmfiWhatis(rpmfiFMode(bfi));
472 if ((rpmfiFFlags(afi) & RPMFILE_GHOST) ||
473 (rpmfiFFlags(bfi) & RPMFILE_GHOST)) return 0;
475 if (awhat != bwhat) return 1;
478 const char * alink = rpmfiFLink(afi);
479 const char * blink = rpmfiFLink(bfi);
480 if (alink == blink) return 0;
481 if (alink == NULL) return 1;
482 if (blink == NULL) return -1;
483 return strcmp(alink, blink);
484 } else if (awhat == REG) {
485 size_t adiglen, bdiglen;
486 pgpHashAlgo aalgo, balgo;
487 const unsigned char * adigest = rpmfiFDigest(afi, &aalgo, &adiglen);
488 const unsigned char * bdigest = rpmfiFDigest(bfi, &balgo, &bdiglen);
489 if (adigest == bdigest) return 0;
490 if (adigest == NULL) return 1;
491 if (bdigest == NULL) return -1;
492 /* can't meaningfully compare different hash types */
493 if (aalgo != balgo || adiglen != bdiglen) return -1;
494 return memcmp(adigest, bdigest, adiglen);
500 rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
502 const char * fn = rpmfiFN(nfi);
503 rpmfileAttrs newFlags = rpmfiFFlags(nfi);
505 rpmFileTypes dbWhat, newWhat, diskWhat;
507 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
509 if (lstat(fn, &sb)) {
511 * The file doesn't exist on the disk. Create it unless the new
512 * package has marked it as missingok, or allfiles is requested.
514 if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
515 rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
523 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
524 dbWhat = rpmfiWhatis(rpmfiFMode(ofi));
525 newWhat = rpmfiWhatis(rpmfiFMode(nfi));
528 * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
529 * them in older packages as well.
534 if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK)
536 else if (newWhat != dbWhat && diskWhat != dbWhat)
538 else if (dbWhat != newWhat)
540 else if (dbWhat != LINK && dbWhat != REG)
544 * This order matters - we'd prefer to CREATE the file if at all
545 * possible in case something else (like the timestamp) has changed.
547 memset(buffer, 0, sizeof(buffer));
549 pgpHashAlgo oalgo, nalgo;
550 size_t odiglen, ndiglen;
551 const unsigned char * odigest, * ndigest;
552 odigest = rpmfiFDigest(ofi, &oalgo, &odiglen);
553 if (diskWhat == REG) {
554 if (rpmDoDigest(oalgo, fn, 0,
555 (unsigned char *)buffer, NULL))
556 return FA_CREATE; /* assume file has been removed */
557 if (odigest && !memcmp(odigest, buffer, odiglen))
558 return FA_CREATE; /* unmodified config file, replace. */
560 ndigest = rpmfiFDigest(nfi, &nalgo, &ndiglen);
561 /* XXX can't compare different hash types, what should we do here? */
562 if (oalgo != nalgo || odiglen != ndiglen)
564 if (odigest && ndigest && !memcmp(odigest, ndigest, odiglen))
565 return FA_SKIP; /* identical file, don't bother. */
566 } else /* dbWhat == LINK */ {
567 const char * oFLink, * nFLink;
568 oFLink = rpmfiFLink(ofi);
569 if (diskWhat == LINK) {
570 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
571 return FA_CREATE; /* assume file has been removed */
572 if (oFLink && !strcmp(oFLink, buffer))
573 return FA_CREATE; /* unmodified config file, replace. */
575 nFLink = rpmfiFLink(nfi);
576 if (oFLink && nFLink && !strcmp(oFLink, nFLink))
577 return FA_SKIP; /* identical file, don't bother. */
581 * The config file on the disk has been modified, but
582 * the ones in the two packages are different. It would
583 * be nice if RPM was smart enough to at least try and
584 * merge the difference ala CVS, but...
589 int rpmfiConfigConflict(const rpmfi fi)
591 const char * fn = rpmfiFN(fi);
592 rpmfileAttrs flags = rpmfiFFlags(fi);
594 rpmFileTypes newWhat, diskWhat;
597 if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) {
601 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
602 newWhat = rpmfiWhatis(rpmfiFMode(fi));
604 if (newWhat != LINK && newWhat != REG)
607 if (diskWhat != newWhat)
610 memset(buffer, 0, sizeof(buffer));
611 if (newWhat == REG) {
614 const unsigned char *ndigest = rpmfiFDigest(fi, &algo, &diglen);
615 if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL))
616 return 0; /* assume file has been removed */
617 if (ndigest && !memcmp(ndigest, buffer, diglen))
618 return 0; /* unmodified config file */
619 } else /* newWhat == LINK */ {
621 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
622 return 0; /* assume file has been removed */
623 nFLink = rpmfiFLink(fi);
624 if (nFLink && !strcmp(nFLink, buffer))
625 return 0; /* unmodified config file */
631 const char * rpmfiTypeString(rpmfi fi)
633 switch(rpmteType(fi->te)) {
634 case TR_ADDED: return " install";
635 case TR_REMOVED: return " erase";
636 default: return "???";
640 static char **duparray(char ** src, int size)
642 char **dest = xmalloc((size+1) * sizeof(*dest));
643 for (int i = 0; i < size; i++) {
644 dest[i] = xstrdup(src[i]);
646 headerFreeData(src, RPM_STRING_ARRAY_TYPE);
650 static void * freearray(char **array, int size)
652 for (int i = 0; i < size; i++) {
660 * Relocate files in header.
661 * @todo multilib file dispositions need to be checked.
662 * @param ts transaction set
663 * @param fi transaction element file info
664 * @param origH package header
665 * @param actions file dispositions
666 * @return header with relocated files
669 Header relocateFileList(const rpmts ts, rpmfi fi,
670 Header origH, rpmFileAction * actions)
672 rpmte p = rpmtsRelocateElement(ts);
676 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
677 static int _printed = 0;
678 int allowBadRelocate = (rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE);
679 rpmRelocation * relocations = NULL;
681 const char ** validRelocations;
682 rpmTagType validType;
685 uint32_t * dirIndexes;
686 uint32_t * newDirIndexes;
687 rpm_count_t fileCount, dirCount, numValid;
688 rpm_flag_t * fFlags = NULL;
689 rpm_color_t * fColors = NULL;
690 rpm_color_t * dColors = NULL;
691 rpm_mode_t * fModes = NULL;
696 int haveRelocatedBase = 0;
697 int haveRelocatedFile = 0;
702 if (!hge(origH, RPMTAG_PREFIXES, &validType,
703 (rpm_data_t *) &validRelocations, &numValid))
709 while (p->relocs[numRelocations].newPath ||
710 p->relocs[numRelocations].oldPath)
714 * If no relocations are specified (usually the case), then return the
715 * original header. If there are prefixes, however, then INSTPREFIXES
716 * should be added, but, since relocateFileList() can be called more
717 * than once for the same header, don't bother if already present.
719 if (p->relocs == NULL || numRelocations == 0) {
721 if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
722 xx = hae(origH, RPMTAG_INSTPREFIXES,
723 validType, validRelocations, numValid);
724 validRelocations = hfd(validRelocations, validType);
726 /* XXX FIXME multilib file actions need to be checked. */
727 return headerLink(origH);
730 h = headerLink(origH);
732 relocations = xmalloc(sizeof(*relocations) * numRelocations);
734 /* Build sorted relocation list from raw relocations. */
735 for (i = 0; i < numRelocations; i++) {
739 * Default relocations (oldPath == NULL) are handled in the UI,
742 if (p->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
744 /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
745 too, but those are more trouble to fix up. :-( */
746 t = xstrdup(p->relocs[i].oldPath);
747 relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
749 : stripTrailingChar(t, '/');
751 /* An old path w/o a new path is valid, and indicates exclusion */
752 if (p->relocs[i].newPath) {
755 t = xstrdup(p->relocs[i].newPath);
756 relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
758 : stripTrailingChar(t, '/');
760 /* FIX: relocations[i].oldPath == NULL */
761 /* Verify that the relocation's old path is in the header. */
762 for (j = 0; j < numValid; j++) {
763 if (!strcmp(validRelocations[j], relocations[i].oldPath))
767 /* XXX actions check prevents problem from being appended twice. */
768 if (j == numValid && !allowBadRelocate && actions) {
769 rpmps ps = rpmtsProblems(ts);
770 rpmpsAppend(ps, RPMPROB_BADRELOCATE,
771 rpmteNEVRA(p), rpmteKey(p),
772 relocations[i].oldPath, NULL, NULL, 0);
776 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
781 relocations[i].newPath = NULL;
785 /* stupid bubble sort, but it's probably faster here */
786 for (i = 0; i < numRelocations; i++) {
789 for (j = 1; j < numRelocations; j++) {
790 rpmRelocation tmpReloc;
791 if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
792 relocations[j ].oldPath == NULL || /* XXX can't happen */
793 strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
796 tmpReloc = relocations[j - 1];
797 relocations[j - 1] = relocations[j];
798 relocations[j] = tmpReloc;
801 if (!madeSwap) break;
806 rpmlog(RPMLOG_DEBUG, "========== relocations\n");
807 for (i = 0; i < numRelocations; i++) {
808 if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
809 if (relocations[i].newPath == NULL)
810 rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n",
811 i, relocations[i].oldPath);
813 rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
814 i, relocations[i].oldPath, relocations[i].newPath);
818 /* Add relocation values to the header */
820 const char ** actualRelocations;
821 rpm_count_t numActual;
823 actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
825 for (i = 0; i < numValid; i++) {
826 for (j = 0; j < numRelocations; j++) {
827 if (relocations[j].oldPath == NULL || /* XXX can't happen */
828 strcmp(validRelocations[i], relocations[j].oldPath))
830 /* On install, a relocate to NULL means skip the path. */
831 if (relocations[j].newPath) {
832 actualRelocations[numActual] = relocations[j].newPath;
837 if (j == numRelocations) {
838 actualRelocations[numActual] = validRelocations[i];
844 xx = hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
845 (rpm_data_t *) actualRelocations, numActual);
847 actualRelocations = _free(actualRelocations);
848 validRelocations = hfd(validRelocations, validType);
851 xx = hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &baseNames, &fileCount);
852 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &dirIndexes, NULL);
853 xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &dirNames, &dirCount);
854 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (rpm_data_t *) &fFlags, NULL);
855 xx = hge(h, RPMTAG_FILECOLORS, NULL, (rpm_data_t *) &fColors, NULL);
856 xx = hge(h, RPMTAG_FILEMODES, NULL, (rpm_data_t *) &fModes, NULL);
858 dColors = xcalloc(dirCount, sizeof(*dColors));
860 newDirIndexes = xmalloc(sizeof(*newDirIndexes) * fileCount);
861 memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
862 dirIndexes = newDirIndexes;
865 * For all relocations, we go through sorted file/relocation lists
866 * backwards so that /usr/local relocations take precedence over /usr
870 /* Relocate individual paths. */
872 for (i = fileCount - 1; i >= 0; i--) {
877 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
878 if (len >= fileAlloced) {
879 fileAlloced = len * 2;
880 fn = xrealloc(fn, fileAlloced);
883 assert(fn != NULL); /* XXX can't happen */
885 fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
887 if (fColors != NULL) {
888 /* XXX pkgs may not have unique dirNames, so color all dirNames that match. */
889 for (j = 0; j < dirCount; j++) {
890 if (strcmp(dirNames[dirIndexes[i]], dirNames[j])) continue;
891 dColors[j] |= fColors[i];
896 * See if this file path needs relocating.
899 * XXX FIXME: Would a bsearch of the (already sorted)
900 * relocation list be a good idea?
902 for (j = numRelocations - 1; j >= 0; j--) {
903 if (relocations[j].oldPath == NULL) /* XXX can't happen */
905 len = strcmp(relocations[j].oldPath, "/")
906 ? strlen(relocations[j].oldPath)
912 * Only subdirectories or complete file paths may be relocated. We
913 * don't check for '\0' as our directory names all end in '/'.
915 if (!(fn[len] == '/' || fnlen == len))
918 if (strncmp(relocations[j].oldPath, fn, len))
924 /* FIX: fModes may be NULL */
925 ft = rpmfiWhatis(fModes[i]);
927 /* On install, a relocate to NULL means skip the path. */
928 if (relocations[j].newPath == NULL) {
930 /* Start with the parent, looking for directory to exclude. */
931 for (j = dirIndexes[i]; j < dirCount; j++) {
932 len = strlen(dirNames[j]) - 1;
933 while (len > 0 && dirNames[j][len-1] == '/') len--;
936 if (strncmp(fn, dirNames[j], fnlen))
942 actions[i] = FA_SKIPNSTATE;
943 rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
949 /* Relocation on full paths only, please. */
950 if (fnlen != len) continue;
953 rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
954 fn, relocations[j].newPath);
957 strcpy(fn, relocations[j].newPath);
958 { char * te = strrchr(fn, '/');
960 if (te > fn) te++; /* root is special */
963 te = fn + strlen(fn);
964 if (strcmp(baseNames[i], te)) { /* basename changed too? */
965 if (!haveRelocatedBase) {
966 baseNames = duparray(baseNames, fileCount);
967 haveRelocatedBase = 1;
970 baseNames[i] = xstrdup(te);
972 *te = '\0'; /* terminate new directory name */
975 /* Does this directory already exist in the directory list? */
976 for (j = 0; j < dirCount; j++) {
977 if (fnlen != strlen(dirNames[j]))
979 if (strncmp(fn, dirNames[j], fnlen))
989 /* Creating new paths is a pita */
990 if (!haveRelocatedFile) {
991 dirNames = duparray(dirNames, dirCount);
992 haveRelocatedFile = 1;
994 dirNames = xrealloc(dirNames,
995 sizeof(*dirNames) * (dirCount + 1));
998 dirNames[dirCount] = xstrdup(fn);
999 dirIndexes[i] = dirCount;
1003 /* Finish off by relocating directories. */
1004 for (i = dirCount - 1; i >= 0; i--) {
1005 for (j = numRelocations - 1; j >= 0; j--) {
1007 if (relocations[j].oldPath == NULL) /* XXX can't happen */
1009 len = strcmp(relocations[j].oldPath, "/")
1010 ? strlen(relocations[j].oldPath)
1013 if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
1017 * Only subdirectories or complete file paths may be relocated. We
1018 * don't check for '\0' as our directory names all end in '/'.
1020 if (dirNames[i][len] != '/')
1023 if (relocations[j].newPath) { /* Relocate the path */
1025 rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
1026 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
1027 (void) rpmCleanPath(t);
1031 rpmlog(RPMLOG_DEBUG,
1032 "relocating directory %s to %s\n", dirNames[i], t);
1039 /* Save original filenames in header and replace (relocated) filenames. */
1046 xx = hge(h, RPMTAG_BASENAMES, &t, &d, &c);
1047 xx = hae(h, RPMTAG_ORIGBASENAMES, t, d, c);
1051 xx = hge(h, RPMTAG_DIRNAMES, &t, &d, &c);
1052 xx = hae(h, RPMTAG_ORIGDIRNAMES, t, d, c);
1056 xx = hge(h, RPMTAG_DIRINDEXES, &t, &d, &c);
1057 xx = hae(h, RPMTAG_ORIGDIRINDEXES, t, d, c);
1060 xx = hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
1061 baseNames, fileCount);
1062 if (haveRelocatedBase) {
1063 baseNames = freearray(baseNames, fileCount);
1065 fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
1066 xx = hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &fi->bnl, &fi->fc);
1068 xx = hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
1069 dirNames, dirCount);
1070 dirNames = freearray(dirNames, dirCount);
1072 fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
1073 xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &fi->dnl, &fi->dc);
1075 xx = hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
1076 dirIndexes, fileCount);
1077 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &fi->dil, NULL);
1080 /* If we did relocations, baseNames and dirNames might be NULL by now */
1081 baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
1082 dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
1084 for (i = 0; i < numRelocations; i++) {
1085 free(relocations[i].oldPath);
1086 free(relocations[i].newPath);
1089 free(newDirIndexes);
1095 rpmfi rpmfiFree(rpmfi fi)
1097 HFD_t hfd = headerFreeData;
1099 if (fi == NULL) return NULL;
1102 return rpmfiUnlink(fi, fi->Type);
1104 if (_rpmfi_debug < 0)
1105 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
1107 /* Free pre- and post-transaction script and interpreter strings. */
1108 fi->pretrans = _free(fi->pretrans);
1109 fi->pretransprog = _free(fi->pretransprog);
1110 fi->posttrans = _free(fi->posttrans);
1111 fi->posttransprog = _free(fi->posttransprog);
1114 fi->bnl = hfd(fi->bnl, RPM_FORCEFREE_TYPE);
1115 fi->dnl = hfd(fi->dnl, RPM_FORCEFREE_TYPE);
1117 fi->flinks = hfd(fi->flinks, RPM_FORCEFREE_TYPE);
1118 fi->flangs = hfd(fi->flangs, RPM_FORCEFREE_TYPE);
1119 fi->digests = _free(fi->digests);
1121 fi->cdict = hfd(fi->cdict, RPM_FORCEFREE_TYPE);
1123 fi->fuser = hfd(fi->fuser, RPM_FORCEFREE_TYPE);
1124 fi->fgroup = hfd(fi->fgroup, RPM_FORCEFREE_TYPE);
1126 fi->fstates = _free(fi->fstates);
1128 if (!fi->keep_header && fi->h == NULL) {
1129 fi->fmtimes = _constfree(fi->fmtimes);
1130 fi->fmodes = _free(fi->fmodes);
1131 fi->fflags = _constfree(fi->fflags);
1132 fi->vflags = _constfree(fi->vflags);
1133 fi->fsizes = _constfree(fi->fsizes);
1134 fi->frdevs = _constfree(fi->frdevs);
1135 fi->finodes = _constfree(fi->finodes);
1136 fi->dil = _free(fi->dil);
1138 fi->fcolors = _constfree(fi->fcolors);
1139 fi->fcdictx = _constfree(fi->fcdictx);
1140 fi->ddict = _constfree(fi->ddict);
1141 fi->fddictx = _constfree(fi->fddictx);
1142 fi->fddictn = _constfree(fi->fddictn);
1147 fi->fsm = freeFSM(fi->fsm);
1149 fi->fn = _free(fi->fn);
1150 fi->apath = _free(fi->apath);
1151 fi->fmapflags = _free(fi->fmapflags);
1153 fi->obnl = hfd(fi->obnl, RPM_FORCEFREE_TYPE);
1154 fi->odnl = hfd(fi->odnl, RPM_FORCEFREE_TYPE);
1156 fi->fcontexts = hfd(fi->fcontexts, RPM_FORCEFREE_TYPE);
1158 fi->actions = _free(fi->actions);
1159 fi->replacedSizes = _free(fi->replacedSizes);
1160 fi->replaced = _free(fi->replaced);
1162 fi->h = headerFree(fi->h);
1164 (void) rpmfiUnlink(fi, fi->Type);
1165 memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
1171 #define _fdupe(_fi, _data) \
1172 if ((_fi)->_data != NULL) \
1173 (_fi)->_data = memcpy(xmalloc((_fi)->fc * sizeof(*(_fi)->_data)), \
1174 (_fi)->_data, (_fi)->fc * sizeof(*(_fi)->_data))
1176 /* XXX Ick, not SEF. */
1177 #define _fdupestring(_h, _tag, _data) \
1178 if (hge((_h), (_tag), NULL, (rpm_data_t *) &(_data), NULL)) \
1179 _data = xstrdup(_data)
1181 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, int scareMem)
1184 (scareMem ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry);
1185 HFD_t hfd = headerFreeData;
1192 struct rpmtd_s fdigests;
1197 if (tagN == RPMTAG_BASENAMES) {
1204 fi = xcalloc(1, sizeof(*fi));
1205 if (fi == NULL) /* XXX can't happen */
1208 fi->magic = RPMFIMAGIC;
1214 fi->hae = (HAE_t) headerAddEntry;
1215 fi->hme = (HME_t) headerModifyEntry;
1216 fi->hre = (HRE_t) headerRemoveEntry;
1217 fi->hfd = headerFreeData;
1219 fi->h = (scareMem ? headerLink(h) : NULL);
1221 if (fi->fsm == NULL)
1224 /* 0 means unknown */
1225 xx = hge(h, RPMTAG_ARCHIVESIZE, NULL, (rpm_data_t *) &uip, NULL);
1227 fi->archiveSize = (xx ? *uip : 0);
1229 /* Extract pre- and post-transaction script and interpreter strings. */
1230 _fdupestring(h, RPMTAG_PRETRANS, fi->pretrans);
1231 _fdupestring(h, RPMTAG_PRETRANSPROG, fi->pretransprog);
1232 _fdupestring(h, RPMTAG_POSTTRANS, fi->posttrans);
1233 _fdupestring(h, RPMTAG_POSTTRANSPROG, fi->posttransprog);
1235 if (!hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &fi->bnl, &fi->fc)) {
1240 xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &fi->dnl, &fi->dc);
1241 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &fi->dil, NULL);
1242 xx = hge(h, RPMTAG_FILEMODES, NULL, (rpm_data_t *) &fi->fmodes, NULL);
1243 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (rpm_data_t *) &fi->fflags, NULL);
1244 xx = hge(h, RPMTAG_FILEVERIFYFLAGS, NULL, (rpm_data_t *) &fi->vflags, NULL);
1245 xx = hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &fi->fsizes, NULL);
1247 xx = hge(h, RPMTAG_FILECOLORS, NULL, (rpm_data_t *) &fi->fcolors, NULL);
1249 if (fi->fcolors != NULL)
1250 for (i = 0; i < fi->fc; i++)
1251 fi->color |= fi->fcolors[i];
1252 xx = hge(h, RPMTAG_CLASSDICT, NULL, (rpm_data_t *) &fi->cdict, &fi->ncdict);
1253 xx = hge(h, RPMTAG_FILECLASS, NULL, (rpm_data_t *) &fi->fcdictx, NULL);
1255 xx = hge(h, RPMTAG_DEPENDSDICT, NULL, (rpm_data_t *) &fi->ddict, &fi->nddict);
1256 xx = hge(h, RPMTAG_FILEDEPENDSX, NULL, (rpm_data_t *) &fi->fddictx, NULL);
1257 xx = hge(h, RPMTAG_FILEDEPENDSN, NULL, (rpm_data_t *) &fi->fddictn, NULL);
1259 xx = hge(h, RPMTAG_FILESTATES, NULL, (rpm_data_t *) &fi->fstates, NULL);
1260 if (xx == 0 || fi->fstates == NULL)
1261 fi->fstates = xcalloc(fi->fc, sizeof(*fi->fstates));
1263 _fdupe(fi, fstates);
1265 fi->action = FA_UNKNOWN;
1268 if (fi->actions == NULL)
1269 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1271 fi->keep_header = (scareMem ? 1 : 0);
1273 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1275 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1277 xx = hge(h, RPMTAG_FILELINKTOS, NULL, (rpm_data_t *) &fi->flinks, NULL);
1278 xx = hge(h, RPMTAG_FILELANGS, NULL, (rpm_data_t *) &fi->flangs, NULL);
1280 /* digest algorithm hardwired to MD5 for now */
1281 fi->digestalgo = PGPHASHALGO_MD5;
1283 /* grab hex digests from header and store in binary format */
1284 if (headerGet(h, RPMTAG_FILEDIGESTS, &fdigests, HEADERGET_MINMEM)) {
1285 const char *fdigest;
1286 size_t diglen = rpmDigestLength(fi->digestalgo);
1287 fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
1289 while ((fdigest = rpmtdNextString(&fdigests))) {
1290 if (!(fdigest && *fdigest != '\0')) {
1291 memset(t, 0, diglen);
1295 for (int j = 0; j < diglen; j++, t++, fdigest += 2)
1296 *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
1298 rpmtdFreeData(&fdigests);
1301 /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes, or fcontexts */
1302 xx = hge(h, RPMTAG_FILEMTIMES, NULL, (rpm_data_t *) &fi->fmtimes, NULL);
1303 xx = hge(h, RPMTAG_FILERDEVS, NULL, (rpm_data_t *) &fi->frdevs, NULL);
1304 xx = hge(h, RPMTAG_FILEINODES, NULL, (rpm_data_t *) &fi->finodes, NULL);
1306 fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
1308 xx = hge(h, RPMTAG_FILEUSERNAME, NULL, (rpm_data_t *) &fi->fuser, NULL);
1309 xx = hge(h, RPMTAG_FILEGROUPNAME, NULL, (rpm_data_t *) &fi->fgroup, NULL);
1313 if ((p = rpmtsRelocateElement(ts)) != NULL && rpmteType(p) == TR_ADDED
1314 && !headerIsSource(h)
1315 && !headerIsEntry(h, RPMTAG_ORIGBASENAMES))
1320 if (fi->actions == NULL)
1321 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1322 /* FIX: fi-digests undefined */
1323 foo = relocateFileList(ts, fi, h, fi->actions);
1324 fi->h = headerFree(fi->h);
1325 fi->h = headerLink(foo);
1326 foo = headerFree(foo);
1330 _fdupe(fi, fmtimes);
1332 _fdupe(fi, finodes);
1339 _fdupe(fi, fcolors);
1340 _fdupe(fi, fcdictx);
1342 if (fi->ddict != NULL)
1343 fi->ddict = memcpy(xmalloc(fi->nddict * sizeof(*fi->ddict)),
1344 fi->ddict, fi->nddict * sizeof(*fi->ddict));
1346 _fdupe(fi, fddictx);
1347 _fdupe(fi, fddictn);
1349 fi->h = headerFree(fi->h);
1353 for (i = 0; i < fi->dc; i++) {
1354 if ((len = strlen(fi->dnl[i])) > dnlmax)
1358 for (i = 0; i < fi->fc; i++) {
1359 if ((len = strlen(fi->bnl[i])) > bnlmax)
1362 fi->fnlen = dnlmax + bnlmax + 1;
1369 if (_rpmfi_debug < 0)
1370 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, Type, (fi ? fi->fc : 0));
1372 /* FIX: rpmfi null annotations */
1373 return rpmfiLink(fi, (fi ? fi->Type : NULL));
1376 void rpmfiBuildFNames(Header h, rpmTag tagN,
1377 const char *** fnp, rpm_count_t * fcp)
1379 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
1380 HFD_t hfd = headerFreeData;
1381 const char ** baseNames;
1382 const char ** dirNames;
1383 uint32_t * dirIndexes;
1385 const char ** fileNames;
1387 rpmTag dirNameTag = 0;
1388 rpmTag dirIndexesTag = 0;
1389 rpmTagType bnt, dnt;
1393 if (tagN == RPMTAG_BASENAMES) {
1394 dirNameTag = RPMTAG_DIRNAMES;
1395 dirIndexesTag = RPMTAG_DIRINDEXES;
1396 } else if (tagN == RPMTAG_ORIGBASENAMES) {
1397 dirNameTag = RPMTAG_ORIGDIRNAMES;
1398 dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
1401 if (!hge(h, tagN, &bnt, (rpm_data_t *) &baseNames, &count)) {
1402 if (fnp) *fnp = NULL;
1404 return; /* no file list */
1407 xx = hge(h, dirNameTag, &dnt, (rpm_data_t *) &dirNames, NULL);
1408 xx = hge(h, dirIndexesTag, NULL, (rpm_data_t *) &dirIndexes, &count);
1410 size = sizeof(*fileNames) * count;
1411 for (i = 0; i < count; i++)
1412 size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
1414 fileNames = xmalloc(size);
1415 t = ((char *) fileNames) + (sizeof(*fileNames) * count);
1416 for (i = 0; i < count; i++) {
1418 t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
1421 baseNames = hfd(baseNames, bnt);
1422 dirNames = hfd(dirNames, dnt);
1427 fileNames = _free(fileNames);
1428 if (fcp) *fcp = count;