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_loff_t rpmfiFSize(rpmfi fi)
223 rpm_loff_t fsize = 0;
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]);
651 * Relocate files in header.
652 * @todo multilib file dispositions need to be checked.
653 * @param ts transaction set
654 * @param fi transaction element file info
655 * @param origH package header
656 * @param actions file dispositions
657 * @return header with relocated files
660 Header relocateFileList(const rpmts ts, rpmfi fi,
661 Header origH, rpmFileAction * actions)
663 rpmte p = rpmtsRelocateElement(ts);
664 static int _printed = 0;
665 int allowBadRelocate = (rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE);
666 rpmRelocation * relocations = NULL;
670 uint32_t * dirIndexes;
671 uint32_t * newDirIndexes;
672 rpm_count_t fileCount, dirCount, numValid = 0;
673 rpm_color_t * fColors = NULL;
674 rpm_color_t * dColors = NULL;
675 rpm_mode_t * fModes = NULL;
680 int haveRelocatedBase = 0;
684 struct rpmtd_s validRelocs;
685 struct rpmtd_s bnames, dnames, dindexes, fcolors, fmodes;
688 if (headerGet(origH, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM))
689 numValid = rpmtdCount(&validRelocs);
694 while (p->relocs[numRelocations].newPath ||
695 p->relocs[numRelocations].oldPath)
699 * If no relocations are specified (usually the case), then return the
700 * original header. If there are prefixes, however, then INSTPREFIXES
701 * should be added, but, since relocateFileList() can be called more
702 * than once for the same header, don't bother if already present.
704 if (p->relocs == NULL || numRelocations == 0) {
706 if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES)) {
707 rpmtdSetTag(&validRelocs, RPMTAG_INSTPREFIXES);
708 headerPut(origH, &validRelocs, HEADERPUT_DEFAULT);
710 rpmtdFreeData(&validRelocs);
712 /* XXX FIXME multilib file actions need to be checked. */
713 return headerLink(origH);
716 h = headerLink(origH);
718 relocations = xmalloc(sizeof(*relocations) * numRelocations);
720 /* Build sorted relocation list from raw relocations. */
721 for (i = 0; i < numRelocations; i++) {
725 * Default relocations (oldPath == NULL) are handled in the UI,
728 if (p->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
730 /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
731 too, but those are more trouble to fix up. :-( */
732 t = xstrdup(p->relocs[i].oldPath);
733 relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
735 : stripTrailingChar(t, '/');
737 /* An old path w/o a new path is valid, and indicates exclusion */
738 if (p->relocs[i].newPath) {
741 const char *validprefix;
743 t = xstrdup(p->relocs[i].newPath);
744 relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
746 : stripTrailingChar(t, '/');
748 /* FIX: relocations[i].oldPath == NULL */
749 /* Verify that the relocation's old path is in the header. */
750 rpmtdInit(&validRelocs);
751 while ((validprefix = rpmtdNextString(&validRelocs))) {
752 if (strcmp(validprefix, relocations[i].oldPath) == 0) {
758 /* XXX actions check prevents problem from being appended twice. */
759 if (!valid && !allowBadRelocate && actions) {
760 rpmps ps = rpmtsProblems(ts);
761 rpmpsAppend(ps, RPMPROB_BADRELOCATE,
762 rpmteNEVRA(p), rpmteKey(p),
763 relocations[i].oldPath, NULL, NULL, 0);
767 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
772 relocations[i].newPath = NULL;
776 /* stupid bubble sort, but it's probably faster here */
777 for (i = 0; i < numRelocations; i++) {
780 for (j = 1; j < numRelocations; j++) {
781 rpmRelocation tmpReloc;
782 if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
783 relocations[j ].oldPath == NULL || /* XXX can't happen */
784 strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
787 tmpReloc = relocations[j - 1];
788 relocations[j - 1] = relocations[j];
789 relocations[j] = tmpReloc;
792 if (!madeSwap) break;
797 rpmlog(RPMLOG_DEBUG, "========== relocations\n");
798 for (i = 0; i < numRelocations; i++) {
799 if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
800 if (relocations[i].newPath == NULL)
801 rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n",
802 i, relocations[i].oldPath);
804 rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n",
805 i, relocations[i].oldPath, relocations[i].newPath);
809 /* Add relocation values to the header */
811 const char *validprefix;
812 const char ** actualRelocations;
813 rpm_count_t numActual;
815 actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
817 rpmtdInit(&validRelocs);
818 while ((validprefix = rpmtdNextString(&validRelocs))) {
819 for (j = 0; j < numRelocations; j++) {
820 if (relocations[j].oldPath == NULL || /* XXX can't happen */
821 strcmp(validprefix, relocations[j].oldPath))
823 /* On install, a relocate to NULL means skip the path. */
824 if (relocations[j].newPath) {
825 actualRelocations[numActual] = relocations[j].newPath;
830 if (j == numRelocations) {
831 actualRelocations[numActual] = validprefix;
838 if (rpmtdFromStringArray(&pfx, RPMTAG_INSTPREFIXES,
839 actualRelocations, numActual)) {
840 headerPut(h, &pfx, HEADERPUT_DEFAULT);
844 actualRelocations = _free(actualRelocations);
845 rpmtdFreeData(&validRelocs);
848 headerGet(h, RPMTAG_BASENAMES, &bnames, fi->scareFlags);
849 headerGet(h, RPMTAG_DIRINDEXES, &dindexes, fi->scareFlags);
850 headerGet(h, RPMTAG_DIRNAMES, &dnames, fi->scareFlags);
851 headerGet(h, RPMTAG_FILECOLORS, &fcolors, fi->scareFlags);
852 headerGet(h, RPMTAG_FILEMODES, &fmodes, fi->scareFlags);
853 /* TODO XXX ugh.. use rpmtd iterators & friends instead */
854 baseNames = bnames.data;
855 dirIndexes = dindexes.data;
856 fColors = fcolors.data;
857 fModes = fmodes.data;
858 fileCount = rpmtdCount(&bnames);
859 dirCount = rpmtdCount(&dnames);
860 /* XXX TODO: use rpmtdDup() instead */
861 dirNames = dnames.data = duparray(dnames.data, dirCount);
862 dnames.flags |= RPMTD_PTR_ALLOCED;
864 dColors = xcalloc(dirCount, sizeof(*dColors));
866 newDirIndexes = xmalloc(sizeof(*newDirIndexes) * fileCount);
867 memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
868 dirIndexes = newDirIndexes;
871 * For all relocations, we go through sorted file/relocation lists
872 * backwards so that /usr/local relocations take precedence over /usr
876 /* Relocate individual paths. */
878 for (i = fileCount - 1; i >= 0; i--) {
883 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
884 if (len >= fileAlloced) {
885 fileAlloced = len * 2;
886 fn = xrealloc(fn, fileAlloced);
889 assert(fn != NULL); /* XXX can't happen */
891 fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
893 if (fColors != NULL) {
894 /* XXX pkgs may not have unique dirNames, so color all dirNames that match. */
895 for (j = 0; j < dirCount; j++) {
896 if (strcmp(dirNames[dirIndexes[i]], dirNames[j])) continue;
897 dColors[j] |= fColors[i];
902 * See if this file path needs relocating.
905 * XXX FIXME: Would a bsearch of the (already sorted)
906 * relocation list be a good idea?
908 for (j = numRelocations - 1; j >= 0; j--) {
909 if (relocations[j].oldPath == NULL) /* XXX can't happen */
911 len = strcmp(relocations[j].oldPath, "/")
912 ? strlen(relocations[j].oldPath)
918 * Only subdirectories or complete file paths may be relocated. We
919 * don't check for '\0' as our directory names all end in '/'.
921 if (!(fn[len] == '/' || fnlen == len))
924 if (strncmp(relocations[j].oldPath, fn, len))
930 /* FIX: fModes may be NULL */
931 ft = rpmfiWhatis(fModes[i]);
933 /* On install, a relocate to NULL means skip the path. */
934 if (relocations[j].newPath == NULL) {
936 /* Start with the parent, looking for directory to exclude. */
937 for (j = dirIndexes[i]; j < dirCount; j++) {
938 len = strlen(dirNames[j]) - 1;
939 while (len > 0 && dirNames[j][len-1] == '/') len--;
942 if (strncmp(fn, dirNames[j], fnlen))
948 actions[i] = FA_SKIPNSTATE;
949 rpmlog(RPMLOG_DEBUG, "excluding %s %s\n",
955 /* Relocation on full paths only, please. */
956 if (fnlen != len) continue;
959 rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
960 fn, relocations[j].newPath);
963 strcpy(fn, relocations[j].newPath);
964 { char * te = strrchr(fn, '/');
966 if (te > fn) te++; /* root is special */
969 te = fn + strlen(fn);
970 if (strcmp(baseNames[i], te)) { /* basename changed too? */
971 if (!haveRelocatedBase) {
972 /* XXX TODO: use rpmtdDup() instead */
973 bnames.data = baseNames = duparray(baseNames, fileCount);
974 bnames.flags |= RPMTD_PTR_ALLOCED;
975 haveRelocatedBase = 1;
978 baseNames[i] = xstrdup(te);
980 *te = '\0'; /* terminate new directory name */
983 /* Does this directory already exist in the directory list? */
984 for (j = 0; j < dirCount; j++) {
985 if (fnlen != strlen(dirNames[j]))
987 if (strncmp(fn, dirNames[j], fnlen))
997 /* Creating new paths is a pita */
998 dirNames = dnames.data = xrealloc(dnames.data,
999 sizeof(*dirNames) * (dirCount + 1));
1001 free(dirNames[dirCount]);
1002 dirNames[dirCount] = xstrdup(fn);
1003 dirIndexes[i] = dirCount;
1008 /* Finish off by relocating directories. */
1009 for (i = dirCount - 1; i >= 0; i--) {
1010 for (j = numRelocations - 1; j >= 0; j--) {
1012 if (relocations[j].oldPath == NULL) /* XXX can't happen */
1014 len = strcmp(relocations[j].oldPath, "/")
1015 ? strlen(relocations[j].oldPath)
1018 if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
1022 * Only subdirectories or complete file paths may be relocated. We
1023 * don't check for '\0' as our directory names all end in '/'.
1025 if (dirNames[i][len] != '/')
1028 if (relocations[j].newPath) { /* Relocate the path */
1030 rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL);
1031 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
1032 (void) rpmCleanPath(t);
1036 rpmlog(RPMLOG_DEBUG,
1037 "relocating directory %s to %s\n", dirNames[i], t);
1045 /* Save original filenames in header and replace (relocated) filenames. */
1049 headerGet(h, RPMTAG_BASENAMES, &td, HEADERGET_MINMEM);
1050 rpmtdSetTag(&td, RPMTAG_ORIGBASENAMES);
1051 headerPut(h, &td, HEADERPUT_DEFAULT);
1054 headerGet(h, RPMTAG_DIRNAMES, &td, HEADERGET_MINMEM);
1055 rpmtdSetTag(&td, RPMTAG_ORIGDIRNAMES);
1056 headerPut(h, &td, HEADERPUT_DEFAULT);
1059 headerGet(h, RPMTAG_DIRINDEXES, &td, HEADERGET_MINMEM);
1060 rpmtdSetTag(&td, RPMTAG_ORIGDIRINDEXES);
1061 headerPut(h, &td, HEADERPUT_DEFAULT);
1064 if (rpmtdFromStringArray(&td, RPMTAG_BASENAMES, (const char**) baseNames, fileCount)) {
1068 headerGet(h, RPMTAG_BASENAMES, &td, fi->scareFlags);
1069 fi->fc = rpmtdCount(&td);
1072 if (rpmtdFromStringArray(&td, RPMTAG_DIRNAMES, (const char**) dirNames, dirCount)) {
1076 headerGet(h, RPMTAG_DIRNAMES, &td, fi->scareFlags);
1077 fi->dc = rpmtdCount(&td);
1080 if (rpmtdFromUint32(&td, RPMTAG_DIRINDEXES, dirIndexes, fileCount)) {
1083 headerGet(h, RPMTAG_DIRINDEXES, &td, fi->scareFlags);
1084 /* Ugh, nasty games with how dil is alloced depending on scareMem */
1085 if (fi->scareFlags & HEADERGET_ALLOC)
1090 rpmtdFreeData(&bnames);
1091 rpmtdFreeData(&dnames);
1092 rpmtdFreeData(&dindexes);
1093 rpmtdFreeData(&fcolors);
1094 rpmtdFreeData(&fmodes);
1096 for (i = 0; i < numRelocations; i++) {
1097 free(relocations[i].oldPath);
1098 free(relocations[i].newPath);
1101 free(newDirIndexes);
1107 rpmfi rpmfiFree(rpmfi fi)
1109 if (fi == NULL) return NULL;
1112 return rpmfiUnlink(fi, fi->Type);
1114 if (_rpmfi_debug < 0)
1115 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
1117 /* Free pre- and post-transaction script and interpreter strings. */
1118 fi->pretrans = _free(fi->pretrans);
1119 fi->pretransprog = _free(fi->pretransprog);
1120 fi->posttrans = _free(fi->posttrans);
1121 fi->posttransprog = _free(fi->posttransprog);
1124 fi->bnl = _free(fi->bnl);
1125 fi->dnl = _free(fi->dnl);
1127 fi->flinks = _free(fi->flinks);
1128 fi->flangs = _free(fi->flangs);
1129 fi->digests = _free(fi->digests);
1131 fi->cdict = _free(fi->cdict);
1133 fi->fuser = _free(fi->fuser);
1134 fi->fgroup = _free(fi->fgroup);
1136 fi->fstates = _free(fi->fstates);
1138 if (!fi->keep_header && fi->h == NULL) {
1139 fi->fmtimes = _constfree(fi->fmtimes);
1140 fi->fmodes = _free(fi->fmodes);
1141 fi->fflags = _constfree(fi->fflags);
1142 fi->vflags = _constfree(fi->vflags);
1143 fi->fsizes = _constfree(fi->fsizes);
1144 fi->frdevs = _constfree(fi->frdevs);
1145 fi->finodes = _constfree(fi->finodes);
1146 fi->dil = _free(fi->dil);
1148 fi->fcolors = _constfree(fi->fcolors);
1149 fi->fcdictx = _constfree(fi->fcdictx);
1150 fi->ddict = _constfree(fi->ddict);
1151 fi->fddictx = _constfree(fi->fddictx);
1152 fi->fddictn = _constfree(fi->fddictn);
1157 fi->fsm = freeFSM(fi->fsm);
1159 fi->fn = _free(fi->fn);
1160 fi->apath = _free(fi->apath);
1161 fi->fmapflags = _free(fi->fmapflags);
1163 fi->obnl = _free(fi->obnl);
1164 fi->odnl = _free(fi->odnl);
1166 fi->actions = _free(fi->actions);
1167 fi->replacedSizes = _free(fi->replacedSizes);
1168 fi->replaced = _free(fi->replaced);
1170 fi->h = headerFree(fi->h);
1172 (void) rpmfiUnlink(fi, fi->Type);
1173 memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
1179 #define _hgfi(_h, _tag, _td, _flags, _data) \
1180 if (headerGet((_h), (_tag), (_td), (_flags))) \
1183 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, int scareMem)
1188 rpm_loff_t *asize = NULL;
1191 struct rpmtd_s fdigests, digalgo;
1193 headerGetFlags scareFlags = scareMem ? HEADERGET_MINMEM : HEADERGET_ALLOC;
1194 headerGetFlags defFlags = HEADERGET_ALLOC;
1198 if (tagN == RPMTAG_BASENAMES) {
1205 fi = xcalloc(1, sizeof(*fi));
1206 if (fi == NULL) /* XXX can't happen */
1209 fi->magic = RPMFIMAGIC;
1214 fi->hae = (HAE_t) headerAddEntry;
1215 fi->hme = (HME_t) headerModifyEntry;
1216 fi->scareFlags = scareFlags;
1218 fi->h = (scareMem ? headerLink(h) : NULL);
1220 if (fi->fsm == NULL)
1223 if (headerGet(h, RPMTAG_LONGARCHIVESIZE, &td, HEADERGET_EXT)) {
1224 asize = rpmtdGetUint64(&td);
1226 /* 0 means unknown */
1228 fi->archiveSize = asize ? *asize : 0;
1231 /* Extract pre- and post-transaction script and interpreter strings. */
1232 _hgfi(h, RPMTAG_PRETRANS, &td, defFlags, fi->pretrans);
1233 _hgfi(h, RPMTAG_PRETRANSPROG, &td, defFlags, fi->pretransprog);
1234 _hgfi(h, RPMTAG_POSTTRANS, &td, defFlags, fi->posttrans);
1235 _hgfi(h, RPMTAG_POSTTRANSPROG, &td, defFlags, fi->posttransprog);
1237 _hgfi(h, RPMTAG_BASENAMES, &td, defFlags, fi->bnl);
1238 fi->fc = rpmtdCount(&td);
1243 _hgfi(h, RPMTAG_DIRNAMES, &td, defFlags, fi->dnl);
1244 fi->dc = rpmtdCount(&td);
1245 _hgfi(h, RPMTAG_DIRINDEXES, &td, scareFlags, fi->dil);
1246 _hgfi(h, RPMTAG_FILEMODES, &td, scareFlags, fi->fmodes);
1247 _hgfi(h, RPMTAG_FILEFLAGS, &td, scareFlags, fi->fflags);
1248 _hgfi(h, RPMTAG_FILEVERIFYFLAGS, &td, scareFlags, fi->vflags);
1249 _hgfi(h, RPMTAG_FILESIZES, &td, scareFlags, fi->fsizes);
1251 _hgfi(h, RPMTAG_FILECOLORS, &td, scareFlags, fi->fcolors);
1253 if (fi->fcolors != NULL)
1254 for (i = 0; i < fi->fc; i++)
1255 fi->color |= fi->fcolors[i];
1257 _hgfi(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
1258 fi->ncdict = rpmtdCount(&td);
1259 _hgfi(h, RPMTAG_FILECLASS, &td, scareFlags, fi->fcdictx);
1260 _hgfi(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
1261 fi->nddict = rpmtdCount(&td);
1262 _hgfi(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
1263 _hgfi(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
1265 _hgfi(h, RPMTAG_FILESTATES, &td, defFlags, fi->fstates);
1266 if (fi->fstates == NULL)
1267 fi->fstates = xcalloc(fi->fc, sizeof(*fi->fstates));
1269 fi->action = FA_UNKNOWN;
1272 if (fi->actions == NULL)
1273 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1275 fi->keep_header = (scareMem ? 1 : 0);
1277 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1279 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1281 _hgfi(h, RPMTAG_FILELINKTOS, &td, defFlags, fi->flinks);
1282 _hgfi(h, RPMTAG_FILELANGS, &td, defFlags, fi->flangs);
1284 /* See if the package has non-md5 file digests */
1285 fi->digestalgo = PGPHASHALGO_MD5;
1286 if (headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM)) {
1287 pgpHashAlgo *algo = rpmtdGetUint32(&digalgo);
1288 /* Hmm, what to do with unknown digest algorithms? */
1289 if (algo && rpmDigestLength(*algo) != 0) {
1290 fi->digestalgo = *algo;
1295 /* grab hex digests from header and store in binary format */
1296 if (headerGet(h, RPMTAG_FILEDIGESTS, &fdigests, HEADERGET_MINMEM)) {
1297 const char *fdigest;
1298 size_t diglen = rpmDigestLength(fi->digestalgo);
1299 fi->digests = t = xmalloc(rpmtdCount(&fdigests) * diglen);
1301 while ((fdigest = rpmtdNextString(&fdigests))) {
1302 if (!(fdigest && *fdigest != '\0')) {
1303 memset(t, 0, diglen);
1307 for (int j = 0; j < diglen; j++, t++, fdigest += 2)
1308 *t = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
1310 rpmtdFreeData(&fdigests);
1313 /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
1314 _hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
1315 _hgfi(h, RPMTAG_FILERDEVS, &td, scareFlags, fi->frdevs);
1316 _hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
1318 fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
1320 _hgfi(h, RPMTAG_FILEUSERNAME, &td, defFlags, fi->fuser);
1321 _hgfi(h, RPMTAG_FILEGROUPNAME, &td, defFlags, fi->fgroup);
1325 if ((p = rpmtsRelocateElement(ts)) != NULL && rpmteType(p) == TR_ADDED
1326 && !headerIsSource(h)
1327 && !headerIsEntry(h, RPMTAG_ORIGBASENAMES))
1332 if (fi->actions == NULL)
1333 fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
1334 /* FIX: fi-digests undefined */
1335 foo = relocateFileList(ts, fi, h, fi->actions);
1336 fi->h = headerFree(fi->h);
1337 fi->h = headerLink(foo);
1338 foo = headerFree(foo);
1342 fi->h = headerFree(fi->h);
1346 for (i = 0; i < fi->dc; i++) {
1347 if ((len = strlen(fi->dnl[i])) > dnlmax)
1351 for (i = 0; i < fi->fc; i++) {
1352 if ((len = strlen(fi->bnl[i])) > bnlmax)
1355 fi->fnlen = dnlmax + bnlmax + 1;
1362 if (_rpmfi_debug < 0)
1363 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, Type, (fi ? fi->fc : 0));
1365 /* FIX: rpmfi null annotations */
1366 return rpmfiLink(fi, (fi ? fi->Type : NULL));