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 = rpmfiDigest(fi, &algo, NULL);
180 return (algo == PGPHASHALGO_MD5) ? digest : NULL;
183 const unsigned char * rpmfiDigest(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 const char * rpmfiFLink(rpmfi fi)
201 const char * flink = NULL;
203 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
204 if (fi->flinks != NULL)
205 flink = fi->flinks[fi->i];
210 rpm_off_t rpmfiFSize(rpmfi fi)
214 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
215 if (fi->fsizes != NULL)
216 fsize = fi->fsizes[fi->i];
221 rpm_rdev_t rpmfiFRdev(rpmfi fi)
223 rpm_rdev_t frdev = 0;
225 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
226 if (fi->frdevs != NULL)
227 frdev = fi->frdevs[fi->i];
232 rpm_ino_t rpmfiFInode(rpmfi fi)
234 rpm_ino_t finode = 0;
236 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
237 if (fi->finodes != NULL)
238 finode = fi->finodes[fi->i];
243 rpm_color_t rpmfiColor(rpmfi fi)
245 rpm_color_t color = 0;
248 /* XXX ignore all but lsnibble for now. */
249 color = fi->color & 0xf;
253 rpm_color_t rpmfiFColor(rpmfi fi)
255 rpm_color_t fcolor = 0;
257 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
258 if (fi->fcolors != NULL)
259 /* XXX ignore all but lsnibble for now. */
260 fcolor = (fi->fcolors[fi->i] & 0x0f);
265 const char * rpmfiFClass(rpmfi fi)
267 const char * fclass = NULL;
270 if (fi != NULL && fi->fcdictx != NULL && fi->i >= 0 && fi->i < fi->fc) {
271 cdictx = fi->fcdictx[fi->i];
272 if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
273 fclass = fi->cdict[cdictx];
278 const char * rpmfiFContext(rpmfi fi)
280 const char * fcontext = NULL;
282 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
283 if (fi->fcontexts != NULL)
284 fcontext = fi->fcontexts[fi->i];
289 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
293 const uint32_t * fddict = NULL;
295 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
296 if (fi->fddictn != NULL)
297 fddictn = fi->fddictn[fi->i];
298 if (fddictn > 0 && fi->fddictx != NULL)
299 fddictx = fi->fddictx[fi->i];
300 if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
301 fddict = fi->ddict + fddictx;
308 uint32_t rpmfiFNlink(rpmfi fi)
312 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
313 /* XXX rpm-2.3.12 has not RPMTAG_FILEINODES */
314 if (fi->finodes && fi->frdevs) {
315 rpm_ino_t finode = fi->finodes[fi->i];
316 rpm_rdev_t frdev = fi->frdevs[fi->i];
319 for (j = 0; j < fi->fc; j++) {
320 if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
328 rpm_time_t rpmfiFMtime(rpmfi fi)
330 rpm_time_t fmtime = 0;
332 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
333 if (fi->fmtimes != NULL)
334 fmtime = fi->fmtimes[fi->i];
339 const char * rpmfiFUser(rpmfi fi)
341 const char * fuser = NULL;
343 /* XXX add support for ancient RPMTAG_FILEUIDS? */
344 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
345 if (fi->fuser != NULL)
346 fuser = fi->fuser[fi->i];
351 const char * rpmfiFGroup(rpmfi fi)
353 const char * fgroup = NULL;
355 /* XXX add support for ancient RPMTAG_FILEGIDS? */
356 if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
357 if (fi->fgroup != NULL)
358 fgroup = fi->fgroup[fi->i];
363 int rpmfiNext(rpmfi fi)
367 if (fi != NULL && ++fi->i >= 0) {
368 if (fi->i < fi->fc) {
371 fi->j = fi->dil[fi->i];
375 if (_rpmfi_debug < 0 && i != -1)
376 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] : ""));
383 rpmfi rpmfiInit(rpmfi fi, int fx)
386 if (fx >= 0 && fx < fi->fc) {
395 int rpmfiNextD(rpmfi fi)
399 if (fi != NULL && ++fi->j >= 0) {
405 if (_rpmfi_debug < 0 && j != -1)
406 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, (fi->Type ? fi->Type : "?Type?"), j);
413 rpmfi rpmfiInitD(rpmfi fi, int dx)
416 if (dx >= 0 && dx < fi->fc)
426 * Identify a file type.
427 * @param ft file type
428 * @return string to identify a file type
431 const char * ftstring (rpmFileTypes ft)
434 case XDIR: return "directory";
435 case CDEV: return "char dev";
436 case BDEV: return "block dev";
437 case LINK: return "link";
438 case SOCK: return "sock";
439 case PIPE: return "fifo/pipe";
440 case REG: return "file";
441 default: return "unknown file type";
445 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
447 if (S_ISDIR(mode)) return XDIR;
448 if (S_ISCHR(mode)) return CDEV;
449 if (S_ISBLK(mode)) return BDEV;
450 if (S_ISLNK(mode)) return LINK;
451 if (S_ISSOCK(mode)) return SOCK;
452 if (S_ISFIFO(mode)) return PIPE;
456 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
458 rpmFileTypes awhat = rpmfiWhatis(rpmfiFMode(afi));
459 rpmFileTypes bwhat = rpmfiWhatis(rpmfiFMode(bfi));
461 if ((rpmfiFFlags(afi) & RPMFILE_GHOST) ||
462 (rpmfiFFlags(bfi) & RPMFILE_GHOST)) return 0;
464 if (awhat != bwhat) return 1;
467 const char * alink = rpmfiFLink(afi);
468 const char * blink = rpmfiFLink(bfi);
469 if (alink == blink) return 0;
470 if (alink == NULL) return 1;
471 if (blink == NULL) return -1;
472 return strcmp(alink, blink);
473 } else if (awhat == REG) {
474 size_t adiglen, bdiglen;
475 pgpHashAlgo aalgo, balgo;
476 const unsigned char * adigest = rpmfiDigest(afi, &aalgo, &adiglen);
477 const unsigned char * bdigest = rpmfiDigest(bfi, &balgo, &bdiglen);
478 if (adigest == bdigest) return 0;
479 if (adigest == NULL) return 1;
480 if (bdigest == NULL) return -1;
481 /* can't meaningfully compare different hash types */
482 if (aalgo != balgo || adiglen != bdiglen) return -1;
483 return memcmp(adigest, bdigest, adiglen);
489 rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
491 const char * fn = rpmfiFN(nfi);
492 rpmfileAttrs newFlags = rpmfiFFlags(nfi);
494 rpmFileTypes dbWhat, newWhat, diskWhat;
496 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
498 if (lstat(fn, &sb)) {
500 * The file doesn't exist on the disk. Create it unless the new
501 * package has marked it as missingok, or allfiles is requested.
503 if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
504 rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
512 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
513 dbWhat = rpmfiWhatis(rpmfiFMode(ofi));
514 newWhat = rpmfiWhatis(rpmfiFMode(nfi));
517 * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
518 * them in older packages as well.
523 if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK)
525 else if (newWhat != dbWhat && diskWhat != dbWhat)
527 else if (dbWhat != newWhat)
529 else if (dbWhat != LINK && dbWhat != REG)
533 * This order matters - we'd prefer to CREATE the file if at all
534 * possible in case something else (like the timestamp) has changed.
536 memset(buffer, 0, sizeof(buffer));
538 pgpHashAlgo oalgo, nalgo;
539 size_t odiglen, ndiglen;
540 const unsigned char * odigest, * ndigest;
541 odigest = rpmfiDigest(ofi, &oalgo, &odiglen);
542 if (diskWhat == REG) {
543 if (rpmDoDigest(oalgo, fn, 0,
544 (unsigned char *)buffer, NULL))
545 return FA_CREATE; /* assume file has been removed */
546 if (odigest && !memcmp(odigest, buffer, odiglen))
547 return FA_CREATE; /* unmodified config file, replace. */
549 ndigest = rpmfiDigest(nfi, &nalgo, &ndiglen);
550 /* XXX can't compare different hash types, what should we do here? */
551 if (oalgo != nalgo || odiglen != ndiglen)
553 if (odigest && ndigest && !memcmp(odigest, ndigest, odiglen))
554 return FA_SKIP; /* identical file, don't bother. */
555 } else /* dbWhat == LINK */ {
556 const char * oFLink, * nFLink;
557 oFLink = rpmfiFLink(ofi);
558 if (diskWhat == LINK) {
559 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
560 return FA_CREATE; /* assume file has been removed */
561 if (oFLink && !strcmp(oFLink, buffer))
562 return FA_CREATE; /* unmodified config file, replace. */
564 nFLink = rpmfiFLink(nfi);
565 if (oFLink && nFLink && !strcmp(oFLink, nFLink))
566 return FA_SKIP; /* identical file, don't bother. */
570 * The config file on the disk has been modified, but
571 * the ones in the two packages are different. It would
572 * be nice if RPM was smart enough to at least try and
573 * merge the difference ala CVS, but...
578 int rpmfiConfigConflict(const rpmfi fi)
580 const char * fn = rpmfiFN(fi);
581 rpmfileAttrs flags = rpmfiFFlags(fi);
583 rpmFileTypes newWhat, diskWhat;
586 if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) {
590 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
591 newWhat = rpmfiWhatis(rpmfiFMode(fi));
593 if (newWhat != LINK && newWhat != REG)
596 if (diskWhat != newWhat)
599 memset(buffer, 0, sizeof(buffer));
600 if (newWhat == REG) {
603 const unsigned char *ndigest = rpmfiDigest(fi, &algo, &diglen);
604 if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL))
605 return 0; /* assume file has been removed */
606 if (ndigest && !memcmp(ndigest, buffer, diglen))
607 return 0; /* unmodified config file */
608 } else /* newWhat == LINK */ {
610 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
611 return 0; /* assume file has been removed */
612 nFLink = rpmfiFLink(fi);
613 if (nFLink && !strcmp(nFLink, buffer))
614 return 0; /* unmodified config file */
620 const char * rpmfiTypeString(rpmfi fi)
622 switch(rpmteType(fi->te)) {
623 case TR_ADDED: return " install";
624 case TR_REMOVED: return " erase";
625 default: return "???";
629 static char **duparray(char ** src, int size)
631 char **dest = xmalloc((size+1) * sizeof(*dest));
632 for (int i = 0; i < size; i++) {
633 dest[i] = xstrdup(src[i]);
635 headerFreeData(src, RPM_STRING_ARRAY_TYPE);
639 static void * freearray(char **array, int size)
641 for (int i = 0; i < size; i++) {
649 * Relocate files in header.
650 * @todo multilib file dispositions need to be checked.
651 * @param ts transaction set
652 * @param fi transaction element file info
653 * @param origH package header
654 * @param actions file dispositions
655 * @return header with relocated files
658 Header relocateFileList(const rpmts ts, rpmfi fi,
659 Header origH, rpmFileAction * actions)
661 rpmte p = rpmtsRelocateElement(ts);
665 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
666 static int _printed = 0;
667 int allowBadRelocate = (rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE);
668 rpmRelocation * relocations = NULL;
670 const char ** validRelocations;
671 rpmTagType validType;
674 uint32_t * dirIndexes;
675 uint32_t * newDirIndexes;
676 rpm_count_t fileCount, dirCount, numValid;
677 rpm_flag_t * fFlags = NULL;
678 rpm_color_t * fColors = NULL;
679 rpm_color_t * dColors = NULL;
680 rpm_mode_t * fModes = NULL;
685 int haveRelocatedBase = 0;
686 int haveRelocatedFile = 0;
691 if (!hge(origH, RPMTAG_PREFIXES, &validType,
692 (rpm_data_t *) &validRelocations, &numValid))
698 while (p->relocs[numRelocations].newPath ||
699 p->relocs[numRelocations].oldPath)
703 * If no relocations are specified (usually the case), then return the
704 * original header. If there are prefixes, however, then INSTPREFIXES
705 * should be added, but, since relocateFileList() can be called more
706 * than once for the same header, don't bother if already present.
708 if (p->relocs == NULL || numRelocations == 0) {
710 if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
711 xx = hae(origH, RPMTAG_INSTPREFIXES,
712 validType, validRelocations, numValid);
713 validRelocations = hfd(validRelocations, validType);
715 /* XXX FIXME multilib file actions need to be checked. */
716 return headerLink(origH);
719 h = headerLink(origH);
721 relocations = xmalloc(sizeof(*relocations) * numRelocations);
723 /* Build sorted relocation list from raw relocations. */
724 for (i = 0; i < numRelocations; i++) {
728 * Default relocations (oldPath == NULL) are handled in the UI,
731 if (p->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
733 /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
734 too, but those are more trouble to fix up. :-( */
735 t = xstrdup(p->relocs[i].oldPath);
736 relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
738 : stripTrailingChar(t, '/');
740 /* An old path w/o a new path is valid, and indicates exclusion */
741 if (p->relocs[i].newPath) {
744 t = xstrdup(p->relocs[i].newPath);
745 relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
747 : stripTrailingChar(t, '/');
749 /* FIX: relocations[i].oldPath == NULL */
750 /* Verify that the relocation's old path is in the header. */
751 for (j = 0; j < numValid; j++) {
752 if (!strcmp(validRelocations[j], relocations[i].oldPath))
756 /* XXX actions check prevents problem from being appended twice. */
757 if (j == numValid && !allowBadRelocate && actions) {
758 rpmps ps = rpmtsProblems(ts);
759 rpmpsAppend(ps, RPMPROB_BADRELOCATE,
760 rpmteNEVRA(p), rpmteKey(p),
761 relocations[i].oldPath, NULL, NULL, 0);
765 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
770 relocations[i].newPath = NULL;
774 /* stupid bubble sort, but it's probably faster here */
775 for (i = 0; i < numRelocations; i++) {
778 for (j = 1; j < numRelocations; j++) {
779 rpmRelocation tmpReloc;
780 if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
781 relocations[j ].oldPath == NULL || /* XXX can't happen */
782 strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
785 tmpReloc = relocations[j - 1];
786 relocations[j - 1] = relocations[j];
787 relocations[j] = tmpReloc;
790 if (!madeSwap) break;
795 rpmlog(RPMLOG_DEBUG, "========== relocations\n");
796 for (i = 0; i < numRelocations; i++) {
797 if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
798 if (relocations[i].newPath == NULL)
799 rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n",
800 i, relocations[i].oldPath);
802 rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
803 i, relocations[i].oldPath, relocations[i].newPath);
807 /* Add relocation values to the header */
809 const char ** actualRelocations;
810 rpm_count_t numActual;
812 actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
814 for (i = 0; i < numValid; i++) {
815 for (j = 0; j < numRelocations; j++) {
816 if (relocations[j].oldPath == NULL || /* XXX can't happen */
817 strcmp(validRelocations[i], relocations[j].oldPath))
819 /* On install, a relocate to NULL means skip the path. */
820 if (relocations[j].newPath) {
821 actualRelocations[numActual] = relocations[j].newPath;
826 if (j == numRelocations) {
827 actualRelocations[numActual] = validRelocations[i];
833 xx = hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
834 (rpm_data_t *) actualRelocations, numActual);
836 actualRelocations = _free(actualRelocations);
837 validRelocations = hfd(validRelocations, validType);
840 xx = hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &baseNames, &fileCount);
841 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &dirIndexes, NULL);
842 xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &dirNames, &dirCount);
843 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (rpm_data_t *) &fFlags, NULL);
844 xx = hge(h, RPMTAG_FILECOLORS, NULL, (rpm_data_t *) &fColors, NULL);
845 xx = hge(h, RPMTAG_FILEMODES, NULL, (rpm_data_t *) &fModes, NULL);
847 dColors = xcalloc(dirCount, sizeof(*dColors));
849 newDirIndexes = xmalloc(sizeof(*newDirIndexes) * fileCount);
850 memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
851 dirIndexes = newDirIndexes;
854 * For all relocations, we go through sorted file/relocation lists
855 * backwards so that /usr/local relocations take precedence over /usr
859 /* Relocate individual paths. */
861 for (i = fileCount - 1; i >= 0; i--) {
866 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
867 if (len >= fileAlloced) {
868 fileAlloced = len * 2;
869 fn = xrealloc(fn, fileAlloced);
872 assert(fn != NULL); /* XXX can't happen */
874 fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
876 if (fColors != NULL) {
877 /* XXX pkgs may not have unique dirNames, so color all dirNames that match. */
878 for (j = 0; j < dirCount; j++) {
879 if (strcmp(dirNames[dirIndexes[i]], dirNames[j])) continue;
880 dColors[j] |= fColors[i];
885 * See if this file path needs relocating.
888 * XXX FIXME: Would a bsearch of the (already sorted)
889 * relocation list be a good idea?
891 for (j = numRelocations - 1; j >= 0; j--) {
892 if (relocations[j].oldPath == NULL) /* XXX can't happen */
894 len = strcmp(relocations[j].oldPath, "/")
895 ? strlen(relocations[j].oldPath)
901 * Only subdirectories or complete file paths may be relocated. We
902 * don't check for '\0' as our directory names all end in '/'.
904 if (!(fn[len] == '/' || fnlen == len))
907 if (strncmp(relocations[j].oldPath, fn, len))
913 /* FIX: fModes may be NULL */
914 ft = rpmfiWhatis(fModes[i]);
916 /* On install, a relocate to NULL means skip the path. */
917 if (relocations[j].newPath == NULL) {
919 /* Start with the parent, looking for directory to exclude. */
920 for (j = dirIndexes[i]; j < dirCount; j++) {
921 len = strlen(dirNames[j]) - 1;
922 while (len > 0 && dirNames[j][len-1] == '/') len--;
925 if (strncmp(fn, dirNames[j], fnlen))
931 actions[i] = FA_SKIPNSTATE;
932 rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
938 /* Relocation on full paths only, please. */
939 if (fnlen != len) continue;
942 rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
943 fn, relocations[j].newPath);
946 strcpy(fn, relocations[j].newPath);
947 { char * te = strrchr(fn, '/');
949 if (te > fn) te++; /* root is special */
952 te = fn + strlen(fn);
953 if (strcmp(baseNames[i], te)) { /* basename changed too? */
954 if (!haveRelocatedBase) {
955 baseNames = duparray(baseNames, fileCount);
956 haveRelocatedBase = 1;
959 baseNames[i] = xstrdup(te);
961 *te = '\0'; /* terminate new directory name */
964 /* Does this directory already exist in the directory list? */
965 for (j = 0; j < dirCount; j++) {
966 if (fnlen != strlen(dirNames[j]))
968 if (strncmp(fn, dirNames[j], fnlen))
978 /* Creating new paths is a pita */
979 if (!haveRelocatedFile) {
980 dirNames = duparray(dirNames, dirCount);
981 haveRelocatedFile = 1;
983 dirNames = xrealloc(dirNames,
984 sizeof(*dirNames) * (dirCount + 1));
987 dirNames[dirCount] = xstrdup(fn);
988 dirIndexes[i] = dirCount;
992 /* Finish off by relocating directories. */
993 for (i = dirCount - 1; i >= 0; i--) {
994 for (j = numRelocations - 1; j >= 0; j--) {
996 if (relocations[j].oldPath == NULL) /* XXX can't happen */
998 len = strcmp(relocations[j].oldPath, "/")
999 ? strlen(relocations[j].oldPath)
1002 if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
1006 * Only subdirectories or complete file paths may be relocated. We
1007 * don't check for '\0' as our directory names all end in '/'.
1009 if (dirNames[i][len] != '/')
1012 if (relocations[j].newPath) { /* Relocate the path */
1014 rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
1015 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
1016 (void) rpmCleanPath(t);
1020 rpmlog(RPMLOG_DEBUG,
1021 "relocating directory %s to %s\n", dirNames[i], t);
1028 /* Save original filenames in header and replace (relocated) filenames. */
1035 xx = hge(h, RPMTAG_BASENAMES, &t, &d, &c);
1036 xx = hae(h, RPMTAG_ORIGBASENAMES, t, d, c);
1040 xx = hge(h, RPMTAG_DIRNAMES, &t, &d, &c);
1041 xx = hae(h, RPMTAG_ORIGDIRNAMES, t, d, c);
1045 xx = hge(h, RPMTAG_DIRINDEXES, &t, &d, &c);
1046 xx = hae(h, RPMTAG_ORIGDIRINDEXES, t, d, c);
1049 xx = hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
1050 baseNames, fileCount);
1051 if (haveRelocatedBase) {
1052 baseNames = freearray(baseNames, fileCount);
1054 fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
1055 xx = hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &fi->bnl, &fi->fc);
1057 xx = hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
1058 dirNames, dirCount);
1059 dirNames = freearray(dirNames, dirCount);
1061 fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
1062 xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &fi->dnl, &fi->dc);
1064 xx = hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
1065 dirIndexes, fileCount);
1066 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &fi->dil, NULL);
1069 /* If we did relocations, baseNames and dirNames might be NULL by now */
1070 baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
1071 dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
1073 for (i = 0; i < numRelocations; i++) {
1074 free(relocations[i].oldPath);
1075 free(relocations[i].newPath);
1078 free(newDirIndexes);
1084 rpmfi rpmfiFree(rpmfi fi)
1086 HFD_t hfd = headerFreeData;
1088 if (fi == NULL) return NULL;
1091 return rpmfiUnlink(fi, fi->Type);
1093 if (_rpmfi_debug < 0)
1094 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
1096 /* Free pre- and post-transaction script and interpreter strings. */
1097 fi->pretrans = _free(fi->pretrans);
1098 fi->pretransprog = _free(fi->pretransprog);
1099 fi->posttrans = _free(fi->posttrans);
1100 fi->posttransprog = _free(fi->posttransprog);
1103 fi->bnl = hfd(fi->bnl, RPM_FORCEFREE_TYPE);
1104 fi->dnl = hfd(fi->dnl, RPM_FORCEFREE_TYPE);
1106 fi->flinks = hfd(fi->flinks, RPM_FORCEFREE_TYPE);
1107 fi->flangs = hfd(fi->flangs, RPM_FORCEFREE_TYPE);
1108 fi->digests = _free(fi->digests);
1110 fi->cdict = hfd(fi->cdict, RPM_FORCEFREE_TYPE);
1112 fi->fuser = hfd(fi->fuser, RPM_FORCEFREE_TYPE);
1113 fi->fgroup = hfd(fi->fgroup, RPM_FORCEFREE_TYPE);
1115 fi->fstates = _free(fi->fstates);
1117 if (!fi->keep_header && fi->h == NULL) {
1118 fi->fmtimes = _constfree(fi->fmtimes);
1119 fi->fmodes = _free(fi->fmodes);
1120 fi->fflags = _constfree(fi->fflags);
1121 fi->vflags = _constfree(fi->vflags);
1122 fi->fsizes = _constfree(fi->fsizes);
1123 fi->frdevs = _constfree(fi->frdevs);
1124 fi->finodes = _constfree(fi->finodes);
1125 fi->dil = _free(fi->dil);
1127 fi->fcolors = _constfree(fi->fcolors);
1128 fi->fcdictx = _constfree(fi->fcdictx);
1129 fi->ddict = _constfree(fi->ddict);
1130 fi->fddictx = _constfree(fi->fddictx);
1131 fi->fddictn = _constfree(fi->fddictn);
1136 fi->fsm = freeFSM(fi->fsm);
1138 fi->fn = _free(fi->fn);
1139 fi->apath = _free(fi->apath);
1140 fi->fmapflags = _free(fi->fmapflags);
1142 fi->obnl = hfd(fi->obnl, RPM_FORCEFREE_TYPE);
1143 fi->odnl = hfd(fi->odnl, RPM_FORCEFREE_TYPE);
1145 fi->fcontexts = hfd(fi->fcontexts, RPM_FORCEFREE_TYPE);
1147 fi->actions = _free(fi->actions);
1148 fi->replacedSizes = _free(fi->replacedSizes);
1149 fi->replaced = _free(fi->replaced);
1151 fi->h = headerFree(fi->h);
1153 (void) rpmfiUnlink(fi, fi->Type);
1154 memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
1160 #define _fdupe(_fi, _data) \
1161 if ((_fi)->_data != NULL) \
1162 (_fi)->_data = memcpy(xmalloc((_fi)->fc * sizeof(*(_fi)->_data)), \
1163 (_fi)->_data, (_fi)->fc * sizeof(*(_fi)->_data))
1165 /* XXX Ick, not SEF. */
1166 #define _fdupestring(_h, _tag, _data) \
1167 if (hge((_h), (_tag), NULL, (rpm_data_t *) &(_data), NULL)) \
1168 _data = xstrdup(_data)
1170 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, int scareMem)
1173 (scareMem ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry);
1174 HFD_t hfd = headerFreeData;
1181 struct rpmtd_s fdigests;
1186 if (tagN == RPMTAG_BASENAMES) {
1193 fi = xcalloc(1, sizeof(*fi));
1194 if (fi == NULL) /* XXX can't happen */
1197 fi->magic = RPMFIMAGIC;
1203 fi->hae = (HAE_t) headerAddEntry;
1204 fi->hme = (HME_t) headerModifyEntry;
1205 fi->hre = (HRE_t) headerRemoveEntry;
1206 fi->hfd = headerFreeData;
1208 fi->h = (scareMem ? headerLink(h) : NULL);
1210 if (fi->fsm == NULL)
1213 /* 0 means unknown */
1214 xx = hge(h, RPMTAG_ARCHIVESIZE, NULL, (rpm_data_t *) &uip, NULL);
1216 fi->archiveSize = (xx ? *uip : 0);
1218 /* Extract pre- and post-transaction script and interpreter strings. */
1219 _fdupestring(h, RPMTAG_PRETRANS, fi->pretrans);
1220 _fdupestring(h, RPMTAG_PRETRANSPROG, fi->pretransprog);
1221 _fdupestring(h, RPMTAG_POSTTRANS, fi->posttrans);
1222 _fdupestring(h, RPMTAG_POSTTRANSPROG, fi->posttransprog);
1224 if (!hge(h, RPMTAG_BASENAMES, NULL, (rpm_data_t *) &fi->bnl, &fi->fc)) {
1229 xx = hge(h, RPMTAG_DIRNAMES, NULL, (rpm_data_t *) &fi->dnl, &fi->dc);
1230 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &fi->dil, NULL);
1231 xx = hge(h, RPMTAG_FILEMODES, NULL, (rpm_data_t *) &fi->fmodes, NULL);
1232 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (rpm_data_t *) &fi->fflags, NULL);
1233 xx = hge(h, RPMTAG_FILEVERIFYFLAGS, NULL, (rpm_data_t *) &fi->vflags, NULL);
1234 xx = hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &fi->fsizes, NULL);
1236 xx = hge(h, RPMTAG_FILECOLORS, NULL, (rpm_data_t *) &fi->fcolors, NULL);
1238 if (fi->fcolors != NULL)
1239 for (i = 0; i < fi->fc; i++)
1240 fi->color |= fi->fcolors[i];
1241 xx = hge(h, RPMTAG_CLASSDICT, NULL, (rpm_data_t *) &fi->cdict, &fi->ncdict);
1242 xx = hge(h, RPMTAG_FILECLASS, NULL, (rpm_data_t *) &fi->fcdictx, NULL);
1244 xx = hge(h, RPMTAG_DEPENDSDICT, NULL, (rpm_data_t *) &fi->ddict, &fi->nddict);
1245 xx = hge(h, RPMTAG_FILEDEPENDSX, NULL, (rpm_data_t *) &fi->fddictx, NULL);
1246 xx = hge(h, RPMTAG_FILEDEPENDSN, NULL, (rpm_data_t *) &fi->fddictn, NULL);
1248 xx = hge(h, RPMTAG_FILESTATES, NULL, (rpm_data_t *) &fi->fstates, NULL);
1249 if (xx == 0 || fi->fstates == NULL)
1250 fi->fstates = xcalloc(fi->fc, sizeof(*fi->fstates));
1252 _fdupe(fi, fstates);
1254 fi->action = FA_UNKNOWN;
1257 if (fi->actions == NULL)
1258 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1260 fi->keep_header = (scareMem ? 1 : 0);
1262 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1264 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1266 xx = hge(h, RPMTAG_FILELINKTOS, NULL, (rpm_data_t *) &fi->flinks, NULL);
1267 xx = hge(h, RPMTAG_FILELANGS, NULL, (rpm_data_t *) &fi->flangs, NULL);
1269 /* digest algorithm hardwired to MD5 for now */
1270 fi->digestalgo = PGPHASHALGO_MD5;
1272 /* grab hex digests from header and store in binary format */
1273 if (headerGet(h, RPMTAG_FILEMD5S, &fdigests, HEADERGET_MINMEM)) {
1274 const char *fdigest;
1275 size_t diglen = rpmDigestLength(fi->digestalgo);
1276 fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
1278 while ((fdigest = rpmtdNextString(&fdigests))) {
1279 if (!(fdigest && *fdigest != '\0')) {
1280 memset(t, 0, diglen);
1284 for (int j = 0; j < diglen; j++, t++, fdigest += 2)
1285 *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
1287 rpmtdFreeData(&fdigests);
1290 /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes, or fcontexts */
1291 xx = hge(h, RPMTAG_FILEMTIMES, NULL, (rpm_data_t *) &fi->fmtimes, NULL);
1292 xx = hge(h, RPMTAG_FILERDEVS, NULL, (rpm_data_t *) &fi->frdevs, NULL);
1293 xx = hge(h, RPMTAG_FILEINODES, NULL, (rpm_data_t *) &fi->finodes, NULL);
1295 fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
1297 xx = hge(h, RPMTAG_FILEUSERNAME, NULL, (rpm_data_t *) &fi->fuser, NULL);
1298 xx = hge(h, RPMTAG_FILEGROUPNAME, NULL, (rpm_data_t *) &fi->fgroup, NULL);
1302 if ((p = rpmtsRelocateElement(ts)) != NULL && rpmteType(p) == TR_ADDED
1303 && !headerIsSource(h)
1304 && !headerIsEntry(h, RPMTAG_ORIGBASENAMES))
1309 if (fi->actions == NULL)
1310 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1311 /* FIX: fi-digests undefined */
1312 foo = relocateFileList(ts, fi, h, fi->actions);
1313 fi->h = headerFree(fi->h);
1314 fi->h = headerLink(foo);
1315 foo = headerFree(foo);
1319 _fdupe(fi, fmtimes);
1321 _fdupe(fi, finodes);
1328 _fdupe(fi, fcolors);
1329 _fdupe(fi, fcdictx);
1331 if (fi->ddict != NULL)
1332 fi->ddict = memcpy(xmalloc(fi->nddict * sizeof(*fi->ddict)),
1333 fi->ddict, fi->nddict * sizeof(*fi->ddict));
1335 _fdupe(fi, fddictx);
1336 _fdupe(fi, fddictn);
1338 fi->h = headerFree(fi->h);
1342 for (i = 0; i < fi->dc; i++) {
1343 if ((len = strlen(fi->dnl[i])) > dnlmax)
1347 for (i = 0; i < fi->fc; i++) {
1348 if ((len = strlen(fi->bnl[i])) > bnlmax)
1351 fi->fnlen = dnlmax + bnlmax + 1;
1358 if (_rpmfi_debug < 0)
1359 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, Type, (fi ? fi->fc : 0));
1361 /* FIX: rpmfi null annotations */
1362 return rpmfiLink(fi, (fi ? fi->Type : NULL));
1365 void rpmfiBuildFNames(Header h, rpmTag tagN,
1366 const char *** fnp, rpm_count_t * fcp)
1368 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
1369 HFD_t hfd = headerFreeData;
1370 const char ** baseNames;
1371 const char ** dirNames;
1372 uint32_t * dirIndexes;
1374 const char ** fileNames;
1376 rpmTag dirNameTag = 0;
1377 rpmTag dirIndexesTag = 0;
1378 rpmTagType bnt, dnt;
1382 if (tagN == RPMTAG_BASENAMES) {
1383 dirNameTag = RPMTAG_DIRNAMES;
1384 dirIndexesTag = RPMTAG_DIRINDEXES;
1385 } else if (tagN == RPMTAG_ORIGBASENAMES) {
1386 dirNameTag = RPMTAG_ORIGDIRNAMES;
1387 dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
1390 if (!hge(h, tagN, &bnt, (rpm_data_t *) &baseNames, &count)) {
1391 if (fnp) *fnp = NULL;
1393 return; /* no file list */
1396 xx = hge(h, dirNameTag, &dnt, (rpm_data_t *) &dirNames, NULL);
1397 xx = hge(h, dirIndexesTag, NULL, (rpm_data_t *) &dirIndexes, &count);
1399 size = sizeof(*fileNames) * count;
1400 for (i = 0; i < count; i++)
1401 size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
1403 fileNames = xmalloc(size);
1404 t = ((char *) fileNames) + (sizeof(*fileNames) * count);
1405 for (i = 0; i < count; i++) {
1407 t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
1410 baseNames = hfd(baseNames, bnt);
1411 dirNames = hfd(dirNames, dnt);
1416 fileNames = _free(fileNames);
1417 if (fcp) *fcp = count;